cdk-nextjs 0.6.2 → 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 (263) hide show
  1. package/.jsii +2404 -2723
  2. package/.jsii.tabl.json +1 -1
  3. package/API.md +1681 -1930
  4. package/CLAUDE.md +2 -1
  5. package/README.md +429 -130
  6. package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +148 -169
  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 +667 -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 +8 -0
  79. package/lib/generated-structs/OptionalNextjsPostDeployProps.js +1 -1
  80. package/lib/generated-structs/OptionalPostDeployCustomResourceProperties.d.ts +6 -4
  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/prune-cache-bucket.d.ts +7 -3
  85. package/lib/lambdas/post-deploy/prune-cache-bucket.js +57 -71
  86. package/lib/lambdas/post-deploy/prune-cache-bucket.test.d.ts +1 -0
  87. package/lib/lambdas/post-deploy/prune-cache-bucket.test.js +114 -0
  88. package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +1 -0
  89. package/lib/lambdas/post-deploy/prune-revalidation-table.js +23 -31
  90. package/lib/lambdas/post-deploy/prune-revalidation-table.test.d.ts +1 -0
  91. package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +71 -0
  92. package/lib/lambdas/post-deploy/prune-s3.d.ts +14 -5
  93. package/lib/lambdas/post-deploy/prune-s3.js +41 -12
  94. package/lib/lambdas/post-deploy/prune-s3.test.js +97 -18
  95. package/lib/lambdas/redeploy-stage/redeploy-stage-function.d.ts +13 -0
  96. package/lib/lambdas/redeploy-stage/redeploy-stage-function.js +55 -0
  97. package/lib/lambdas/redeploy-stage/redeploy-stage.d.ts +24 -0
  98. package/lib/lambdas/redeploy-stage/redeploy-stage.js +68 -0
  99. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.d.ts +20 -0
  100. package/lib/lambdas/redeploy-stage/redeploy-stage.lambda.js +24 -0
  101. package/lib/lambdas/redeploy-stage/redeploy-stage.test.d.ts +1 -0
  102. package/lib/lambdas/redeploy-stage/redeploy-stage.test.js +93 -0
  103. package/lib/nextjs-api.d.ts +102 -18
  104. package/lib/nextjs-api.js +338 -38
  105. package/lib/nextjs-api.test.js +537 -1
  106. package/lib/nextjs-build/global-containers.Dockerfile +15 -10
  107. package/lib/nextjs-build/nextjs-build.d.ts +339 -63
  108. package/lib/nextjs-build/nextjs-build.js +684 -327
  109. package/lib/nextjs-build/nextjs-build.test.d.ts +1 -0
  110. package/lib/nextjs-build/nextjs-build.test.js +412 -0
  111. package/lib/nextjs-build/patch-fetch.js +1 -1
  112. package/lib/nextjs-build/patch-fetch.test.js +166 -11
  113. package/lib/nextjs-build/regional-containers.Dockerfile +17 -10
  114. package/lib/nextjs-cache.d.ts +82 -4
  115. package/lib/nextjs-cache.js +186 -10
  116. package/lib/nextjs-cache.test.js +176 -1
  117. package/lib/nextjs-compute/nextjs-compute-base-props.d.ts +21 -8
  118. package/lib/nextjs-compute/nextjs-compute-base-props.js +41 -1
  119. package/lib/nextjs-compute/nextjs-compute-base-props.test.d.ts +1 -0
  120. package/lib/nextjs-compute/nextjs-compute-base-props.test.js +44 -0
  121. package/lib/nextjs-compute/nextjs-containers.d.ts +19 -0
  122. package/lib/nextjs-compute/nextjs-containers.js +57 -20
  123. package/lib/nextjs-compute/nextjs-functions.d.ts +122 -7
  124. package/lib/nextjs-compute/nextjs-functions.js +113 -67
  125. package/lib/nextjs-compute/nextjs-functions.test.d.ts +1 -0
  126. package/lib/nextjs-compute/nextjs-functions.test.js +99 -0
  127. package/lib/nextjs-distribution.d.ts +194 -23
  128. package/lib/nextjs-distribution.js +535 -62
  129. package/lib/nextjs-distribution.test.d.ts +1 -0
  130. package/lib/nextjs-distribution.test.js +697 -0
  131. package/lib/nextjs-post-deploy.d.ts +13 -5
  132. package/lib/nextjs-post-deploy.js +13 -10
  133. package/lib/nextjs-post-deploy.test.d.ts +1 -0
  134. package/lib/nextjs-post-deploy.test.js +34 -0
  135. package/lib/nextjs-static-assets.d.ts +17 -4
  136. package/lib/nextjs-static-assets.js +22 -5
  137. package/lib/root-constructs/nextjs-base-construct.d.ts +102 -58
  138. package/lib/root-constructs/nextjs-base-construct.js +139 -47
  139. package/lib/root-constructs/nextjs-global-containers.d.ts +18 -20
  140. package/lib/root-constructs/nextjs-global-containers.js +20 -71
  141. package/lib/root-constructs/nextjs-global-functions.d.ts +26 -28
  142. package/lib/root-constructs/nextjs-global-functions.js +52 -70
  143. package/lib/root-constructs/nextjs-regional-containers.d.ts +18 -5
  144. package/lib/root-constructs/nextjs-regional-containers.js +8 -15
  145. package/lib/root-constructs/nextjs-regional-functions.d.ts +22 -18
  146. package/lib/root-constructs/nextjs-regional-functions.js +8 -26
  147. package/lib/runtime/api-gateway-path.d.ts +34 -0
  148. package/lib/runtime/api-gateway-path.js +71 -0
  149. package/lib/runtime/api-gateway-path.test.d.ts +1 -0
  150. package/lib/runtime/api-gateway-path.test.js +65 -0
  151. package/lib/runtime/case-redirect.d.ts +22 -0
  152. package/lib/runtime/case-redirect.js +63 -0
  153. package/lib/runtime/case-redirect.test.d.ts +1 -0
  154. package/lib/runtime/case-redirect.test.js +32 -0
  155. package/lib/runtime/core.d.ts +234 -0
  156. package/lib/runtime/core.js +1213 -0
  157. package/lib/runtime/core.test.d.ts +1 -0
  158. package/lib/runtime/core.test.js +1678 -0
  159. package/lib/runtime/deployment-root.d.ts +13 -0
  160. package/lib/runtime/deployment-root.js +29 -0
  161. package/lib/runtime/dispatch.d.ts +331 -0
  162. package/lib/runtime/dispatch.js +751 -0
  163. package/lib/runtime/dispatch.test.d.ts +1 -0
  164. package/lib/runtime/dispatch.test.js +853 -0
  165. package/lib/runtime/entrypoints.d.ts +57 -0
  166. package/lib/runtime/entrypoints.js +115 -0
  167. package/lib/runtime/http/abort-signal.d.ts +6 -0
  168. package/lib/runtime/http/abort-signal.js +19 -0
  169. package/lib/runtime/http/abort-signal.test.d.ts +1 -0
  170. package/lib/runtime/http/abort-signal.test.js +49 -0
  171. package/lib/runtime/http/node-server.d.ts +38 -0
  172. package/lib/runtime/http/node-server.js +99 -0
  173. package/lib/runtime/http/node-server.test.d.ts +1 -0
  174. package/lib/runtime/http/node-server.test.js +96 -0
  175. package/lib/runtime/http/node-sink.d.ts +16 -0
  176. package/lib/runtime/http/node-sink.js +48 -0
  177. package/lib/runtime/http/node-sink.test.d.ts +1 -0
  178. package/lib/runtime/http/node-sink.test.js +66 -0
  179. package/lib/runtime/http/request.d.ts +62 -0
  180. package/lib/runtime/http/request.js +134 -0
  181. package/lib/runtime/http/request.test.d.ts +1 -0
  182. package/lib/runtime/http/request.test.js +103 -0
  183. package/lib/runtime/http/response.d.ts +77 -0
  184. package/lib/runtime/http/response.js +229 -0
  185. package/lib/runtime/http/response.test.d.ts +1 -0
  186. package/lib/runtime/http/response.test.js +178 -0
  187. package/lib/runtime/http/sink.d.ts +73 -0
  188. package/lib/runtime/http/sink.js +188 -0
  189. package/lib/runtime/http/sink.test.d.ts +1 -0
  190. package/lib/runtime/http/sink.test.js +257 -0
  191. package/lib/runtime/image-utils.d.ts +78 -0
  192. package/lib/runtime/image-utils.js +129 -0
  193. package/lib/runtime/image-utils.test.d.ts +1 -0
  194. package/lib/runtime/image-utils.test.js +237 -0
  195. package/lib/runtime/image.d.ts +76 -0
  196. package/lib/runtime/image.js +296 -0
  197. package/lib/runtime/image.test.d.ts +1 -0
  198. package/lib/runtime/image.test.js +405 -0
  199. package/lib/runtime/lambda-event.d.ts +4 -0
  200. package/lib/runtime/lambda-event.js +113 -0
  201. package/lib/runtime/lambda-event.test.d.ts +1 -0
  202. package/lib/runtime/lambda-event.test.js +119 -0
  203. package/lib/runtime/lambda.mjs +41595 -0
  204. package/lib/runtime/load-module.d.ts +8 -0
  205. package/lib/runtime/load-module.js +35 -0
  206. package/lib/runtime/manifest.d.ts +215 -0
  207. package/lib/runtime/manifest.js +118 -0
  208. package/lib/runtime/middleware.d.ts +43 -0
  209. package/lib/runtime/middleware.js +113 -0
  210. package/lib/runtime/middleware.test.d.ts +1 -0
  211. package/lib/runtime/middleware.test.js +259 -0
  212. package/lib/runtime/next-modules.d.ts +55 -0
  213. package/lib/runtime/next-modules.js +124 -0
  214. package/lib/runtime/next-modules.test.d.ts +1 -0
  215. package/lib/runtime/next-modules.test.js +34 -0
  216. package/lib/runtime/public-files.d.ts +32 -0
  217. package/lib/runtime/public-files.js +117 -0
  218. package/lib/runtime/public-files.test.d.ts +1 -0
  219. package/lib/runtime/public-files.test.js +97 -0
  220. package/lib/runtime/server.mjs +41588 -0
  221. package/lib/runtime/static-files.d.ts +50 -0
  222. package/lib/runtime/static-files.js +266 -0
  223. package/lib/runtime/static-files.test.d.ts +1 -0
  224. package/lib/runtime/static-files.test.js +118 -0
  225. package/lib/runtime/util.d.ts +28 -0
  226. package/lib/runtime/util.js +79 -0
  227. package/lib/utils/base-path.d.ts +106 -13
  228. package/lib/utils/base-path.js +254 -41
  229. package/lib/utils/base-path.test.js +219 -51
  230. package/lib/utils/get-architecture.d.ts +7 -8
  231. package/lib/utils/get-architecture.js +12 -13
  232. package/lib/utils/zip-directory.d.ts +14 -0
  233. package/lib/utils/zip-directory.js +121 -0
  234. package/lib/utils/zip-directory.test.d.ts +1 -0
  235. package/lib/utils/zip-directory.test.js +99 -0
  236. package/package.json +22 -3
  237. package/scripts/capture-adapter-fixture.mjs +325 -0
  238. package/scripts/e2e-deploy.sh +398 -0
  239. package/scripts/e2e-harness/README.md +707 -0
  240. package/scripts/e2e-harness/app.js +370 -0
  241. package/scripts/e2e-harness/common.sh +249 -0
  242. package/scripts/e2e-harness/screen.mjs +302 -0
  243. package/scripts/e2e-harness/stage-proxy.mjs +145 -0
  244. package/scripts/e2e-harness/type-filters.mjs +47 -0
  245. package/scripts/e2e-logs.sh +75 -0
  246. package/scripts/e2e-offline.sh +91 -0
  247. package/scripts/e2e-sweep.sh +370 -0
  248. package/scripts/e2e-warm.sh +114 -0
  249. package/scripts/zero-config-build.mjs +418 -0
  250. package/docs/1k-concurrent-users-executions.png +0 -0
  251. package/docs/plans/adapter-runtime-release.md +0 -362
  252. package/docs/plans/phase-0-image-function-opt-in.md +0 -295
  253. package/lib/generated-structs/OptionalDockerImageFunctionProps.d.ts +0 -425
  254. package/lib/generated-structs/OptionalDockerImageFunctionProps.js +0 -3
  255. package/lib/image-optimization/handler-utils.d.ts +0 -34
  256. package/lib/image-optimization/handler-utils.js +0 -83
  257. package/lib/image-optimization/handler-utils.test.js +0 -178
  258. package/lib/nextjs-build/functions.Dockerfile +0 -31
  259. package/lib/nextjs-compute/nextjs-image-function.d.ts +0 -53
  260. package/lib/nextjs-compute/nextjs-image-function.js +0 -59
  261. package/lib/utils/experimental-flags.d.ts +0 -24
  262. package/lib/utils/experimental-flags.js +0 -30
  263. /package/lib/{image-optimization/handler-utils.test.d.ts → adapter/adapter.test.d.ts} +0 -0
@@ -0,0 +1,20 @@
1
+ import type { EventBridgeHandler } from "aws-lambda";
2
+ /**
3
+ * The `detail` of a "CloudFormation Stack Status Change" event, as documented
4
+ * in the CloudFormation User Guide ("Stack Status Change event detail").
5
+ */
6
+ interface StackStatusChangeDetail {
7
+ readonly "stack-id": string;
8
+ readonly "status-details": {
9
+ readonly status: string;
10
+ readonly "status-reason"?: string;
11
+ };
12
+ }
13
+ /**
14
+ * Invoked by `NextjsApi`'s EventBridge rule when its stack finishes an update;
15
+ * see {@link redeployStage}. The API and stage come from the environment rather
16
+ * than the event: the rule only matches this stack, and the event names the
17
+ * stack, not the API.
18
+ */
19
+ export declare const handler: EventBridgeHandler<"CloudFormation Stack Status Change", StackStatusChangeDetail, void>;
20
+ export {};
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handler = void 0;
4
+ const redeploy_stage_1 = require("./redeploy-stage");
5
+ /**
6
+ * Invoked by `NextjsApi`'s EventBridge rule when its stack finishes an update;
7
+ * see {@link redeployStage}. The API and stage come from the environment rather
8
+ * than the event: the rule only matches this stack, and the event names the
9
+ * stack, not the API.
10
+ */
11
+ const handler = async (event) => {
12
+ const restApiId = process.env.REST_API_ID;
13
+ const stageName = process.env.STAGE_NAME;
14
+ if (!restApiId || !stageName) {
15
+ throw new Error("REST_API_ID and STAGE_NAME must be set.");
16
+ }
17
+ await (0, redeploy_stage_1.redeployStage)({
18
+ restApiId,
19
+ stageName,
20
+ stackStatus: event.detail["status-details"].status,
21
+ });
22
+ };
23
+ exports.handler = handler;
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkZXBsb3ktc3RhZ2UubGFtYmRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xhbWJkYXMvcmVkZXBsb3ktc3RhZ2UvcmVkZXBsb3ktc3RhZ2UubGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUFpRDtBQWNqRDs7Ozs7R0FLRztBQUNJLE1BQU0sT0FBTyxHQUloQixLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUU7SUFDbEIsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUM7SUFDMUMsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7SUFDekMsSUFBSSxDQUFDLFNBQVMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMseUNBQXlDLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBQ0QsTUFBTSxJQUFBLDhCQUFhLEVBQUM7UUFDbEIsU0FBUztRQUNULFNBQVM7UUFDVCxXQUFXLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLE1BQU07S0FDbkQsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDO0FBZlcsUUFBQSxPQUFPLFdBZWxCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBFdmVudEJyaWRnZUhhbmRsZXIgfSBmcm9tIFwiYXdzLWxhbWJkYVwiO1xuaW1wb3J0IHsgcmVkZXBsb3lTdGFnZSB9IGZyb20gXCIuL3JlZGVwbG95LXN0YWdlXCI7XG5cbi8qKlxuICogVGhlIGBkZXRhaWxgIG9mIGEgXCJDbG91ZEZvcm1hdGlvbiBTdGFjayBTdGF0dXMgQ2hhbmdlXCIgZXZlbnQsIGFzIGRvY3VtZW50ZWRcbiAqIGluIHRoZSBDbG91ZEZvcm1hdGlvbiBVc2VyIEd1aWRlIChcIlN0YWNrIFN0YXR1cyBDaGFuZ2UgZXZlbnQgZGV0YWlsXCIpLlxuICovXG5pbnRlcmZhY2UgU3RhY2tTdGF0dXNDaGFuZ2VEZXRhaWwge1xuICByZWFkb25seSBcInN0YWNrLWlkXCI6IHN0cmluZztcbiAgcmVhZG9ubHkgXCJzdGF0dXMtZGV0YWlsc1wiOiB7XG4gICAgcmVhZG9ubHkgc3RhdHVzOiBzdHJpbmc7XG4gICAgcmVhZG9ubHkgXCJzdGF0dXMtcmVhc29uXCI/OiBzdHJpbmc7XG4gIH07XG59XG5cbi8qKlxuICogSW52b2tlZCBieSBgTmV4dGpzQXBpYCdzIEV2ZW50QnJpZGdlIHJ1bGUgd2hlbiBpdHMgc3RhY2sgZmluaXNoZXMgYW4gdXBkYXRlO1xuICogc2VlIHtAbGluayByZWRlcGxveVN0YWdlfS4gVGhlIEFQSSBhbmQgc3RhZ2UgY29tZSBmcm9tIHRoZSBlbnZpcm9ubWVudCByYXRoZXJcbiAqIHRoYW4gdGhlIGV2ZW50OiB0aGUgcnVsZSBvbmx5IG1hdGNoZXMgdGhpcyBzdGFjaywgYW5kIHRoZSBldmVudCBuYW1lcyB0aGVcbiAqIHN0YWNrLCBub3QgdGhlIEFQSS5cbiAqL1xuZXhwb3J0IGNvbnN0IGhhbmRsZXI6IEV2ZW50QnJpZGdlSGFuZGxlcjxcbiAgXCJDbG91ZEZvcm1hdGlvbiBTdGFjayBTdGF0dXMgQ2hhbmdlXCIsXG4gIFN0YWNrU3RhdHVzQ2hhbmdlRGV0YWlsLFxuICB2b2lkXG4+ID0gYXN5bmMgKGV2ZW50KSA9PiB7XG4gIGNvbnN0IHJlc3RBcGlJZCA9IHByb2Nlc3MuZW52LlJFU1RfQVBJX0lEO1xuICBjb25zdCBzdGFnZU5hbWUgPSBwcm9jZXNzLmVudi5TVEFHRV9OQU1FO1xuICBpZiAoIXJlc3RBcGlJZCB8fCAhc3RhZ2VOYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiUkVTVF9BUElfSUQgYW5kIFNUQUdFX05BTUUgbXVzdCBiZSBzZXQuXCIpO1xuICB9XG4gIGF3YWl0IHJlZGVwbG95U3RhZ2Uoe1xuICAgIHJlc3RBcGlJZCxcbiAgICBzdGFnZU5hbWUsXG4gICAgc3RhY2tTdGF0dXM6IGV2ZW50LmRldGFpbFtcInN0YXR1cy1kZXRhaWxzXCJdLnN0YXR1cyxcbiAgfSk7XG59O1xuIl19
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /* eslint-disable import/no-extraneous-dependencies */
4
+ // Only the client is mocked; the command classes stay real so assertions can
5
+ // read `command.input`. `send` goes through the holder because the module
6
+ // constructs its client at import time.
7
+ jest.mock("@aws-sdk/client-api-gateway", () => ({
8
+ ...jest.requireActual("@aws-sdk/client-api-gateway"),
9
+ APIGatewayClient: jest.fn(() => ({
10
+ send: (...args) => holder.send(...args),
11
+ })),
12
+ }));
13
+ const client_api_gateway_1 = require("@aws-sdk/client-api-gateway");
14
+ const redeploy_stage_1 = require("./redeploy-stage");
15
+ const holder = { send: jest.fn() };
16
+ const input = {
17
+ restApiId: "api1",
18
+ stageName: "prod",
19
+ stackStatus: "UPDATE_COMPLETE",
20
+ };
21
+ /** The API as it is: its deployments (pages of them) and its stages. */
22
+ function stubApi(pages, stages) {
23
+ holder.send.mockImplementation((command) => {
24
+ if (command instanceof client_api_gateway_1.CreateDeploymentCommand) {
25
+ return Promise.resolve({ id: "new" });
26
+ }
27
+ if (command instanceof client_api_gateway_1.GetStagesCommand) {
28
+ return Promise.resolve({ item: stages });
29
+ }
30
+ if (command instanceof client_api_gateway_1.GetDeploymentsCommand) {
31
+ const index = Number(command.input.position ?? 0);
32
+ return Promise.resolve({
33
+ items: pages[index],
34
+ position: index + 1 < pages.length ? String(index + 1) : undefined,
35
+ });
36
+ }
37
+ return Promise.resolve({});
38
+ });
39
+ }
40
+ function sent(type) {
41
+ return holder.send.mock.calls
42
+ .map(([command]) => command)
43
+ .filter((command) => command instanceof type);
44
+ }
45
+ beforeEach(() => holder.send.mockReset());
46
+ it("deploys the stage from the live API", async () => {
47
+ stubApi([[]], [{ stageName: "prod", deploymentId: "new" }]);
48
+ await expect((0, redeploy_stage_1.redeployStage)(input)).resolves.toBe("new");
49
+ expect(sent(client_api_gateway_1.CreateDeploymentCommand).map((c) => c.input)).toEqual([
50
+ {
51
+ restApiId: "api1",
52
+ stageName: "prod",
53
+ description: `${redeploy_stage_1.REDEPLOY_DESCRIPTION_PREFIX} UPDATE_COMPLETE`,
54
+ },
55
+ ]);
56
+ });
57
+ it("deletes only its own earlier deployments no stage references", async () => {
58
+ const ours = (id) => ({
59
+ id,
60
+ description: `${redeploy_stage_1.REDEPLOY_DESCRIPTION_PREFIX} UPDATE_COMPLETE`,
61
+ });
62
+ stubApi([
63
+ // CloudFormation's own, its previous run's, and the new one.
64
+ [
65
+ {
66
+ id: "cfn",
67
+ description: "Automatically created by the RestApi construct",
68
+ },
69
+ ours("prev"),
70
+ ],
71
+ // A run whose deployment another stage still serves, on a second page.
72
+ [ours("pinned"), ours("new")],
73
+ ], [
74
+ { stageName: "prod", deploymentId: "new" },
75
+ { stageName: "canary", deploymentId: "pinned" },
76
+ ]);
77
+ await (0, redeploy_stage_1.redeployStage)(input);
78
+ expect(sent(client_api_gateway_1.DeleteDeploymentCommand).map((c) => c.input)).toEqual([
79
+ { restApiId: "api1", deploymentId: "prev" },
80
+ ]);
81
+ });
82
+ it("does not fail the run when a prune is rejected", async () => {
83
+ stubApi([[{ id: "prev", description: `${redeploy_stage_1.REDEPLOY_DESCRIPTION_PREFIX} x` }]], []);
84
+ const warn = jest.spyOn(console, "warn").mockImplementation(() => { });
85
+ const send = holder.send.getMockImplementation();
86
+ holder.send.mockImplementation((command) => command instanceof client_api_gateway_1.DeleteDeploymentCommand
87
+ ? Promise.reject(new Error("BadRequestException"))
88
+ : send(command));
89
+ await expect((0, redeploy_stage_1.redeployStage)(input)).resolves.toBe("new");
90
+ expect(warn).toHaveBeenCalled();
91
+ warn.mockRestore();
92
+ });
93
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkZXBsb3ktc3RhZ2UudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYW1iZGFzL3JlZGVwbG95LXN0YWdlL3JlZGVwbG95LXN0YWdlLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxzREFBc0Q7QUFDdEQsNkVBQTZFO0FBQzdFLDBFQUEwRTtBQUMxRSx3Q0FBd0M7QUFDeEMsSUFBSSxDQUFDLElBQUksQ0FBQyw2QkFBNkIsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQzlDLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyw2QkFBNkIsQ0FBQztJQUNwRCxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDL0IsSUFBSSxFQUFFLENBQUMsR0FBRyxJQUFlLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUM7S0FDbkQsQ0FBQyxDQUFDO0NBQ0osQ0FBQyxDQUFDLENBQUM7QUFFSixvRUFLcUM7QUFDckMscURBQThFO0FBRTlFLE1BQU0sTUFBTSxHQUFHLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDO0FBRW5DLE1BQU0sS0FBSyxHQUFHO0lBQ1osU0FBUyxFQUFFLE1BQU07SUFDakIsU0FBUyxFQUFFLE1BQU07SUFDakIsV0FBVyxFQUFFLGlCQUFpQjtDQUMvQixDQUFDO0FBRUYsd0VBQXdFO0FBQ3hFLFNBQVMsT0FBTyxDQUNkLEtBQStDLEVBQy9DLE1BQXFEO0lBRXJELE1BQU0sQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxPQUFnQixFQUFFLEVBQUU7UUFDbEQsSUFBSSxPQUFPLFlBQVksNENBQXVCLEVBQUUsQ0FBQztZQUMvQyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUN4QyxDQUFDO1FB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c291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzICovXG4vLyBPbmx5IHRoZSBjbGllbnQgaXMgbW9ja2VkOyB0aGUgY29tbWFuZCBjbGFzc2VzIHN0YXkgcmVhbCBzbyBhc3NlcnRpb25zIGNhblxuLy8gcmVhZCBgY29tbWFuZC5pbnB1dGAuIGBzZW5kYCBnb2VzIHRocm91Z2ggdGhlIGhvbGRlciBiZWNhdXNlIHRoZSBtb2R1bGVcbi8vIGNvbnN0cnVjdHMgaXRzIGNsaWVudCBhdCBpbXBvcnQgdGltZS5cbmplc3QubW9jayhcIkBhd3Mtc2RrL2NsaWVudC1hcGktZ2F0ZXdheVwiLCAoKSA9PiAoe1xuICAuLi5qZXN0LnJlcXVpcmVBY3R1YWwoXCJAYXdzLXNkay9jbGllbnQtYXBpLWdhdGV3YXlcIiksXG4gIEFQSUdhdGV3YXlDbGllbnQ6IGplc3QuZm4oKCkgPT4gKHtcbiAgICBzZW5kOiAoLi4uYXJnczogdW5rbm93bltdKSA9PiBob2xkZXIuc2VuZCguLi5hcmdzKSxcbiAgfSkpLFxufSkpO1xuXG5pbXBvcnQge1xuICBDcmVhdGVEZXBsb3ltZW50Q29tbWFuZCxcbiAgRGVsZXRlRGVwbG95bWVudENvbW1hbmQsXG4gIEdldERlcGxveW1lbnRzQ29tbWFuZCxcbiAgR2V0U3RhZ2VzQ29tbWFuZCxcbn0gZnJvbSBcIkBhd3Mtc2RrL2NsaWVudC1hcGktZ2F0ZXdheVwiO1xuaW1wb3J0IHsgUkVERVBMT1lfREVTQ1JJUFRJT05fUFJFRklYLCByZWRlcGxveVN0YWdlIH0gZnJvbSBcIi4vcmVkZXBsb3ktc3RhZ2VcIjtcblxuY29uc3QgaG9sZGVyID0geyBzZW5kOiBqZXN0LmZuKCkgfTtcblxuY29uc3QgaW5wdXQgPSB7XG4gIHJlc3RBcGlJZDogXCJhcGkxXCIsXG4gIHN0YWdlTmFtZTogXCJwcm9kXCIsXG4gIHN0YWNrU3RhdHVzOiBcIlVQREFURV9DT01QTEVURVwiLFxufTtcblxuLyoqIFRoZSBBUEkgYXMgaXQgaXM6IGl0cyBkZXBsb3ltZW50cyAocGFnZXMgb2YgdGhlbSkgYW5kIGl0cyBzdGFnZXMuICovXG5mdW5jdGlvbiBzdHViQXBpKFxuICBwYWdlczogeyBpZDogc3RyaW5nOyBkZXNjcmlwdGlvbj86IHN0cmluZyB9W11bXSxcbiAgc3RhZ2VzOiB7IHN0YWdlTmFtZTogc3RyaW5nOyBkZXBsb3ltZW50SWQ6IHN0cmluZyB9W10sXG4pIHtcbiAgaG9sZGVyLnNlbmQubW9ja0ltcGxlbWVudGF0aW9uKChjb21tYW5kOiB1bmtub3duKSA9PiB7XG4gICAgaWYgKGNvbW1hbmQgaW5zdGFuY2VvZiBDcmVhdGVEZXBsb3ltZW50Q29tbWFuZCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7IGlkOiBcIm5ld1wiIH0pO1xuICAgIH1cbiAgICBpZiAoY29tbWFuZCBpbnN0YW5jZW9mIEdldFN0YWdlc0NvbW1hbmQpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoeyBpdGVtOiBzdGFnZXMgfSk7XG4gICAgfVxuICAgIGlmIChjb21tYW5kIGluc3RhbmNlb2YgR2V0RGVwbG95bWVudHNDb21tYW5kKSB7XG4gICAgICBjb25zdCBpbmRleCA9IE51bWJlcihjb21tYW5kLmlucHV0LnBvc2l0aW9uID8/IDApO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgIGl0ZW1zOiBwYWdlc1tpbmRleF0sXG4gICAgICAgIHBvc2l0aW9uOiBpbmRleCArIDEgPCBwYWdlcy5sZW5ndGggPyBTdHJpbmcoaW5kZXggKyAxKSA6IHVuZGVmaW5lZCxcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIHNlbnQ8VD4odHlwZTogbmV3ICguLi5hcmdzOiBuZXZlcltdKSA9PiBUKTogVFtdIHtcbiAgcmV0dXJuIGhvbGRlci5zZW5kLm1vY2suY2FsbHNcbiAgICAubWFwKChbY29tbWFuZF0pID0+IGNvbW1hbmQpXG4gICAgLmZpbHRlcigoY29tbWFuZCk6IGNvbW1hbmQgaXMgVCA9PiBjb21tYW5kIGluc3RhbmNlb2YgdHlwZSk7XG59XG5cbmJlZm9yZUVhY2goKCkgPT4gaG9sZGVyLnNlbmQubW9ja1Jlc2V0KCkpO1xuXG5pdChcImRlcGxveXMgdGhlIHN0YWdlIGZyb20gdGhlIGxpdmUgQVBJXCIsIGFzeW5jICgpID0+IHtcbiAgc3R1YkFwaShbW11dLCBbeyBzdGFnZU5hbWU6IFwicHJvZFwiLCBkZXBsb3ltZW50SWQ6IFwibmV3XCIgfV0pO1xuXG4gIGF3YWl0IGV4cGVjdChyZWRlcGxveVN0YWdlKGlucHV0KSkucmVzb2x2ZXMudG9CZShcIm5ld1wiKTtcblxuICBleHBlY3Qoc2VudChDcmVhdGVEZXBsb3ltZW50Q29tbWFuZCkubWFwKChjKSA9PiBjLmlucHV0KSkudG9FcXVhbChbXG4gICAge1xuICAgICAgcmVzdEFwaUlkOiBcImFwaTFcIixcbiAgICAgIHN0YWdlTmFtZTogXCJwcm9kXCIsXG4gICAgICBkZXNjcmlwdGlvbjogYCR7UkVERVBMT1lfREVTQ1JJUFRJT05fUFJFRklYfSBVUERBVEVfQ09NUExFVEVgLFxuICAgIH0sXG4gIF0pO1xufSk7XG5cbml0KFwiZGVsZXRlcyBvbmx5IGl0cyBvd24gZWFybGllciBkZXBsb3ltZW50cyBubyBzdGFnZSByZWZlcmVuY2VzXCIsIGFzeW5jICgpID0+IHtcbiAgY29uc3Qgb3VycyA9IChpZDogc3RyaW5nKSA9PiAoe1xuICAgIGlkLFxuICAgIGRlc2NyaXB0aW9uOiBgJHtSRURFUExPWV9ERVNDUklQVElPTl9QUkVGSVh9IFVQREFURV9DT01QTEVURWAsXG4gIH0pO1xuICBzdHViQXBpKFxuICAgIFtcbiAgICAgIC8vIENsb3VkRm9ybWF0aW9uJ3Mgb3duLCBpdHMgcHJldmlvdXMgcnVuJ3MsIGFuZCB0aGUgbmV3IG9uZS5cbiAgICAgIFtcbiAgICAgICAge1xuICAgICAgICAgIGlkOiBcImNmblwiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkF1dG9tYXRpY2FsbHkgY3JlYXRlZCBieSB0aGUgUmVzdEFwaSBjb25zdHJ1Y3RcIixcbiAgICAgICAgfSxcbiAgICAgICAgb3VycyhcInByZXZcIiksXG4gICAgICBdLFxuICAgICAgLy8gQSBydW4gd2hvc2UgZGVwbG95bWVudCBhbm90aGVyIHN0YWdlIHN0aWxsIHNlcnZlcywgb24gYSBzZWNvbmQgcGFnZS5cbiAgICAgIFtvdXJzKFwicGlubmVkXCIpLCBvdXJzKFwibmV3XCIpXSxcbiAgICBdLFxuICAgIFtcbiAgICAgIHsgc3RhZ2VOYW1lOiBcInByb2RcIiwgZGVwbG95bWVudElkOiBcIm5ld1wiIH0sXG4gICAgICB7IHN0YWdlTmFtZTogXCJjYW5hcnlcIiwgZGVwbG95bWVudElkOiBcInBpbm5lZFwiIH0sXG4gICAgXSxcbiAgKTtcblxuICBhd2FpdCByZWRlcGxveVN0YWdlKGlucHV0KTtcblxuICBleHBlY3Qoc2VudChEZWxldGVEZXBsb3ltZW50Q29tbWFuZCkubWFwKChjKSA9PiBjLmlucHV0KSkudG9FcXVhbChbXG4gICAgeyByZXN0QXBpSWQ6IFwiYXBpMVwiLCBkZXBsb3ltZW50SWQ6IFwicHJldlwiIH0sXG4gIF0pO1xufSk7XG5cbml0KFwiZG9lcyBub3QgZmFpbCB0aGUgcnVuIHdoZW4gYSBwcnVuZSBpcyByZWplY3RlZFwiLCBhc3luYyAoKSA9PiB7XG4gIHN0dWJBcGkoXG4gICAgW1t7IGlkOiBcInByZXZcIiwgZGVzY3JpcHRpb246IGAke1JFREVQTE9ZX0RFU0NSSVBUSU9OX1BSRUZJWH0geGAgfV1dLFxuICAgIFtdLFxuICApO1xuICBjb25zdCB3YXJuID0gamVzdC5zcHlPbihjb25zb2xlLCBcIndhcm5cIikubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+IHt9KTtcbiAgY29uc3Qgc2VuZCA9IGhvbGRlci5zZW5kLmdldE1vY2tJbXBsZW1lbnRhdGlvbigpITtcbiAgaG9sZGVyLnNlbmQubW9ja0ltcGxlbWVudGF0aW9uKChjb21tYW5kOiB1bmtub3duKSA9PlxuICAgIGNvbW1hbmQgaW5zdGFuY2VvZiBEZWxldGVEZXBsb3ltZW50Q29tbWFuZFxuICAgICAgPyBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoXCJCYWRSZXF1ZXN0RXhjZXB0aW9uXCIpKVxuICAgICAgOiBzZW5kKGNvbW1hbmQpLFxuICApO1xuXG4gIGF3YWl0IGV4cGVjdChyZWRlcGxveVN0YWdlKGlucHV0KSkucmVzb2x2ZXMudG9CZShcIm5ld1wiKTtcbiAgZXhwZWN0KHdhcm4pLnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgd2Fybi5tb2NrUmVzdG9yZSgpO1xufSk7XG4iXX0=
@@ -1,15 +1,22 @@
1
1
  import { RestApi, MethodOptions, RestApiProps, AwsIntegrationProps, LambdaIntegrationOptions } from "aws-cdk-lib/aws-apigateway";
2
2
  import { IVpc } from "aws-cdk-lib/aws-ec2";
3
- import { IFunction } from "aws-cdk-lib/aws-lambda";
3
+ import { Rule } from "aws-cdk-lib/aws-events";
4
+ import { Function as LambdaFunction, IFunction } from "aws-cdk-lib/aws-lambda";
4
5
  import { IBucket } from "aws-cdk-lib/aws-s3";
5
6
  import { Construct } from "constructs";
6
- import { PublicDirEntry } from "./nextjs-build/nextjs-build";
7
+ import { OptionalFunctionProps } from "./generated-structs/OptionalFunctionProps";
8
+ import { NextjsFunctionGroupBehavior, PublicDirEntry } from "./nextjs-build/nextjs-build";
7
9
  export interface NextjsApiOverrides {
8
10
  readonly restApiProps?: RestApiProps;
9
11
  readonly staticIntegrationProps?: AwsIntegrationProps;
10
12
  readonly s3MethodOptions?: MethodOptions;
11
13
  readonly dynamicIntegrationProps?: LambdaIntegrationOptions;
12
- readonly imageIntegrationProps?: LambdaIntegrationOptions;
14
+ /**
15
+ * Props for the function that deploys the stage again after each stack
16
+ * update.
17
+ * @see NextjsApiProps.redeployAfterUpdate
18
+ */
19
+ readonly redeployFunctionProps?: OptionalFunctionProps;
13
20
  }
14
21
  export interface NextjsApiProps {
15
22
  /**
@@ -29,19 +36,6 @@ export interface NextjsApiProps {
29
36
  * Required if `NextjsRegionalFunctions`. The Lambda function for server-side rendering
30
37
  */
31
38
  readonly serverFunction?: IFunction;
32
- /**
33
- * Dedicated image optimization Lambda for the `_next/image` route. When
34
- * omitted, no `_next/image` resource is created and those requests fall
35
- * through to `serverFunction` via the `{proxy+}` catch-all.
36
- *
37
- * When provided, it is assumed to support Lambda response streaming (as the
38
- * dedicated image Lambda this package builds does) and is invoked with
39
- * `ResponseTransferMode.STREAM` accordingly. If you supply a custom
40
- * `imageFunction` that doesn't support streaming, override
41
- * `responseTransferMode` to `BUFFERED` via `overrides.imageIntegrationProps`,
42
- * otherwise API Gateway returns a 502.
43
- */
44
- readonly imageFunction?: IFunction;
45
39
  /**
46
40
  * The S3 bucket containing static assets
47
41
  */
@@ -61,6 +55,40 @@ export interface NextjsApiProps {
61
55
  * [Future] Required if `NextjsRegionalContainers`. VPC to create VPC Link and ECS Service Discovery
62
56
  */
63
57
  readonly vpc?: IVpc;
58
+ /**
59
+ * The non-`default` function groups, the Lambdas
60
+ * {@link functionGroupBehaviors} route to.
61
+ * @default - no splitting; `{proxy+}` serves every dynamic route
62
+ */
63
+ readonly functionGroups?: NextjsApiFunctionGroup[];
64
+ /**
65
+ * `NextjsBuild.functionGroupBehaviors`: each distinct `route` becomes a
66
+ * resource subtree integrated with its group, so the routes each group was
67
+ * packaged with reach it rather than {@link serverFunction}.
68
+ * @default - none
69
+ */
70
+ readonly functionGroupBehaviors?: NextjsFunctionGroupBehavior[];
71
+ /**
72
+ * Deploy the stage again once each stack update has finished, so it serves
73
+ * the API as it is after the update.
74
+ *
75
+ * CloudFormation snapshots the API into a new deployment while resources
76
+ * removed from the template still exist — it deletes them only during
77
+ * cleanup — so the stage keeps serving them. After removing a function
78
+ * group, its routes then point at a deleted Lambda and answer 500 until the
79
+ * next deployment. An EventBridge rule on this stack's `UPDATE_COMPLETE`
80
+ * (and `UPDATE_ROLLBACK_COMPLETE`) invokes a small function that deploys the
81
+ * stage from the live API and deletes the deployments its earlier runs made.
82
+ *
83
+ * Ignored when `overrides.restApiProps.deploy` is `false`: there is no stage.
84
+ * @default true
85
+ */
86
+ readonly redeployAfterUpdate?: boolean;
87
+ }
88
+ /** A non-default function group and the Lambda its routes must reach. */
89
+ export interface NextjsApiFunctionGroup {
90
+ readonly name: string;
91
+ readonly function: IFunction;
64
92
  }
65
93
  /**
66
94
  * Creates an API Gateway REST API for Next.js applications
@@ -80,11 +108,31 @@ export declare class NextjsApi extends Construct {
80
108
  * mapping added that way won't show up here.
81
109
  */
82
110
  get url(): string;
111
+ /**
112
+ * Deploys the stage again after each stack update.
113
+ * @see NextjsApiProps.redeployAfterUpdate
114
+ */
115
+ readonly redeployFunction?: LambdaFunction;
116
+ /**
117
+ * Matches this stack's `UPDATE_COMPLETE` and `UPDATE_ROLLBACK_COMPLETE` and
118
+ * invokes {@link redeployFunction}.
119
+ */
120
+ readonly redeployRule?: Rule;
83
121
  private readonly baseResource;
84
122
  private readonly nextResource;
123
+ /**
124
+ * Resources created only as parents of a group route, and their paths. API
125
+ * Gateway answers a request for a resource with no method itself — 403
126
+ * "Missing Authentication Token" — rather than falling back to a `{proxy+}`
127
+ * higher up, so each needs one. Without it a `/api/reports/**` group turned
128
+ * `/api/reports` and `/api` into 403s.
129
+ */
130
+ private readonly groupParentResources;
85
131
  private readonly props;
86
132
  private staticIntegrationRole;
87
133
  constructor(scope: Construct, id: string, props: NextjsApiProps);
134
+ /** @see NextjsApiProps.redeployAfterUpdate */
135
+ private createRedeploy;
88
136
  private validateProps;
89
137
  private createRestApi;
90
138
  /**
@@ -111,9 +159,45 @@ export declare class NextjsApi extends Construct {
111
159
  private createS3Integration;
112
160
  private getStaticMethodOptions;
113
161
  /**
114
- * Create Lambda Proxy integration for the `_next/image` route.
162
+ * One resource subtree per function group pattern.
163
+ *
164
+ * Unlike CloudFront this needs no ordering: API Gateway matches on a resource
165
+ * *tree*, so `/api/reports/{proxy+}` beats `/api/{proxy+}` beats `/{proxy+}`
166
+ * structurally, and "longest pattern wins" comes for free. What does need care
167
+ * is not creating the same path twice — two groups under `/api` share the `api`
168
+ * resource — so every segment goes through {@link resourceFor}.
169
+ */
170
+ private createFunctionGroupIntegrations;
171
+ /**
172
+ * The group pattern validation accepts every character a CloudFront path
173
+ * pattern can hold, and API Gateway's path parts hold fewer: `~`, `@`, `+`,
174
+ * `&` and quotes pass it and then fail `addResource` with an error that names
175
+ * neither the group nor the pattern. Say which, and what to do instead.
176
+ */
177
+ private assertRoutable;
178
+ /**
179
+ * Refuse a group route that shares a resource with a `public/` entry.
180
+ *
181
+ * A public directory `docs` is `docs/{proxy+}` with a `GET` to S3. `/docs/**`
182
+ * adds `ANY` to that same resource, and API Gateway prefers the `GET`, so
183
+ * every page load under the group went to S3; `/docs/guide/**` is a more
184
+ * specific resource instead, and takes `/docs/guide/…` away from the public
185
+ * files. A public file `pricing` and an exact `/pricing` are the same
186
+ * resource the same way. `NextjsDistribution` rejects the CloudFront
187
+ * equivalents.
188
+ */
189
+ private assertNoPublicCollision;
190
+ /**
191
+ * Resource paths, as segment arrays, for one group pattern.
192
+ *
193
+ * A subtree gets `{proxy+}` as its last segment and so owns everything *under*
194
+ * the path but not the path itself, matching both the CloudFront translation and
195
+ * `assignRoutesToGroups`. An exact path gets no proxy segment, which leaves its
196
+ * children falling through to the root `{proxy+}` — also the CloudFront result.
115
197
  */
116
- private createImageIntegration;
198
+ private resourcePathsFor;
199
+ /** Walk or create a resource path, reusing whatever already exists. */
200
+ private resourceFor;
117
201
  /**
118
202
  * Create Lambda Proxy integration for all other routes
119
203
  */