cdk-nextjs 0.6.1 → 0.7.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 (266) hide show
  1. package/.jsii +2467 -2714
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1725 -1909
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +152 -170
  7. package/assets/lambdas/redeploy-stage/redeploy-stage.lambda/index.js +875 -0
  8. package/docs/adapter-runtime.md +185 -0
  9. package/docs/breaking-changes.md +687 -4
  10. package/docs/caching-guide.md +156 -112
  11. package/docs/cdk-nextjs-cfn-exec-policy.json +2 -1
  12. package/docs/development-guide.md +1 -1
  13. package/docs/harness-coverage.md +598 -0
  14. package/docs/init-cache-deployment.md +32 -1
  15. package/docs/next-build-output-guide.md +30 -20
  16. package/examples/README.md +5 -1
  17. package/lib/adapter/__fixtures__/app-playground-base-path.json +4926 -0
  18. package/lib/adapter/__fixtures__/app-playground.json +4917 -0
  19. package/lib/adapter/__fixtures__/pages-i18n.json +1728 -0
  20. package/lib/adapter/adapter.mjs +1548 -185
  21. package/lib/adapter/adapter.test.js +106 -0
  22. package/lib/adapter/aws-cache-store.d.ts +489 -0
  23. package/lib/adapter/aws-cache-store.js +1004 -0
  24. package/lib/adapter/aws-cache-store.test.d.ts +1 -0
  25. package/lib/adapter/aws-cache-store.test.js +361 -0
  26. package/lib/adapter/build-outputs.d.ts +80 -0
  27. package/lib/adapter/build-outputs.js +852 -0
  28. package/lib/adapter/build-outputs.test.d.ts +1 -0
  29. package/lib/adapter/build-outputs.test.js +861 -0
  30. package/lib/adapter/cache-handler.d.ts +9 -2
  31. package/lib/adapter/cache-handler.js +72 -96
  32. package/lib/adapter/cache-handler.mjs +18956 -17774
  33. package/lib/adapter/cache-handler.test.js +263 -31
  34. package/lib/adapter/cache-kinds.d.ts +32 -0
  35. package/lib/adapter/cache-kinds.js +35 -0
  36. package/lib/adapter/cache-kinds.test.d.ts +1 -0
  37. package/lib/adapter/cache-kinds.test.js +69 -0
  38. package/lib/adapter/cache-utils.d.ts +90 -0
  39. package/lib/adapter/cache-utils.js +199 -4
  40. package/lib/adapter/cache-utils.test.d.ts +1 -0
  41. package/lib/adapter/cache-utils.test.js +179 -0
  42. package/lib/adapter/function-groups.d.ts +215 -0
  43. package/lib/adapter/function-groups.js +1099 -0
  44. package/lib/adapter/function-groups.test.d.ts +1 -0
  45. package/lib/adapter/function-groups.test.js +743 -0
  46. package/lib/adapter/init-cache.d.ts +6 -0
  47. package/lib/adapter/init-cache.js +245 -0
  48. package/lib/adapter/init-cache.test.d.ts +1 -0
  49. package/lib/adapter/init-cache.test.js +137 -0
  50. package/lib/adapter/local-file-cache-handler.d.ts +23 -0
  51. package/lib/adapter/local-file-cache-handler.js +52 -1
  52. package/lib/adapter/memory-cache-handler.d.ts +26 -17
  53. package/lib/adapter/memory-cache-handler.js +32 -50
  54. package/lib/adapter/memory-cache-handler.test.js +105 -85
  55. package/lib/adapter/s3-cache-handler.d.ts +179 -40
  56. package/lib/adapter/s3-cache-handler.js +807 -277
  57. package/lib/adapter/s3-cache-handler.test.js +1186 -31
  58. package/lib/adapter/use-cache-common.d.ts +90 -0
  59. package/lib/adapter/use-cache-common.js +250 -0
  60. package/lib/adapter/use-cache-common.test.d.ts +1 -0
  61. package/lib/adapter/use-cache-common.test.js +646 -0
  62. package/lib/adapter/use-cache-default-handler.d.ts +24 -0
  63. package/lib/adapter/use-cache-default-handler.js +90 -0
  64. package/lib/adapter/use-cache-default-handler.mjs +38645 -0
  65. package/lib/adapter/use-cache-handlers.test.d.ts +1 -0
  66. package/lib/adapter/use-cache-handlers.test.js +349 -0
  67. package/lib/adapter/use-cache-remote-handler.d.ts +26 -0
  68. package/lib/adapter/use-cache-remote-handler.js +186 -0
  69. package/lib/{image-optimization/handler.mjs → adapter/use-cache-remote-handler.mjs} +33572 -38798
  70. package/lib/generated-structs/OptionalNextjsApiProps.d.ts +59 -0
  71. package/lib/generated-structs/OptionalNextjsApiProps.js +3 -0
  72. package/lib/generated-structs/OptionalNextjsCacheProps.d.ts +15 -6
  73. package/lib/generated-structs/OptionalNextjsCacheProps.js +1 -1
  74. package/lib/generated-structs/OptionalNextjsContainersProps.d.ts +25 -11
  75. package/lib/generated-structs/OptionalNextjsContainersProps.js +1 -1
  76. package/lib/generated-structs/OptionalNextjsDistributionProps.d.ts +31 -9
  77. package/lib/generated-structs/OptionalNextjsDistributionProps.js +1 -1
  78. package/lib/generated-structs/OptionalNextjsPostDeployProps.d.ts +13 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +11 -2
  81. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.js +1 -1
  82. package/lib/index.d.ts +6 -7
  83. package/lib/index.js +2 -4
  84. package/lib/lambdas/post-deploy/post-deploy.lambda.js +3 -2
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.d.ts +7 -3
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  88. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  92. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  93. package/lib/lambdas/post-deploy/prune-s3.d.ts +19 -3
  94. package/lib/lambdas/post-deploy/prune-s3.js +54 -15
  95. package/lib/lambdas/post-deploy/prune-s3.test.d.ts +1 -0
  96. package/lib/lambdas/post-deploy/prune-s3.test.js +255 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  103. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  104. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  105. package/lib/nextjs-api.d.ts +107 -18
  106. package/lib/nextjs-api.js +349 -39
  107. package/lib/nextjs-api.test.js +582 -1
  108. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  109. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  110. package/lib/nextjs-build/nextjs-build.js +684 -327
  111. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  112. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  113. package/lib/nextjs-build/patch-fetch.js +1 -1
  114. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  115. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  116. package/lib/nextjs-cache.d.ts +82 -4
  117. package/lib/nextjs-cache.js +186 -10
  118. package/lib/nextjs-cache.test.js +176 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  120. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  121. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  122. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  123. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  124. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  125. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  126. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  127. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  128. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  129. package/lib/nextjs-distribution.d.ts +194 -23
  130. package/lib/nextjs-distribution.js +535 -62
  131. package/lib/nextjs-distribution.test.d.ts +1 -0
  132. package/lib/nextjs-distribution.test.js +697 -0
  133. package/lib/nextjs-post-deploy.d.ts +23 -3
  134. package/lib/nextjs-post-deploy.js +14 -10
  135. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  136. package/lib/nextjs-post-deploy.test.js +34 -0
  137. package/lib/nextjs-static-assets.d.ts +23 -4
  138. package/lib/nextjs-static-assets.js +29 -6
  139. package/lib/nextjs-static-assets.test.js +20 -1
  140. package/lib/root-constructs/nextjs-base-construct.d.ts +105 -45
  141. package/lib/root-constructs/nextjs-base-construct.js +144 -34
  142. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  143. package/lib/root-constructs/nextjs-global-containers.js +20 -70
  144. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  145. package/lib/root-constructs/nextjs-global-functions.js +52 -69
  146. package/lib/root-constructs/nextjs-regional-containers.d.ts +25 -5
  147. package/lib/root-constructs/nextjs-regional-containers.js +17 -15
  148. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  149. package/lib/root-constructs/nextjs-regional-functions.js +8 -25
  150. package/lib/runtime/api-gateway-path.d.ts +34 -0
  151. package/lib/runtime/api-gateway-path.js +71 -0
  152. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  153. package/lib/runtime/api-gateway-path.test.js +65 -0
  154. package/lib/runtime/case-redirect.d.ts +22 -0
  155. package/lib/runtime/case-redirect.js +63 -0
  156. package/lib/runtime/case-redirect.test.d.ts +1 -0
  157. package/lib/runtime/case-redirect.test.js +32 -0
  158. package/lib/runtime/core.d.ts +234 -0
  159. package/lib/runtime/core.js +1213 -0
  160. package/lib/runtime/core.test.d.ts +1 -0
  161. package/lib/runtime/core.test.js +1678 -0
  162. package/lib/runtime/deployment-root.d.ts +13 -0
  163. package/lib/runtime/deployment-root.js +29 -0
  164. package/lib/runtime/dispatch.d.ts +331 -0
  165. package/lib/runtime/dispatch.js +751 -0
  166. package/lib/runtime/dispatch.test.d.ts +1 -0
  167. package/lib/runtime/dispatch.test.js +853 -0
  168. package/lib/runtime/entrypoints.d.ts +57 -0
  169. package/lib/runtime/entrypoints.js +115 -0
  170. package/lib/runtime/http/abort-signal.d.ts +6 -0
  171. package/lib/runtime/http/abort-signal.js +19 -0
  172. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  173. package/lib/runtime/http/abort-signal.test.js +49 -0
  174. package/lib/runtime/http/node-server.d.ts +38 -0
  175. package/lib/runtime/http/node-server.js +99 -0
  176. package/lib/runtime/http/node-server.test.d.ts +1 -0
  177. package/lib/runtime/http/node-server.test.js +96 -0
  178. package/lib/runtime/http/node-sink.d.ts +16 -0
  179. package/lib/runtime/http/node-sink.js +48 -0
  180. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  181. package/lib/runtime/http/node-sink.test.js +66 -0
  182. package/lib/runtime/http/request.d.ts +62 -0
  183. package/lib/runtime/http/request.js +134 -0
  184. package/lib/runtime/http/request.test.d.ts +1 -0
  185. package/lib/runtime/http/request.test.js +103 -0
  186. package/lib/runtime/http/response.d.ts +77 -0
  187. package/lib/runtime/http/response.js +229 -0
  188. package/lib/runtime/http/response.test.d.ts +1 -0
  189. package/lib/runtime/http/response.test.js +178 -0
  190. package/lib/runtime/http/sink.d.ts +73 -0
  191. package/lib/runtime/http/sink.js +188 -0
  192. package/lib/runtime/http/sink.test.d.ts +1 -0
  193. package/lib/runtime/http/sink.test.js +257 -0
  194. package/lib/runtime/image-utils.d.ts +78 -0
  195. package/lib/runtime/image-utils.js +129 -0
  196. package/lib/runtime/image-utils.test.d.ts +1 -0
  197. package/lib/runtime/image-utils.test.js +237 -0
  198. package/lib/runtime/image.d.ts +76 -0
  199. package/lib/runtime/image.js +296 -0
  200. package/lib/runtime/image.test.d.ts +1 -0
  201. package/lib/runtime/image.test.js +405 -0
  202. package/lib/runtime/lambda-event.d.ts +4 -0
  203. package/lib/runtime/lambda-event.js +113 -0
  204. package/lib/runtime/lambda-event.test.d.ts +1 -0
  205. package/lib/runtime/lambda-event.test.js +119 -0
  206. package/lib/runtime/lambda.mjs +41595 -0
  207. package/lib/runtime/load-module.d.ts +8 -0
  208. package/lib/runtime/load-module.js +35 -0
  209. package/lib/runtime/manifest.d.ts +215 -0
  210. package/lib/runtime/manifest.js +118 -0
  211. package/lib/runtime/middleware.d.ts +43 -0
  212. package/lib/runtime/middleware.js +113 -0
  213. package/lib/runtime/middleware.test.d.ts +1 -0
  214. package/lib/runtime/middleware.test.js +259 -0
  215. package/lib/runtime/next-modules.d.ts +55 -0
  216. package/lib/runtime/next-modules.js +124 -0
  217. package/lib/runtime/next-modules.test.d.ts +1 -0
  218. package/lib/runtime/next-modules.test.js +34 -0
  219. package/lib/runtime/public-files.d.ts +32 -0
  220. package/lib/runtime/public-files.js +117 -0
  221. package/lib/runtime/public-files.test.d.ts +1 -0
  222. package/lib/runtime/public-files.test.js +97 -0
  223. package/lib/runtime/server.mjs +41588 -0
  224. package/lib/runtime/static-files.d.ts +50 -0
  225. package/lib/runtime/static-files.js +266 -0
  226. package/lib/runtime/static-files.test.d.ts +1 -0
  227. package/lib/runtime/static-files.test.js +118 -0
  228. package/lib/runtime/util.d.ts +28 -0
  229. package/lib/runtime/util.js +79 -0
  230. package/lib/utils/base-path.d.ts +123 -11
  231. package/lib/utils/base-path.js +276 -39
  232. package/lib/utils/base-path.test.js +275 -50
  233. package/lib/utils/get-architecture.d.ts +7 -8
  234. package/lib/utils/get-architecture.js +12 -13
  235. package/lib/utils/zip-directory.d.ts +14 -0
  236. package/lib/utils/zip-directory.js +121 -0
  237. package/lib/utils/zip-directory.test.d.ts +1 -0
  238. package/lib/utils/zip-directory.test.js +99 -0
  239. package/package.json +22 -3
  240. package/scripts/capture-adapter-fixture.mjs +325 -0
  241. package/scripts/e2e-deploy.sh +398 -0
  242. package/scripts/e2e-harness/README.md +707 -0
  243. package/scripts/e2e-harness/app.js +370 -0
  244. package/scripts/e2e-harness/common.sh +249 -0
  245. package/scripts/e2e-harness/screen.mjs +302 -0
  246. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  247. package/scripts/e2e-harness/type-filters.mjs +47 -0
  248. package/scripts/e2e-logs.sh +75 -0
  249. package/scripts/e2e-offline.sh +91 -0
  250. package/scripts/e2e-sweep.sh +370 -0
  251. package/scripts/e2e-warm.sh +114 -0
  252. package/scripts/zero-config-build.mjs +418 -0
  253. package/docs/1k-concurrent-users-executions.png +0 -0
  254. package/docs/plans/adapter-runtime-release.md +0 -362
  255. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  256. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  257. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  258. package/lib/image-optimization/handler-utils.d.ts +0 -34
  259. package/lib/image-optimization/handler-utils.js +0 -83
  260. package/lib/image-optimization/handler-utils.test.js +0 -178
  261. package/lib/nextjs-build/functions.Dockerfile +0 -31
  262. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  263. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  264. package/lib/utils/experimental-flags.d.ts +0 -24
  265. package/lib/utils/experimental-flags.js +0 -30
  266. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -1,4 +1,7 @@
1
1
  # ~~ Generated by cdk-nextjs ~~
2
+ # cdk-nextjs rewrites any Dockerfile carrying the line above, so that an
3
+ # upgrade does not leave a stale one behind. To own this file yourself, delete
4
+ # that line and cdk-nextjs will leave the rest of it alone.
2
5
  # Modified from: https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
3
6
 
4
7
  # Production image, copy all the files and run next
@@ -14,13 +17,15 @@ ENV NODE_ENV=production
14
17
  RUN addgroup --system --gid 1001 nodejs
15
18
  RUN adduser --system --uid 1001 nextjs
16
19
 
17
- ARG RELATIVE_PATH_TO_PACKAGE
18
- # Copy from local build output instead of builder image
19
- COPY --chown=nextjs:nodejs .next/standalone ./
20
- # Copy .next/static so image optimization can read imported images (e.g. /_next/static/media/*)
21
- COPY --chown=nextjs:nodejs .next/static ./$RELATIVE_PATH_TO_PACKAGE/.next/static
22
- # Copy public directory for image optimization (Next.js needs source images)
23
- COPY --chown=nextjs:nodejs public ./$RELATIVE_PATH_TO_PACKAGE/public
20
+ # The deployment root cdk-nextjs staged during `next build`: the traced assets of
21
+ # every built output, keyed by repo-root-relative path, plus cdk-nextjs's own
22
+ # request-handling server under cdk-nextjs-runtime/. Replaces `.next/standalone`.
23
+ COPY --chown=nextjs:nodejs .next/cdk-nextjs-adapter/app ./
24
+ # `.next/static` and `public` are not copied in: they are in S3, and CloudFront
25
+ # routes their paths there. A request that reaches the server for a `public/`
26
+ # file anyway (a rewrite onto it) is read from S3, using the list of `public/`
27
+ # cdk-nextjs staged in cdk-nextjs-runtime/public-files.json. Image optimization
28
+ # reads its sources from S3 as well.
24
29
 
25
30
  USER nextjs
26
31
 
@@ -28,8 +33,8 @@ EXPOSE 3000
28
33
 
29
34
  ENV PORT=3000
30
35
 
31
- # server.js is created by next build from the standalone output
32
- # https://nextjs.org/docs/pages/api-reference/next-config-js/output
36
+ # cdk-nextjs's own server, staged above. It invokes the entrypoints `next build`
37
+ # produced in-process; there is no `next start` and no server.js.
33
38
  # CMD will be overwritten by ECS Task Definition
34
39
  ENV HOSTNAME="0.0.0.0"
35
- CMD ["node" "server.js"]
40
+ CMD ["node", "cdk-nextjs-runtime/server.mjs"]
@@ -1,3 +1,5 @@
1
+ import { Dirent } from "node:fs";
2
+ import { Architecture } from "aws-cdk-lib/aws-lambda";
1
3
  import { Construct } from "constructs";
2
4
  import { NextjsType } from "../constants";
3
5
  import { NextjsBaseProps } from "../root-constructs/nextjs-base-construct";
@@ -16,7 +18,76 @@ export interface NextjsBuildProps {
16
18
  * @see {@link NextjsBaseProps.skipBuild}
17
19
  */
18
20
  readonly skipBuild?: boolean;
21
+ /**
22
+ * Route groups to package into separate Lambda functions. Only the two
23
+ * Functions `NextjsType`s pass this; see `NextjsFunctionGroup`.
24
+ */
25
+ readonly functionGroups?: NextjsFunctionGroupRoutes[];
26
+ /**
27
+ * Lambda architecture the Functions types deploy, which decides the `sharp`
28
+ * binaries staged into the deployment roots. Ignored by the Containers
29
+ * types, whose image is built for the synth machine.
30
+ * @default - the architecture of the machine running synth
31
+ */
32
+ readonly architecture?: Architecture;
33
+ }
34
+ /**
35
+ * The part of a function group `NextjsBuild` needs: which routes it owns. The
36
+ * per-group Lambda `overrides` are `NextjsFunctions`' business.
37
+ */
38
+ export interface NextjsFunctionGroupRoutes {
39
+ readonly name: string;
40
+ readonly routes: string[];
41
+ }
42
+ /** One staged deployment root, and the function group it belongs to. */
43
+ export interface NextjsDeploymentRoot {
44
+ /**
45
+ * Group name, `default` for the implicit group that owns every unassigned
46
+ * route. The only entry is `default` when `functionGroups` is not used.
47
+ */
48
+ readonly name: string;
49
+ /** Absolute path to the deployment root: the Lambda zip asset's source. */
50
+ readonly path: string;
51
+ /**
52
+ * Route templates this root's package holds, as the adapter assigned them.
53
+ * Empty is legal: the default group still serves `/_next/image`, the static
54
+ * files the runtime reads off disk, and anything the catch-all routes to it.
55
+ */
56
+ readonly routes: string[];
57
+ }
58
+ /**
59
+ * One behavior that routes a function group's URLs to it, as the adapter
60
+ * checked them against what each group was packaged with.
61
+ */
62
+ export interface NextjsFunctionGroupBehavior {
63
+ /** The function group the behavior routes to. */
64
+ readonly group: string;
65
+ /**
66
+ * The group pattern it came from (`/blog/**`), or the parent of an optional
67
+ * catch-all a subtree pattern moved into the group (`/blog` for
68
+ * `/blog/[[...slug]]`), which that subtree's behavior does not match.
69
+ */
70
+ readonly route: string;
71
+ /**
72
+ * The CloudFront path pattern, before basePath and without a leading slash:
73
+ * `blog/*`, `pricing`, `pricing/` for a `trailingSlash` app, and
74
+ * `_next/data/<buildId>/blog/*` for a group owning a Pages Router page.
75
+ */
76
+ readonly pattern: string;
19
77
  }
78
+ /**
79
+ * What every deployment root is staged for: the build's `architecture`, else
80
+ * the synth machine's. Containers ignore it: Docker builds their image
81
+ * natively, so it can only match the synth machine.
82
+ */
83
+ export declare function deploymentArchitecture(props: NextjsBuildProps): Architecture;
84
+ /** {@link NextjsBuild.buildId}: Next.js's build ID, suffixed with the app's `deploymentId`. */
85
+ export declare function deploymentBuildId(manifest: {
86
+ readonly buildId: string;
87
+ readonly config: {
88
+ readonly deploymentId: string;
89
+ };
90
+ }): string;
20
91
  export interface PublicDirEntry {
21
92
  readonly name: string;
22
93
  readonly isDirectory: boolean;
@@ -27,8 +98,24 @@ export interface PublicDirEntry {
27
98
  */
28
99
  export declare class NextjsBuild extends Construct {
29
100
  /**
30
- * Unique id for Next.js build. Used to partition cache storage and as
101
+ * Unique id for this deployment. Used to partition cache storage and as
31
102
  * metadata for static assets in S3 bucket.
103
+ *
104
+ * Next.js's build ID, suffixed with the app's `deploymentId` when it sets
105
+ * one. The build ID alone is not unique per deployment: setting
106
+ * `deploymentId` (or building with `NEXT_DEPLOYMENT_ID`) turns on skew
107
+ * protection, and next.js then *pins* the build ID to the constant
108
+ * `build-TfctsWXpff2fKS` — see `getBuildId` in `next/dist/build/index.js`,
109
+ * which does that deliberately so that tooling doing
110
+ * `.replace(escapedBuildId, …)` still has something to replace. Two
111
+ * successive deployments of such an app would share one cache prefix and one
112
+ * revalidation-table partition, and the new one would read the previous
113
+ * one's prerenders. Appending the deployment ID restores the "one
114
+ * deployment, one partition" invariant that ID exists to carry.
115
+ *
116
+ * Nothing routes on this value — the `/_next/data/<buildId>/…` URL space is
117
+ * routed on Next.js's own build ID, which is what the app's client bundles
118
+ * carry — so it is free to be longer than next.js's own.
32
119
  */
33
120
  buildId: string;
34
121
  /**
@@ -42,111 +129,213 @@ export declare class NextjsBuild extends Construct {
42
129
  */
43
130
  publicDirEntries: PublicDirEntry[];
44
131
  /**
45
- * The entrypoint JavaScript file used as an argument for Node.js to run the
46
- * Next.js standalone server relative to the standalone directory.
47
- * @example "./server.js"
48
- * @example "./packages/ui/server.js" (monorepo)
132
+ * The JavaScript file Node.js runs to serve requests, relative to the
133
+ * deployment root. cdk-nextjs's own container shell, not `next build` output,
134
+ * so it is the same path for every app.
135
+ * @example "cdk-nextjs-runtime/server.mjs"
49
136
  */
50
137
  relativePathToEntrypoint: string;
51
- /**
52
- * Relative path from the standalone directory to the package containing the Next.js app.
53
- * This is automatically detected from the standalone build output.
54
- * @example "." for non-monorepo apps
55
- * @example "./apps/web" for monorepo apps
56
- */
57
- relativePathToPackage: string;
58
138
  /**
59
139
  * Absolute path to the .next directory containing Next.js build artifacts
60
140
  */
61
141
  dotNextPath: string;
62
142
  /**
63
143
  * The Next.js app's own `basePath` — the URL prefix it generates its links and
64
- * asset hrefs under — read out of the build's `required-server-files.json`.
65
- * Normalized to a bare path segment, empty when the app sets none. Exposed so
144
+ * asset hrefs under — as the adapter manifest recorded it. Normalized to a bare path segment, empty when the app sets none. Exposed so
66
145
  * root constructs can reconcile it with the CDK `basePath` prop, which is a
67
146
  * distinct thing; see `resolveBasePath`.
68
147
  */
69
148
  nextConfigBasePath: string;
70
149
  /**
71
- * Absolute path to the directory prepared for the image optimization Lambda
72
- * asset: bundled handler, glibc `sharp` binaries, and `required-server-files.json`.
73
- * Only set for {@link NextjsType.GLOBAL_FUNCTIONS} and
74
- * {@link NextjsType.REGIONAL_FUNCTIONS}, and only when the dedicated image
75
- * optimization Lambda is enabled.
150
+ * The Next.js app's own `assetPrefix`, as a path with a leading slash and no
151
+ * trailing one, empty when the app sets none or sets an absolute URL (which
152
+ * names an origin cdk-nextjs does not serve).
153
+ *
154
+ * Exposed because it is the shape of `assetPrefix` the regional
155
+ * `NextjsType`s cannot serve — see `warnUnservedAssetPrefix`. What the
156
+ * distribution has to answer on is {@link nextConfigAssetPrefixPath}, which
157
+ * also covers the path an absolute prefix carries.
158
+ */
159
+ nextConfigAssetPrefix: string;
160
+ /**
161
+ * The path portion of the app's `assetPrefix`, whichever form it takes: "/cdn"
162
+ * for both `assetPrefix: "/cdn"` and `assetPrefix:
163
+ * "https://cdn.example.com/cdn"`, empty when there is no path to answer on.
164
+ *
165
+ * Exposed because it is a URL prefix the distribution has to answer on: Next.js
166
+ * emits `<assetPrefix>/_next/static/...` for every bundle and compiles a rewrite
167
+ * that serves those URLs' paths itself, while the objects live in S3 under
168
+ * `<basePath>/_next/static/...`.
169
+ */
170
+ nextConfigAssetPrefixPath: string;
171
+ /**
172
+ * Every staged deployment root, one per function group, `default` first: the
173
+ * staged union of each group's shipped outputs and their traced assets,
174
+ * written by the adapter's `onBuildComplete`. Exactly one entry (named
175
+ * `default`, at `.next/cdk-nextjs-adapter/app`) unless `functionGroups`
176
+ * splits the app. The Lambda zip assets; Containers `COPY` the `default` one.
177
+ */
178
+ deploymentRoots: NextjsDeploymentRoot[];
179
+ /**
180
+ * What routes each non-default function group's URLs to it, most specific
181
+ * first — the order CloudFront has to see them in, since it stops at the
182
+ * first match. Empty unless `functionGroups` splits the app.
183
+ */
184
+ functionGroupBehaviors: NextjsFunctionGroupBehavior[];
185
+ /**
186
+ * From the deployment root to the Next.js project dir, POSIX, `""` when
187
+ * the app is at the repo root. The runtime `chdir`s here; Containers pass it to
188
+ * their Dockerfile so `.next/static` and `public` land in the same place.
189
+ * @see AdapterManifest.relativeProjectDir
190
+ */
191
+ relativeProjectDir: string;
192
+ /**
193
+ * The architecture every deployment root's native dependencies (`sharp`)
194
+ * were staged for. The Lambdas deploying them must use the same one.
76
195
  */
77
- imageOptimizationAssetPath?: string;
196
+ architecture: Architecture;
78
197
  private props;
79
198
  private buildCommand;
80
199
  constructor(scope: Construct, id: string, props: NextjsBuildProps);
81
200
  /**
82
- * Execute local build command in the specified directory
83
- */
84
- private runNextBuild;
85
- /**
86
- * Validate Next.js build output
87
- * All builds must be standalone - no fallback to regular builds
201
+ * Line up the groups the props asked for with the roots the build actually
202
+ * staged, and fail loudly when they disagree.
203
+ *
204
+ * They can disagree in both directions, and both mean the same thing — the
205
+ * `.next` on disk came from a build that did not see this `functionGroups` —
206
+ * but the causes differ: `skipBuild: true` with a build run by hand, or a
207
+ * stale `.next` from before the prop changed. Either way every later symptom
208
+ * (a Lambda missing an entrypoint, a CloudFront behavior pointing at a
209
+ * function that cannot serve it) is this, several steps downstream.
88
210
  */
89
- private validateNextBuildOutput;
211
+ private resolveDeploymentRoots;
90
212
  /**
91
- * Find entrypoint client side js files to patch `fetch` only for NextjsGlobalFunctions
213
+ * Lambda enforces 250 MB unzipped at CloudFormation time, which is minutes
214
+ * into a deploy and reports only a size. Splitting exists to stay under that
215
+ * cap, so the error that tells you to split further has to name the group, its
216
+ * size, and what to do — and arrive at synth.
92
217
  */
93
- private patchFetchInClientJs;
218
+ private assertUnderLambdaLimit;
94
219
  /**
95
- * Automatically finds the relative path from standalone directory to the
96
- * package containing server.js by searching for server.js with a .next sibling.
97
- * @returns "." for non-monorepo apps, or relative path like "app-playground" for monorepo apps
220
+ * Read the manifest the adapter's `onBuildComplete` wrote.
221
+ *
222
+ * Its absence means `next build` ran without cdk-nextjs's adapter registered
223
+ * (or with a stale `next.config`), which is worth saying plainly here: every
224
+ * later failure — a Lambda that cannot find `manifest.json`, an empty asset —
225
+ * is the same cause several steps downstream.
98
226
  */
99
- private findRelativePathToServerJs;
227
+ private readAdapterManifest;
100
228
  /**
101
- * Get build ID from .next directory
229
+ * Copy cdk-nextjs's own bundled request-handling shell and the manifest into
230
+ * `<deploymentRoot>/cdk-nextjs-runtime/`, which is where
231
+ * `deploymentRootOf`/`deployedManifestPath` expect to find them.
232
+ *
233
+ * Only the shell the deployment type actually runs is copied — the Lambda
234
+ * handler for Functions, the `node:http` server for Containers — so nothing
235
+ * ships ~1.5 MB of dead code and the tree says which type produced it. Both
236
+ * are copied from this package's `lib/`, next to the compiled construct.
237
+ *
238
+ * Every group gets the same shell *and the same manifest*: a function only
239
+ * knows which routes it owns so it can say so when misrouted, and that comes
240
+ * from {@link FUNCTION_GROUP_ENV_VAR}, not from a per-group manifest.
102
241
  */
103
- private getBuildId;
242
+ private stageRuntime;
104
243
  /**
105
- * Get public directory entries from local filesystem
244
+ * `NEXT_ADAPTER_PATH` for the build, so `adapterPath` in `next.config` is
245
+ * optional.
246
+ *
247
+ * Next.js reads the variable as the *default* value of `adapterPath`
248
+ * (`next/dist/server/config-shared.js`, `defaultConfig`), so an app that does
249
+ * set `adapterPath` still wins and nothing existing changes.
250
+ *
251
+ * Resolved from the Next.js app, not from cdk-nextjs's own `__dirname` and not
252
+ * left as a bare specifier. Both alternatives were tried and both are wrong:
253
+ *
254
+ * - cdk-nextjs's own location loses because the adapter resolves its sibling
255
+ * cache handler relative to wherever *it* was loaded from. An adapter loaded
256
+ * from outside the app's tree hands Next.js a `cacheHandler` outside
257
+ * `turbopack.root`, which Turbopack rejects outright ("leaves the filesystem
258
+ * root").
259
+ * - A bare specifier loses because Next.js resolves `adapterPath` from inside
260
+ * its own config loader, i.e. from `next`'s realpath. Under pnpm that is the
261
+ * virtual store (`node_modules/.pnpm/next@…/node_modules/next/`), and the
262
+ * walk up from there never reaches the app's own `node_modules`.
263
+ *
264
+ * Unset when `cdk-nextjs` is not resolvable from the app, which is legitimate:
265
+ * the Next.js app and the CDK app can be separate packages, and only the CDK one
266
+ * necessarily depends on cdk-nextjs. {@link readAdapterManifest} reports the
267
+ * resulting failure and names this case.
268
+ *
269
+ * One setup this cannot serve, and the reason this repo's own examples still set
270
+ * `adapterPath`: a `link:`/`file:` dependency on a cdk-nextjs checkout *outside*
271
+ * the app's project root. The symlink resolves out of the project, so the
272
+ * `cacheHandler` escape above applies. Set `adapterPath` in `next.config` there
273
+ * — it is resolved by the build, after whatever put the adapter in place.
106
274
  */
107
- private getLocalPublicDirEntries;
275
+ private adapterPathEnv;
108
276
  /**
109
- * Recursively find and remove existing Sharp platform binaries
277
+ * Execute local build command in the specified directory
110
278
  */
111
- private removeExistingSharpBinaries;
279
+ private runNextBuild;
112
280
  /**
113
- * Download and install correct Sharp binaries for Linux MUSL
281
+ * Prepend `patch-fetch.js` to the client entrypoint chunks, for
282
+ * `NextjsGlobalFunctions` only.
283
+ *
284
+ * This is what makes POST work at all on that type. CloudFront reaches the
285
+ * server through a Lambda Function URL with `AuthType: AWS_IAM`, signed by an
286
+ * origin access control, and AWS documents the consequence: "If you use PUT or
287
+ * POST methods with your Lambda function URL, your users must compute the
288
+ * SHA256 of the body and include the payload hash value of the request body in
289
+ * the `x-amz-content-sha256` header when sending the request to CloudFront.
290
+ * Lambda doesn't support unsigned payloads."
291
+ *
292
+ * CloudFront signs GETs itself (empty-body hash) but will not hash a body, and
293
+ * a browser has no way to add that header on its own, so an unpatched app
294
+ * answers every server action, form submission and POST route handler with
295
+ * `403 InvalidSignatureException` before the request reaches Next.js. The
296
+ * patch installs `fetch`/`XMLHttpRequest` wrappers that compute the hash.
297
+ *
298
+ * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-lambda.html
114
299
  */
115
- private downloadAndInstallSharpBinaries;
300
+ private patchFetchInClientJs;
116
301
  /**
117
- * Assemble the deployment asset for the dedicated image optimization
118
- * Lambda: the pre-bundled handler (from this package's own `lib/` output),
119
- * `sharp`'s JS wrapper (already dereferenced from the pnpm store by Next's
120
- * output file tracing into the standalone build), glibc `sharp` binaries
121
- * (the standard Lambda managed runtime is Amazon Linux 2023/glibc, unlike
122
- * the musl binaries the Docker/Lambda Web Adapter server function needs),
123
- * and `required-server-files.json` (read by the handler at cold start to
124
- * build `nextConfig`).
302
+ * Get public directory entries from local filesystem
125
303
  */
126
- private prepareImageOptimizationAssets;
304
+ private getLocalPublicDirEntries;
127
305
  /**
128
- * Locate `sharp`'s JS wrapper inside a standalone `node_modules`.
306
+ * Strip whatever platform-specific Sharp binaries `next build`'s output file
307
+ * tracing staged, since they're the host's (e.g. macOS/glibc) rather than the
308
+ * deployment target's, then install the target's. Skipping this is silent:
309
+ * `imageOptimizer` catches the load failure internally and returns the
310
+ * unoptimized original with an HTTP 200.
129
311
  *
130
- * Next's output file tracing preserves the installer's on-disk layout, so
131
- * npm/yarn produce a hoisted `node_modules/sharp` while pnpm only
132
- * materializes `node_modules/.pnpm/sharp@<version>/node_modules/sharp`.
312
+ * Only a root with `sharp` staged gets the binaries: the image optimizer
313
+ * brings it into `default`, which serves every `/_next/image`, and another
314
+ * group has it only if its own routes use it. So only `default` warns when
315
+ * it's missing.
133
316
  */
134
- private findSharpPackage;
317
+ private stageSharpForTarget;
135
318
  /**
136
- * Copy `sharp` plus the transitive `dependencies` closure `require("sharp")`
137
- * pulls in (`@img/colour`, `detect-libc`, `semver`) into `targetPath`.
319
+ * Recursively find and remove existing Sharp platform binaries.
320
+ *
321
+ * `root` is walked whole rather than just its `node_modules`: the staged tree
322
+ * is keyed by repo-root-relative path, so in a monorepo the `node_modules`
323
+ * holding `sharp` is several directories down. {@link isSharpBinaryPackage} is
324
+ * what keeps that from reaching the app's own output — the staged root holds
325
+ * the compiled `.next` as well as the dependencies.
138
326
  *
139
- * Copying only `sharp` itself leaves those requires unresolvable, and
140
- * `imageOptimizer` swallows the resulting `MODULE_NOT_FOUND` by falling back
141
- * to serving the unoptimized original, so the omission is otherwise silent.
327
+ * @param projectDir the app's directory inside `root`, which `next` is
328
+ * resolved from.
329
+ * @returns the staged `sharp` JS wrapper to install next to, found in the same
330
+ * walk: a root can be hundreds of megabytes, and each group has one.
142
331
  */
143
- private copySharpRuntime;
332
+ private removeExistingSharpBinaries;
144
333
  /**
145
334
  * Resolve the `@img/sharp-<platform>` and `@img/sharp-libvips-<platform>`
146
335
  * versions to install for a given platform.
147
336
  *
148
- * These must match the `sharp` JS wrapper that output file tracing put in
149
- * the standalone build: `sharp`'s `lib/libvips.js` compares the binary's
337
+ * These must match the `sharp` JS wrapper that output file tracing staged:
338
+ * `sharp`'s `lib/libvips.js` compares the binary's
150
339
  * reported libvips version against its own `minimumLibvipsVersion` and
151
340
  * throws at load when they disagree. `sharp` pins both in its
152
341
  * `optionalDependencies`, so that manifest is the authoritative source.
@@ -164,3 +353,90 @@ export declare class NextjsBuild extends Construct {
164
353
  */
165
354
  private isCachedFileValid;
166
355
  }
356
+ /**
357
+ * Pick the staged `sharp` JS wrapper out of every copy found in the tree.
358
+ *
359
+ * Unlike a standalone build there is no single `node_modules` to look in: the
360
+ * tree mirrors repo-root-relative paths, so the search is by directory name.
361
+ *
362
+ * An app can have two `sharp` copies at different versions (its own, hoisted,
363
+ * and next's, nested under `next/node_modules`), and every binary goes into the
364
+ * one root `@img`, so the copy pinning them has to be the one `next`'s image
365
+ * optimizer loads: `nextSharp`, when {@link resolveNextSharp} found it. Otherwise
366
+ * shortest path wins as the closest to a hoisted install, sorted for
367
+ * determinism.
368
+ */
369
+ export declare function pickStagedSharpPackage(candidates: string[], nextSharp?: string): string | undefined;
370
+ /**
371
+ * The real path of the `sharp` entry point the staged `next` resolves from
372
+ * `projectDir`, `undefined` when either does not resolve.
373
+ */
374
+ export declare function resolveNextSharp(projectDir: string): string | undefined;
375
+ /**
376
+ * Whether the entry `name` in `parentPath` is an `@img/sharp-*` platform binary
377
+ * package, or pnpm's store entry for one.
378
+ *
379
+ * The name alone is not enough to delete a directory by. A route segment called
380
+ * `sharp-edges` stages `.next/server/app/sharp-edges/`, and removing it left the
381
+ * manifest listing an entrypoint that is no longer on disk — every request to
382
+ * that route 500ing with "Could not load the entrypoint". Nor is "a `sharp-`
383
+ * package": `sharp-ico` and `sharp-phash` are unrelated dependencies, and
384
+ * removing them failed the app at runtime with MODULE_NOT_FOUND. So both the
385
+ * scope and the place have to match:
386
+ *
387
+ * - `node_modules/@img/sharp-…`, where every platform binary actually lives
388
+ * - `node_modules/.pnpm/@img+sharp-…@0.35.4`, pnpm's store, whose entries are
389
+ * also what the `@img` links point at (`sharp-libvips-…` matches the same way)
390
+ *
391
+ * The `node_modules` segment is required as well, so an app directory that
392
+ * happens to be called `@img` or `.pnpm` is still left alone.
393
+ */
394
+ export declare function isSharpBinaryPackage(parentPath: string, name: string): boolean;
395
+ /**
396
+ * Where the target's `@img/sharp-*` binaries go: `<root>/node_modules/@img`.
397
+ *
398
+ * Not next to the staged `sharp` package. Under pnpm that is
399
+ * `node_modules/.pnpm/sharp@x/node_modules/@img`, which only the store copy of
400
+ * `sharp` resolves from: a dereferenced link to `sharp` (a copy at
401
+ * `app/node_modules/sharp`, say) looks for `@img` from its own path and walks
402
+ * up, never into the store. Both the Functions zip (`zipDirectory`) and the
403
+ * Containers `COPY` keep the links, so it is the store copy that loads, and its
404
+ * walk up reaches the root `node_modules` too, so it serves either layout. It
405
+ * is also where main installed them.
406
+ */
407
+ export declare function sharpBinaryDir(root: string): string;
408
+ /**
409
+ * Every entry under `root`, links listed but not followed.
410
+ *
411
+ * An explicit walk rather than `readdirSync({ recursive: true })`, which on
412
+ * Node 24 descends into symlinked directories itself and so never returns on a
413
+ * cycle — two workspace packages that link each other, which is how pnpm wires a
414
+ * monorepo.
415
+ */
416
+ export declare function listTree(root: string): Dirent[];
417
+ /**
418
+ * Write {@link PUBLIC_FILES_FILE_NAME} into a deployment root's runtime
419
+ * directory: every file under `publicDir`, listed the way the runtime would
420
+ * list it off disk (`readPublicFiles`: symlinks followed, `/`-separated,
421
+ * sorted). An app without `public/` gets `[]`.
422
+ */
423
+ export declare function writePublicFileList(runtimeDir: string, publicDir: string): void;
424
+ /**
425
+ * Total bytes of a tree as its deployment zip stores it. `zipDirectory` keeps
426
+ * links as links, so each counts as its target path, not as the target, which
427
+ * is walked at its own path anyway (every link in a staged root points inside
428
+ * it).
429
+ */
430
+ export declare function storedSize(root: string): number;
431
+ /**
432
+ * `chunk` with `patch` prepended between `PATCH_FETCH_MARKER` and
433
+ * `PATCH_FETCH_END_MARKER`, or `undefined` when it already carries this exact
434
+ * patch.
435
+ *
436
+ * The opening marker carries a hash of the patch, so a chunk patched by a
437
+ * cdk-nextjs whose `patch-fetch.js` differs (an upgrade, over a `.next` reused
438
+ * with `skipBuild: true`) is not mistaken for current: the old patch is cut off
439
+ * at its end marker and this one put in its place, rather than the old one
440
+ * shipping or both stacking up.
441
+ */
442
+ export declare function patchClientChunk(chunk: string, patch: string, chunkPath: string): string | undefined;