@aws/nx-plugin 1.0.0-rc.4 → 1.0.0-rc.41

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 (1138) hide show
  1. package/LICENSE-THIRD-PARTY +5449 -4980
  2. package/README.md +7 -7
  3. package/executors.json +9 -0
  4. package/generators.json +101 -2
  5. package/package.json +35 -17
  6. package/src/agentcore-gateway/attach-upstream.d.ts +33 -0
  7. package/src/agentcore-gateway/attach-upstream.js +38 -0
  8. package/src/agentcore-gateway/attach-upstream.js.map +1 -0
  9. package/src/agentcore-gateway/files/cedar/policies/README.md +52 -0
  10. package/src/agentcore-gateway/files/cedar/policies/permit-all.cedar +11 -0
  11. package/src/agentcore-gateway/files/project/local-dev.ts.template +134 -0
  12. package/src/agentcore-gateway/gateway-connection/generator.d.ts +21 -0
  13. package/src/agentcore-gateway/gateway-connection/generator.js +101 -0
  14. package/src/agentcore-gateway/gateway-connection/generator.js.map +1 -0
  15. package/src/agentcore-gateway/gateway-connection/schema.d.js +6 -0
  16. package/src/agentcore-gateway/gateway-connection/schema.d.js.map +1 -0
  17. package/src/agentcore-gateway/gateway-connection/schema.d.ts +13 -0
  18. package/src/agentcore-gateway/gateway-connection/schema.json +31 -0
  19. package/src/agentcore-gateway/generator.d.ts +25 -0
  20. package/src/agentcore-gateway/generator.js +149 -0
  21. package/src/agentcore-gateway/generator.js.map +1 -0
  22. package/src/agentcore-gateway/mcp-connection/generator.d.ts +19 -0
  23. package/src/agentcore-gateway/mcp-connection/generator.js +59 -0
  24. package/src/agentcore-gateway/mcp-connection/generator.js.map +1 -0
  25. package/src/agentcore-gateway/mcp-connection/schema.d.js +6 -0
  26. package/src/agentcore-gateway/mcp-connection/schema.d.js.map +1 -0
  27. package/src/agentcore-gateway/mcp-connection/schema.d.ts +13 -0
  28. package/src/agentcore-gateway/mcp-connection/schema.json +31 -0
  29. package/src/agentcore-gateway/schema.d.js +6 -0
  30. package/src/agentcore-gateway/schema.d.js.map +1 -0
  31. package/src/agentcore-gateway/schema.d.ts +17 -0
  32. package/src/agentcore-gateway/schema.json +70 -0
  33. package/src/bin/aws-nx-mcp.js +14 -0
  34. package/src/bin/aws-nx-mcp.js.map +1 -0
  35. package/src/connection/{agent-serve-local.d.ts → agent-local-dev.d.ts} +7 -7
  36. package/src/connection/agent-local-dev.js +42 -0
  37. package/src/connection/agent-local-dev.js.map +1 -0
  38. package/src/connection/agent-runtime-config.d.ts +1 -1
  39. package/src/connection/agent-runtime-config.js +9 -14
  40. package/src/connection/agent-runtime-config.js.map +1 -1
  41. package/src/connection/generator.d.ts +7 -14
  42. package/src/connection/generator.js +167 -194
  43. package/src/connection/generator.js.map +1 -1
  44. package/src/connection/local-dev.d.ts +15 -0
  45. package/src/connection/local-dev.js +37 -0
  46. package/src/connection/local-dev.js.map +1 -0
  47. package/src/connection/schema.d.js +6 -0
  48. package/src/connection/schema.d.js.map +1 -0
  49. package/src/connection/schema.d.ts +1 -0
  50. package/src/connection/schema.json +5 -0
  51. package/src/connection/supported-connections.d.ts +107 -0
  52. package/src/connection/supported-connections.js +151 -0
  53. package/src/connection/supported-connections.js.map +1 -0
  54. package/src/index.js +2 -5
  55. package/src/index.js.map +1 -1
  56. package/src/infra/app/__snapshots__/generator.spec.ts.snap +97 -85
  57. package/src/infra/app/files/app/src/main.ts.template +1 -1
  58. package/src/infra/app/files/app/src/stages/application-stage.ts.template +1 -1
  59. package/src/infra/app/generator.d.ts +3 -3
  60. package/src/infra/app/generator.js +142 -122
  61. package/src/infra/app/generator.js.map +1 -1
  62. package/src/infra/app/schema.d.js +6 -0
  63. package/src/infra/app/schema.d.js.map +1 -0
  64. package/src/infra/app/schema.d.ts +1 -1
  65. package/src/infra/app/schema.json +5 -0
  66. package/src/init/generator.d.ts +18 -0
  67. package/src/init/generator.js +35 -0
  68. package/src/init/generator.js.map +1 -0
  69. package/src/init/schema.d.js +6 -0
  70. package/src/init/schema.d.js.map +1 -0
  71. package/src/init/schema.d.ts +16 -0
  72. package/src/init/schema.json +35 -0
  73. package/src/license/__snapshots__/config.spec.ts.snap +23 -0
  74. package/src/license/config-types.d.ts +18 -1
  75. package/src/license/config-types.js +8 -2
  76. package/src/license/config-types.js.map +1 -1
  77. package/src/license/config.d.ts +65 -7
  78. package/src/license/config.js +442 -109
  79. package/src/license/config.js.map +1 -1
  80. package/src/license/dependency-check/check.d.ts +16 -0
  81. package/src/license/dependency-check/check.js +116 -0
  82. package/src/license/dependency-check/check.js.map +1 -0
  83. package/src/license/dependency-check/collectors/collector.d.ts +21 -0
  84. package/src/license/dependency-check/collectors/collector.js +46 -0
  85. package/src/license/dependency-check/collectors/collector.js.map +1 -0
  86. package/src/license/dependency-check/collectors/npm-collector.d.ts +10 -0
  87. package/src/license/dependency-check/collectors/npm-collector.js +68 -0
  88. package/src/license/dependency-check/collectors/npm-collector.js.map +1 -0
  89. package/src/license/dependency-check/collectors/python-collector.d.ts +23 -0
  90. package/src/license/dependency-check/collectors/python-collector.js +114 -0
  91. package/src/license/dependency-check/collectors/python-collector.js.map +1 -0
  92. package/src/license/dependency-check/evaluator.d.ts +9 -0
  93. package/src/license/dependency-check/evaluator.js +94 -0
  94. package/src/license/dependency-check/evaluator.js.map +1 -0
  95. package/src/license/dependency-check/executor-schema.json +6 -0
  96. package/src/license/dependency-check/executor.d.ts +9 -0
  97. package/src/license/dependency-check/executor.js +51 -0
  98. package/src/license/dependency-check/executor.js.map +1 -0
  99. package/src/license/dependency-check/pre-approved.d.ts +6 -0
  100. package/src/license/dependency-check/pre-approved.js +1893 -0
  101. package/src/license/dependency-check/pre-approved.js.map +1 -0
  102. package/src/license/dependency-check/types.d.ts +45 -0
  103. package/src/license/dependency-check/types.js +6 -0
  104. package/src/license/dependency-check/types.js.map +1 -0
  105. package/src/license/generator.d.ts +3 -3
  106. package/src/license/generator.js +126 -30
  107. package/src/license/generator.js.map +1 -1
  108. package/src/license/index.d.ts +8 -0
  109. package/src/license/index.js +7 -0
  110. package/src/license/index.js.map +1 -0
  111. package/src/license/known-exceptions.d.ts +7 -0
  112. package/src/license/known-exceptions.js +39 -0
  113. package/src/license/known-exceptions.js.map +1 -0
  114. package/src/license/schema.d.js +6 -0
  115. package/src/license/schema.d.js.map +1 -0
  116. package/src/license/schema.d.ts +7 -0
  117. package/src/license/schema.json +11 -0
  118. package/src/license/sync/generator.d.ts +2 -2
  119. package/src/license/sync/generator.js +100 -125
  120. package/src/license/sync/generator.js.map +1 -1
  121. package/src/license/sync/project-file-sync.d.ts +3 -3
  122. package/src/license/sync/project-file-sync.js +28 -35
  123. package/src/license/sync/project-file-sync.js.map +1 -1
  124. package/src/mcp-server/generator-info.d.ts +5 -1
  125. package/src/mcp-server/generator-info.js +149 -165
  126. package/src/mcp-server/generator-info.js.map +1 -1
  127. package/src/mcp-server/guide-pipeline.d.ts +1 -1
  128. package/src/mcp-server/guide-pipeline.js +199 -206
  129. package/src/mcp-server/guide-pipeline.js.map +1 -1
  130. package/src/mcp-server/guide-render.js +10 -25
  131. package/src/mcp-server/guide-render.js.map +1 -1
  132. package/src/mcp-server/index.js +6 -10
  133. package/src/mcp-server/index.js.map +1 -1
  134. package/src/mcp-server/mdx-ast.js +42 -56
  135. package/src/mcp-server/mdx-ast.js.map +1 -1
  136. package/src/mcp-server/option-filter.js +33 -47
  137. package/src/mcp-server/option-filter.js.map +1 -1
  138. package/src/mcp-server/schema-registry.d.ts +9 -3
  139. package/src/mcp-server/schema-registry.js +41 -38
  140. package/src/mcp-server/schema-registry.js.map +1 -1
  141. package/src/mcp-server/schema.js +9 -7
  142. package/src/mcp-server/schema.js.map +1 -1
  143. package/src/mcp-server/server.js +22 -24
  144. package/src/mcp-server/server.js.map +1 -1
  145. package/src/mcp-server/tools/add-to-existing-project.d.ts +12 -0
  146. package/src/mcp-server/tools/add-to-existing-project.js +36 -0
  147. package/src/mcp-server/tools/add-to-existing-project.js.map +1 -0
  148. package/src/mcp-server/tools/create-workspace-command.d.ts +1 -1
  149. package/src/mcp-server/tools/create-workspace-command.js +23 -24
  150. package/src/mcp-server/tools/create-workspace-command.js.map +1 -1
  151. package/src/mcp-server/tools/general-guidance.d.ts +3 -3
  152. package/src/mcp-server/tools/general-guidance.js +47 -25
  153. package/src/mcp-server/tools/general-guidance.js.map +1 -1
  154. package/src/mcp-server/tools/generator-guide.d.ts +2 -2
  155. package/src/mcp-server/tools/generator-guide.js +29 -37
  156. package/src/mcp-server/tools/generator-guide.js.map +1 -1
  157. package/src/mcp-server/tools/list-generators.d.ts +2 -2
  158. package/src/mcp-server/tools/list-generators.js +19 -25
  159. package/src/mcp-server/tools/list-generators.js.map +1 -1
  160. package/src/open-api/ts-client/__snapshots__/generator.additional-properties.spec.ts.snap +147 -33
  161. package/src/open-api/ts-client/__snapshots__/generator.arrays.spec.ts.snap +308 -75
  162. package/src/open-api/ts-client/__snapshots__/generator.complex-types.spec.ts.snap +298 -74
  163. package/src/open-api/ts-client/__snapshots__/generator.composite-types.spec.ts.snap +748 -103
  164. package/src/open-api/ts-client/__snapshots__/generator.content-type.spec.ts.snap +230 -37
  165. package/src/open-api/ts-client/__snapshots__/generator.duplicate-types.spec.ts.snap +249 -52
  166. package/src/open-api/ts-client/__snapshots__/generator.edge-cases.spec.ts.snap +5535 -0
  167. package/src/open-api/ts-client/__snapshots__/generator.fast-api-gaps.spec.ts.snap +736 -0
  168. package/src/open-api/ts-client/__snapshots__/generator.fast-api.spec.ts.snap +305 -71
  169. package/src/open-api/ts-client/__snapshots__/generator.multipart.spec.ts.snap +298 -0
  170. package/src/open-api/ts-client/__snapshots__/generator.primitive-types.spec.ts.snap +353 -82
  171. package/src/open-api/ts-client/__snapshots__/generator.request.spec.ts.snap +176 -55
  172. package/src/open-api/ts-client/__snapshots__/generator.reserved-keywords.spec.ts.snap +101 -25
  173. package/src/open-api/ts-client/__snapshots__/generator.response.spec.ts.snap +147 -33
  174. package/src/open-api/ts-client/__snapshots__/generator.spec-compliance.spec.ts.snap +1883 -0
  175. package/src/open-api/ts-client/__snapshots__/generator.streaming.spec.ts.snap +392 -88
  176. package/src/open-api/ts-client/__snapshots__/generator.tags.spec.ts.snap +200 -48
  177. package/src/open-api/ts-client/files/client.gen.ts.template +358 -24
  178. package/src/open-api/ts-client/files/types.gen.ts.template +6 -4
  179. package/src/open-api/ts-client/generator.d.ts +3 -3
  180. package/src/open-api/ts-client/generator.js +41 -26
  181. package/src/open-api/ts-client/generator.js.map +1 -1
  182. package/src/open-api/ts-client/schema.d.js +6 -0
  183. package/src/open-api/ts-client/schema.d.js.map +1 -0
  184. package/src/open-api/ts-hooks/files/options-proxy.gen.ts.template +7 -2
  185. package/src/open-api/ts-hooks/generator.d.ts +3 -3
  186. package/src/open-api/ts-hooks/generator.js +17 -21
  187. package/src/open-api/ts-hooks/generator.js.map +1 -1
  188. package/src/open-api/ts-hooks/generator.spec.tsx +84 -14
  189. package/src/open-api/ts-hooks/schema.d.js +6 -0
  190. package/src/open-api/ts-hooks/schema.d.js.map +1 -0
  191. package/src/open-api/ts-metadata/generator.d.ts +3 -3
  192. package/src/open-api/ts-metadata/generator.js +12 -20
  193. package/src/open-api/ts-metadata/generator.js.map +1 -1
  194. package/src/open-api/ts-metadata/schema.d.js +6 -0
  195. package/src/open-api/ts-metadata/schema.d.js.map +1 -0
  196. package/src/open-api/utils/codegen-data/languages.d.ts +3 -5
  197. package/src/open-api/utils/codegen-data/languages.js +59 -66
  198. package/src/open-api/utils/codegen-data/languages.js.map +1 -1
  199. package/src/open-api/utils/codegen-data/types.d.ts +255 -10
  200. package/src/open-api/utils/codegen-data/types.js +54 -30
  201. package/src/open-api/utils/codegen-data/types.js.map +1 -1
  202. package/src/open-api/utils/codegen-data.d.ts +8 -4
  203. package/src/open-api/utils/codegen-data.js +494 -674
  204. package/src/open-api/utils/codegen-data.js.map +1 -1
  205. package/src/open-api/utils/normalise.d.ts +5 -1
  206. package/src/open-api/utils/normalise.js +437 -246
  207. package/src/open-api/utils/normalise.js.map +1 -1
  208. package/src/open-api/utils/parse.d.ts +2 -2
  209. package/src/open-api/utils/parse.js +11 -13
  210. package/src/open-api/utils/parse.js.map +1 -1
  211. package/src/open-api/utils/parser.d.ts +55 -0
  212. package/src/open-api/utils/parser.js +787 -0
  213. package/src/open-api/utils/parser.js.map +1 -0
  214. package/src/open-api/utils/refs.d.ts +1 -1
  215. package/src/open-api/utils/refs.js +12 -22
  216. package/src/open-api/utils/refs.js.map +1 -1
  217. package/src/open-api/utils/types.d.ts +18 -0
  218. package/src/open-api/utils/types.js +5 -2
  219. package/src/open-api/utils/types.js.map +1 -1
  220. package/src/preset/__snapshots__/generator.spec.ts.snap +109 -28
  221. package/src/preset/generator.d.ts +4 -4
  222. package/src/preset/generator.js +64 -147
  223. package/src/preset/generator.js.map +1 -1
  224. package/src/preset/schema.d.js +6 -0
  225. package/src/preset/schema.d.js.map +1 -0
  226. package/src/preset/schema.d.ts +5 -2
  227. package/src/preset/schema.json +11 -5
  228. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +320 -0
  229. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +734 -0
  230. package/src/py/agent/__snapshots__/{generator.spec.ts.snap → generator.protocols.spec.ts.snap} +182 -314
  231. package/src/py/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +189 -0
  232. package/src/py/agent/a2a-connection/files/agent-connection/app/__targetAgentSnakeCase___client_strands.py.template +30 -0
  233. package/src/py/agent/a2a-connection/files/langchain/agent-connection/app/__targetAgentSnakeCase___client_langchain.py.template +28 -0
  234. package/src/py/agent/a2a-connection/generator.d.ts +3 -3
  235. package/src/py/agent/a2a-connection/generator.js +113 -85
  236. package/src/py/agent/a2a-connection/generator.js.map +1 -1
  237. package/src/py/agent/a2a-connection/schema.d.js +8 -0
  238. package/src/py/agent/a2a-connection/schema.d.js.map +1 -0
  239. package/src/py/agent/a2a-connection/schema.d.ts +1 -0
  240. package/src/py/agent/a2a-connection/schema.json +5 -0
  241. package/src/py/agent/files/a2a-langchain/main.py.template +89 -0
  242. package/src/py/agent/files/ag-ui-langchain/main.py.template +83 -0
  243. package/src/py/agent/files/common/agent.py.template +2 -0
  244. package/src/py/agent/files/common-langchain/agent.py.template +30 -0
  245. package/src/py/agent/files/deploy/Dockerfile.template +1 -1
  246. package/src/py/agent/files/http/init.py.template +7 -25
  247. package/src/py/agent/files/http/main.py.template +3 -4
  248. package/src/py/agent/files/http-langchain/main.py.template +84 -0
  249. package/src/py/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +184 -0
  250. package/src/py/agent/gateway-connection/files/agent-connection/app/__gatewaySnakeCase___client_strands.py.template +35 -0
  251. package/src/py/agent/gateway-connection/files/langchain/agent-connection/app/__gatewaySnakeCase___client_langchain.py.template +34 -0
  252. package/src/py/agent/gateway-connection/generator.d.ts +10 -0
  253. package/src/py/agent/gateway-connection/generator.js +119 -0
  254. package/src/py/agent/gateway-connection/generator.js.map +1 -0
  255. package/src/py/agent/gateway-connection/schema.d.js +6 -0
  256. package/src/py/agent/gateway-connection/schema.d.js.map +1 -0
  257. package/src/py/agent/gateway-connection/schema.d.ts +13 -0
  258. package/src/py/agent/gateway-connection/schema.json +31 -0
  259. package/src/py/agent/generator.d.ts +3 -3
  260. package/src/py/agent/generator.js +290 -179
  261. package/src/py/agent/generator.js.map +1 -1
  262. package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +153 -89
  263. package/src/py/agent/mcp-connection/files/agent-connection/app/__mcpServerSnakeCase___client_strands.py.template +30 -0
  264. package/src/py/agent/mcp-connection/files/langchain/agent-connection/app/__mcpServerSnakeCase___client_langchain.py.template +30 -0
  265. package/src/py/agent/mcp-connection/generator.d.ts +3 -3
  266. package/src/py/agent/mcp-connection/generator.js +65 -126
  267. package/src/py/agent/mcp-connection/generator.js.map +1 -1
  268. package/src/py/agent/mcp-connection/schema.d.js +8 -0
  269. package/src/py/agent/mcp-connection/schema.d.js.map +1 -0
  270. package/src/py/agent/mcp-connection/schema.d.ts +1 -0
  271. package/src/py/agent/mcp-connection/schema.json +5 -0
  272. package/src/py/agent/react-connection/__snapshots__/generator.spec.ts.snap +11 -19
  273. package/src/py/agent/react-connection/generator.d.ts +4 -4
  274. package/src/py/agent/react-connection/generator.js +55 -59
  275. package/src/py/agent/react-connection/generator.js.map +1 -1
  276. package/src/py/agent/react-connection/{serve-local.d.ts → local-dev.d.ts} +6 -6
  277. package/src/py/agent/react-connection/local-dev.js +36 -0
  278. package/src/py/agent/react-connection/local-dev.js.map +1 -0
  279. package/src/py/agent/react-connection/schema.d.js +8 -0
  280. package/src/py/agent/react-connection/schema.d.js.map +1 -0
  281. package/src/py/agent/react-connection/schema.d.ts +1 -0
  282. package/src/py/agent/react-connection/schema.json +5 -0
  283. package/src/py/agent/schema.d.js +6 -0
  284. package/src/py/agent/schema.d.js.map +1 -0
  285. package/src/py/agent/schema.d.ts +2 -1
  286. package/src/py/agent/schema.json +6 -1
  287. package/src/py/api/generator.d.ts +3 -3
  288. package/src/py/api/generator.js +12 -11
  289. package/src/py/api/generator.js.map +1 -1
  290. package/src/py/api/schema.d.js +6 -0
  291. package/src/py/api/schema.d.js.map +1 -0
  292. package/src/py/api/schema.d.ts +1 -0
  293. package/src/py/api/schema.json +5 -0
  294. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +1526 -0
  295. package/src/py/dynamodb/agent-connection/__snapshots__/generator.spec.ts.snap +45 -0
  296. package/src/py/dynamodb/agent-connection/generator.d.ts +10 -0
  297. package/src/py/dynamodb/agent-connection/generator.js +39 -0
  298. package/src/py/dynamodb/agent-connection/generator.js.map +1 -0
  299. package/src/py/dynamodb/agent-connection/schema.d.js +8 -0
  300. package/src/py/dynamodb/agent-connection/schema.d.js.map +1 -0
  301. package/src/py/dynamodb/agent-connection/schema.d.ts +15 -0
  302. package/src/py/dynamodb/agent-connection/schema.json +27 -0
  303. package/src/py/dynamodb/fast-api-connection/__snapshots__/generator.spec.ts.snap +23 -0
  304. package/src/py/dynamodb/fast-api-connection/generator.d.ts +10 -0
  305. package/src/py/dynamodb/fast-api-connection/generator.js +37 -0
  306. package/src/py/dynamodb/fast-api-connection/generator.js.map +1 -0
  307. package/src/py/dynamodb/fast-api-connection/schema.d.js +8 -0
  308. package/src/py/dynamodb/fast-api-connection/schema.d.js.map +1 -0
  309. package/src/py/dynamodb/fast-api-connection/schema.d.ts +13 -0
  310. package/src/py/dynamodb/fast-api-connection/schema.json +23 -0
  311. package/src/py/dynamodb/files/__name__/__init__.py.template +6 -0
  312. package/src/py/dynamodb/files/__name__/client.py.template +39 -0
  313. package/src/py/dynamodb/files/__name__/entities/__init__.py.template +4 -0
  314. package/src/py/dynamodb/files/__name__/entities/base.py.template +63 -0
  315. package/src/py/dynamodb/files/__name__/entities/example.py.template +64 -0
  316. package/src/py/dynamodb/files/config.json.template +24 -0
  317. package/src/py/dynamodb/generator.d.ts +10 -0
  318. package/src/py/dynamodb/generator.js +110 -0
  319. package/src/py/dynamodb/generator.js.map +1 -0
  320. package/src/py/dynamodb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +45 -0
  321. package/src/py/dynamodb/mcp-server-connection/generator.d.ts +10 -0
  322. package/src/py/dynamodb/mcp-server-connection/generator.js +39 -0
  323. package/src/py/dynamodb/mcp-server-connection/generator.js.map +1 -0
  324. package/src/py/dynamodb/mcp-server-connection/schema.d.js +8 -0
  325. package/src/py/dynamodb/mcp-server-connection/schema.d.js.map +1 -0
  326. package/src/py/dynamodb/mcp-server-connection/schema.d.ts +15 -0
  327. package/src/py/dynamodb/mcp-server-connection/schema.json +27 -0
  328. package/src/py/dynamodb/schema.d.js +6 -0
  329. package/src/py/dynamodb/schema.d.js.map +1 -0
  330. package/src/py/dynamodb/schema.d.ts +16 -0
  331. package/src/py/dynamodb/schema.json +75 -0
  332. package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +212 -4678
  333. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +5409 -0
  334. package/src/py/fast-api/files/app/__name__/init.py.template +5 -22
  335. package/src/py/fast-api/files/app/__name__/main.py.template +4 -1
  336. package/src/py/fast-api/generator.d.ts +3 -3
  337. package/src/py/fast-api/generator.js +90 -87
  338. package/src/py/fast-api/generator.js.map +1 -1
  339. package/src/py/fast-api/react/__snapshots__/generator.spec.ts.snap +4 -3
  340. package/src/py/fast-api/react/generator.d.ts +4 -4
  341. package/src/py/fast-api/react/generator.js +25 -25
  342. package/src/py/fast-api/react/generator.js.map +1 -1
  343. package/src/py/fast-api/react/open-api.d.ts +1 -1
  344. package/src/py/fast-api/react/open-api.js +31 -29
  345. package/src/py/fast-api/react/open-api.js.map +1 -1
  346. package/src/py/fast-api/react/schema.d.js +6 -0
  347. package/src/py/fast-api/react/schema.d.js.map +1 -0
  348. package/src/py/fast-api/react/schema.d.ts +1 -0
  349. package/src/py/fast-api/react/schema.json +5 -0
  350. package/src/py/fast-api/schema.d.js +6 -0
  351. package/src/py/fast-api/schema.d.js.map +1 -0
  352. package/src/py/fast-api/schema.d.ts +1 -0
  353. package/src/py/fast-api/schema.json +5 -0
  354. package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +4 -4
  355. package/src/py/lambda-function/generator.d.ts +3 -3
  356. package/src/py/lambda-function/generator.js +60 -59
  357. package/src/py/lambda-function/generator.js.map +1 -1
  358. package/src/py/lambda-function/schema.d.js +6 -0
  359. package/src/py/lambda-function/schema.d.js.map +1 -0
  360. package/src/py/lambda-function/schema.d.ts +1 -0
  361. package/src/py/lambda-function/schema.json +5 -0
  362. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +208 -19
  363. package/src/py/mcp-server/files/deploy/Dockerfile.template +1 -1
  364. package/src/py/mcp-server/generator.d.ts +3 -3
  365. package/src/py/mcp-server/generator.js +162 -124
  366. package/src/py/mcp-server/generator.js.map +1 -1
  367. package/src/py/mcp-server/schema.d.js +6 -0
  368. package/src/py/mcp-server/schema.d.js.map +1 -0
  369. package/src/py/mcp-server/schema.d.ts +1 -0
  370. package/src/py/mcp-server/schema.json +5 -0
  371. package/src/py/project/generator.d.ts +17 -4
  372. package/src/py/project/generator.js +205 -127
  373. package/src/py/project/generator.js.map +1 -1
  374. package/src/py/project/schema.d.js +6 -0
  375. package/src/py/project/schema.d.js.map +1 -0
  376. package/src/py/project/schema.d.ts +1 -0
  377. package/src/py/project/schema.json +5 -0
  378. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +2038 -0
  379. package/src/py/rdb/agent-connection/__snapshots__/generator.spec.ts.snap +104 -0
  380. package/src/py/rdb/agent-connection/generator.d.ts +10 -0
  381. package/src/py/rdb/agent-connection/generator.js +46 -0
  382. package/src/py/rdb/agent-connection/generator.js.map +1 -0
  383. package/src/py/rdb/agent-connection/schema.d.js +8 -0
  384. package/src/py/rdb/agent-connection/schema.d.js.map +1 -0
  385. package/src/py/rdb/agent-connection/schema.d.ts +15 -0
  386. package/src/py/rdb/agent-connection/schema.json +27 -0
  387. package/src/py/rdb/fast-api-connection/__snapshots__/generator.spec.ts.snap +44 -0
  388. package/src/py/rdb/fast-api-connection/files/__apiModuleName__/dependencies/__rdbNameSnake__.py.template +14 -0
  389. package/src/py/rdb/fast-api-connection/generator.d.ts +10 -0
  390. package/src/py/rdb/fast-api-connection/generator.js +54 -0
  391. package/src/py/rdb/fast-api-connection/generator.js.map +1 -0
  392. package/src/py/rdb/fast-api-connection/schema.d.js +8 -0
  393. package/src/py/rdb/fast-api-connection/schema.d.js.map +1 -0
  394. package/src/py/rdb/fast-api-connection/schema.d.ts +13 -0
  395. package/src/py/rdb/fast-api-connection/schema.json +23 -0
  396. package/src/py/rdb/files/Dockerfile.create-db-user.template +10 -0
  397. package/src/py/rdb/files/Dockerfile.migration.template +10 -0
  398. package/src/py/rdb/files/__name__/__init__.py.template +3 -0
  399. package/src/py/rdb/files/__name__/connection.py.template +55 -0
  400. package/src/py/rdb/files/__name__/create_db_user_handler.py.template +97 -0
  401. package/src/py/rdb/files/__name__/migration_handler.py.template +36 -0
  402. package/src/py/rdb/files/__name__/models/__init__.py.template +3 -0
  403. package/src/py/rdb/files/__name__/models/example.py.template +8 -0
  404. package/src/py/rdb/files/__name__/utils.py.template +104 -0
  405. package/src/py/rdb/files/alembic.ini.template +38 -0
  406. package/src/py/rdb/files/config.json.template +14 -0
  407. package/src/py/rdb/files/migrations/env.py.template +80 -0
  408. package/src/py/rdb/files/migrations/script.py.mako.template +28 -0
  409. package/src/py/rdb/generator.d.ts +6 -0
  410. package/src/py/rdb/generator.js +274 -0
  411. package/src/py/rdb/generator.js.map +1 -0
  412. package/src/py/rdb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +101 -0
  413. package/src/py/rdb/mcp-server-connection/generator.d.ts +10 -0
  414. package/src/py/rdb/mcp-server-connection/generator.js +46 -0
  415. package/src/py/rdb/mcp-server-connection/generator.js.map +1 -0
  416. package/src/py/rdb/mcp-server-connection/schema.d.js +8 -0
  417. package/src/py/rdb/mcp-server-connection/schema.d.js.map +1 -0
  418. package/src/py/rdb/mcp-server-connection/schema.d.ts +15 -0
  419. package/src/py/rdb/mcp-server-connection/schema.json +27 -0
  420. package/src/py/rdb/schema.d.js +6 -0
  421. package/src/py/rdb/schema.d.js.map +1 -0
  422. package/src/py/rdb/schema.d.ts +16 -0
  423. package/src/py/rdb/schema.json +77 -0
  424. package/src/py/rdb/utils.d.ts +6 -0
  425. package/src/py/rdb/utils.js +16 -0
  426. package/src/py/rdb/utils.js.map +1 -0
  427. package/src/sdk/agentcore-gateway.d.ts +6 -0
  428. package/src/sdk/agentcore-gateway.js +7 -0
  429. package/src/sdk/agentcore-gateway.js.map +1 -0
  430. package/src/sdk/connection.d.ts +6 -0
  431. package/src/sdk/connection.js +6 -0
  432. package/src/sdk/connection.js.map +1 -0
  433. package/src/sdk/license.d.ts +8 -0
  434. package/src/sdk/license.js +7 -0
  435. package/src/sdk/license.js.map +1 -0
  436. package/src/sdk/open-api.d.ts +10 -0
  437. package/src/sdk/open-api.js +8 -0
  438. package/src/sdk/open-api.js.map +1 -0
  439. package/src/sdk/py.d.ts +16 -0
  440. package/src/sdk/py.js +11 -0
  441. package/src/sdk/py.js.map +1 -0
  442. package/src/sdk/terraform.d.ts +6 -0
  443. package/src/sdk/terraform.js +7 -0
  444. package/src/sdk/terraform.js.map +1 -0
  445. package/src/sdk/ts.d.ts +33 -0
  446. package/src/sdk/ts.js +35 -0
  447. package/src/sdk/ts.js.map +1 -0
  448. package/{sdk → src/sdk}/utils/ast.d.ts +1 -2
  449. package/src/sdk/utils/ast.js +6 -0
  450. package/src/sdk/utils/ast.js.map +1 -0
  451. package/{sdk → src/sdk}/utils/format.d.ts +1 -1
  452. package/src/sdk/utils/format.js +6 -0
  453. package/src/sdk/utils/format.js.map +1 -0
  454. package/{sdk → src/sdk}/utils/test.d.ts +1 -1
  455. package/src/sdk/utils/test.js +6 -0
  456. package/src/sdk/utils/test.js.map +1 -0
  457. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +19 -24
  458. package/src/smithy/project/files/build.Dockerfile.template +1 -4
  459. package/src/smithy/project/files/src/operations/echo.smithy.template +1 -0
  460. package/src/smithy/project/generator.d.ts +3 -3
  461. package/src/smithy/project/generator.js +64 -57
  462. package/src/smithy/project/generator.js.map +1 -1
  463. package/src/smithy/project/schema.d.js +6 -0
  464. package/src/smithy/project/schema.d.js.map +1 -0
  465. package/src/smithy/project/schema.d.ts +1 -0
  466. package/src/smithy/project/schema.json +5 -0
  467. package/src/smithy/react-connection/__snapshots__/generator.spec.ts.snap +1 -1
  468. package/src/smithy/react-connection/generator.d.ts +3 -3
  469. package/src/smithy/react-connection/generator.js +39 -47
  470. package/src/smithy/react-connection/generator.js.map +1 -1
  471. package/src/smithy/react-connection/schema.d.js +6 -0
  472. package/src/smithy/react-connection/schema.d.js.map +1 -0
  473. package/src/smithy/react-connection/schema.d.ts +1 -0
  474. package/src/smithy/react-connection/schema.json +5 -0
  475. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +824 -120
  476. package/src/smithy/ts/api/files/handler.ts.template +2 -2
  477. package/src/smithy/ts/api/files/local-server.ts.template +2 -2
  478. package/src/smithy/ts/api/files/operations/echo.ts.template +2 -2
  479. package/src/smithy/ts/api/files/service.ts.template +3 -3
  480. package/src/smithy/ts/api/generator.d.ts +3 -3
  481. package/src/smithy/ts/api/generator.js +128 -105
  482. package/src/smithy/ts/api/generator.js.map +1 -1
  483. package/src/smithy/ts/api/schema.d.js +6 -0
  484. package/src/smithy/ts/api/schema.d.js.map +1 -0
  485. package/src/smithy/ts/api/schema.d.ts +1 -0
  486. package/src/smithy/ts/api/schema.json +5 -0
  487. package/src/terraform/project/files/application/src/main.tf.template +6 -1
  488. package/src/terraform/project/files/application/src/providers.tf.template +1 -1
  489. package/src/terraform/project/generator.d.ts +3 -3
  490. package/src/terraform/project/generator.js +156 -104
  491. package/src/terraform/project/generator.js.map +1 -1
  492. package/src/terraform/project/schema.d.js +9 -0
  493. package/src/terraform/project/schema.d.js.map +1 -0
  494. package/src/terraform/project/schema.d.ts +1 -0
  495. package/src/terraform/project/schema.json +5 -0
  496. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +1099 -134
  497. package/src/trpc/backend/files/src/client/index.ts.template +1 -1
  498. package/src/trpc/backend/files/src/handler.ts.template +1 -1
  499. package/src/trpc/backend/files/src/index.ts.template +5 -5
  500. package/src/trpc/backend/files/src/init.ts.template +1 -1
  501. package/src/trpc/backend/files/src/local-server.ts.template +1 -1
  502. package/src/trpc/backend/files/src/middleware/index.ts.template +7 -7
  503. package/src/trpc/backend/files/src/procedures/echo.ts.template +3 -3
  504. package/src/trpc/backend/files/src/router.ts.template +2 -2
  505. package/src/trpc/backend/files/src/schema/echo.ts.template +2 -2
  506. package/src/trpc/backend/files/src/schema/index.ts.template +1 -1
  507. package/src/trpc/backend/generator.d.ts +4 -4
  508. package/src/trpc/backend/generator.js +98 -84
  509. package/src/trpc/backend/generator.js.map +1 -1
  510. package/src/trpc/backend/schema.d.js +6 -0
  511. package/src/trpc/backend/schema.d.js.map +1 -0
  512. package/src/trpc/backend/schema.d.ts +3 -2
  513. package/src/trpc/backend/schema.json +5 -0
  514. package/src/trpc/react/__snapshots__/generator.spec.ts.snap +4 -4
  515. package/src/trpc/react/files/src/components/__apiNameClassName__ClientProvider.tsx.template +3 -3
  516. package/src/trpc/react/generator.d.ts +4 -4
  517. package/src/trpc/react/generator.js +63 -58
  518. package/src/trpc/react/generator.js.map +1 -1
  519. package/src/trpc/react/schema.d.js +6 -0
  520. package/src/trpc/react/schema.d.js.map +1 -0
  521. package/src/trpc/react/schema.d.ts +1 -0
  522. package/src/trpc/react/schema.json +5 -0
  523. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +781 -22
  524. package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +256 -0
  525. package/src/ts/agent/a2a-connection/files/agent-connection/app/__targetAgentKebabCase__-client-strands.ts.template +23 -0
  526. package/src/ts/agent/a2a-connection/generator.d.ts +3 -3
  527. package/src/ts/agent/a2a-connection/generator.js +64 -55
  528. package/src/ts/agent/a2a-connection/generator.js.map +1 -1
  529. package/src/ts/agent/a2a-connection/schema.d.js +8 -0
  530. package/src/ts/agent/a2a-connection/schema.d.js.map +1 -0
  531. package/src/ts/agent/a2a-connection/schema.d.ts +1 -0
  532. package/src/ts/agent/a2a-connection/schema.json +5 -0
  533. package/src/ts/agent/files/a2a/index.ts.template +1 -1
  534. package/src/ts/agent/files/ag-ui/index.ts.template +1 -1
  535. package/src/ts/agent/files/common/agent.ts.template +6 -2
  536. package/src/ts/agent/files/deploy/Dockerfile.template +4 -1
  537. package/src/ts/agent/files/http/client.ts.template +2 -2
  538. package/src/ts/agent/files/http/index.ts.template +2 -2
  539. package/src/ts/agent/files/http/router.ts.template +5 -5
  540. package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +220 -0
  541. package/src/ts/agent/gateway-connection/files/agent-connection/app/__gatewayKebabCase__-client-strands.ts.template +30 -0
  542. package/src/ts/agent/gateway-connection/generator.d.ts +10 -0
  543. package/src/ts/agent/gateway-connection/generator.js +116 -0
  544. package/src/ts/agent/gateway-connection/generator.js.map +1 -0
  545. package/src/ts/agent/gateway-connection/schema.d.js +6 -0
  546. package/src/ts/agent/gateway-connection/schema.d.js.map +1 -0
  547. package/src/ts/agent/gateway-connection/schema.d.ts +13 -0
  548. package/src/ts/agent/gateway-connection/schema.json +31 -0
  549. package/src/ts/agent/generator.d.ts +3 -3
  550. package/src/ts/agent/generator.js +203 -144
  551. package/src/ts/agent/generator.js.map +1 -1
  552. package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +192 -111
  553. package/src/ts/agent/mcp-connection/files/agent-connection/app/__mcpServerKebabCase__-client-strands.ts.template +22 -0
  554. package/src/ts/agent/mcp-connection/generator.d.ts +3 -3
  555. package/src/ts/agent/mcp-connection/generator.js +54 -59
  556. package/src/ts/agent/mcp-connection/generator.js.map +1 -1
  557. package/src/ts/agent/mcp-connection/schema.d.js +8 -0
  558. package/src/ts/agent/mcp-connection/schema.d.js.map +1 -0
  559. package/src/ts/agent/mcp-connection/schema.d.ts +1 -0
  560. package/src/ts/agent/mcp-connection/schema.json +5 -0
  561. package/src/ts/agent/react-connection/generator.d.ts +4 -4
  562. package/src/ts/agent/react-connection/generator.js +86 -80
  563. package/src/ts/agent/react-connection/generator.js.map +1 -1
  564. package/src/ts/agent/react-connection/local-dev.d.ts +13 -0
  565. package/src/ts/agent/react-connection/local-dev.js +17 -0
  566. package/src/ts/agent/react-connection/local-dev.js.map +1 -0
  567. package/src/ts/agent/react-connection/schema.d.js +8 -0
  568. package/src/ts/agent/react-connection/schema.d.js.map +1 -0
  569. package/src/ts/agent/react-connection/schema.d.ts +1 -0
  570. package/src/ts/agent/react-connection/schema.json +5 -0
  571. package/src/ts/agent/schema.d.js +6 -0
  572. package/src/ts/agent/schema.d.js.map +1 -0
  573. package/src/ts/agent/schema.d.ts +1 -0
  574. package/src/ts/agent/schema.json +5 -0
  575. package/src/ts/api/generator.d.ts +3 -3
  576. package/src/ts/api/generator.js +16 -16
  577. package/src/ts/api/generator.js.map +1 -1
  578. package/src/ts/api/schema.d.js +6 -0
  579. package/src/ts/api/schema.d.js.map +1 -0
  580. package/src/ts/api/schema.d.ts +3 -1
  581. package/src/ts/api/schema.json +5 -0
  582. package/src/ts/astro-docs/__snapshots__/generator.spec.ts.snap +15 -16
  583. package/src/ts/astro-docs/files/translation/scripts/translate.ts.template +3 -2
  584. package/src/ts/astro-docs/generator.d.ts +3 -3
  585. package/src/ts/astro-docs/generator.js +71 -54
  586. package/src/ts/astro-docs/generator.js.map +1 -1
  587. package/src/ts/astro-docs/schema.d.js +6 -0
  588. package/src/ts/astro-docs/schema.d.js.map +1 -0
  589. package/src/ts/astro-docs/schema.d.ts +2 -2
  590. package/src/ts/astro-docs/schema.json +3 -3
  591. package/src/ts/docs/generator.d.ts +3 -3
  592. package/src/ts/docs/generator.js +10 -10
  593. package/src/ts/docs/generator.js.map +1 -1
  594. package/src/ts/docs/schema.d.js +6 -0
  595. package/src/ts/docs/schema.d.js.map +1 -0
  596. package/src/ts/docs/schema.d.ts +1 -4
  597. package/src/ts/docs/schema.json +3 -3
  598. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +400 -512
  599. package/src/ts/dynamodb/agent-connection/__snapshots__/generator.spec.ts.snap +5 -5
  600. package/src/ts/dynamodb/agent-connection/generator.d.ts +3 -3
  601. package/src/ts/dynamodb/agent-connection/generator.js +21 -23
  602. package/src/ts/dynamodb/agent-connection/generator.js.map +1 -1
  603. package/src/ts/dynamodb/agent-connection/schema.d.js +8 -0
  604. package/src/ts/dynamodb/agent-connection/schema.d.js.map +1 -0
  605. package/src/ts/dynamodb/agent-connection/schema.d.ts +1 -0
  606. package/src/ts/dynamodb/agent-connection/schema.json +5 -0
  607. package/src/ts/dynamodb/files/config.json.template +24 -0
  608. package/src/ts/dynamodb/files/src/client.ts.template +30 -11
  609. package/src/ts/dynamodb/files/src/entities/example.ts.template +1 -1
  610. package/src/ts/dynamodb/files/src/entities/index.ts.template +1 -1
  611. package/src/ts/dynamodb/files/src/index.ts.template +2 -11
  612. package/src/ts/dynamodb/generator.d.ts +3 -3
  613. package/src/ts/dynamodb/generator.js +73 -63
  614. package/src/ts/dynamodb/generator.js.map +1 -1
  615. package/src/ts/dynamodb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +5 -5
  616. package/src/ts/dynamodb/mcp-server-connection/generator.d.ts +3 -3
  617. package/src/ts/dynamodb/mcp-server-connection/generator.js +21 -23
  618. package/src/ts/dynamodb/mcp-server-connection/generator.js.map +1 -1
  619. package/src/ts/dynamodb/mcp-server-connection/schema.d.js +8 -0
  620. package/src/ts/dynamodb/mcp-server-connection/schema.d.js.map +1 -0
  621. package/src/ts/dynamodb/mcp-server-connection/schema.d.ts +1 -0
  622. package/src/ts/dynamodb/mcp-server-connection/schema.json +5 -0
  623. package/src/ts/dynamodb/schema.d.js +6 -0
  624. package/src/ts/dynamodb/schema.d.js.map +1 -0
  625. package/src/ts/dynamodb/schema.d.ts +2 -0
  626. package/src/ts/dynamodb/schema.json +25 -2
  627. package/src/ts/dynamodb/smithy-connection/__snapshots__/generator.spec.ts.snap +3 -3
  628. package/src/ts/dynamodb/smithy-connection/generator.d.ts +3 -3
  629. package/src/ts/dynamodb/smithy-connection/generator.js +20 -22
  630. package/src/ts/dynamodb/smithy-connection/generator.js.map +1 -1
  631. package/src/ts/dynamodb/smithy-connection/schema.d.js +8 -0
  632. package/src/ts/dynamodb/smithy-connection/schema.d.js.map +1 -0
  633. package/src/ts/dynamodb/smithy-connection/schema.d.ts +1 -0
  634. package/src/ts/dynamodb/smithy-connection/schema.json +5 -0
  635. package/src/ts/dynamodb/trpc-connection/__snapshots__/generator.spec.ts.snap +3 -3
  636. package/src/ts/dynamodb/trpc-connection/generator.d.ts +3 -3
  637. package/src/ts/dynamodb/trpc-connection/generator.js +20 -22
  638. package/src/ts/dynamodb/trpc-connection/generator.js.map +1 -1
  639. package/src/ts/dynamodb/trpc-connection/schema.d.js +8 -0
  640. package/src/ts/dynamodb/trpc-connection/schema.d.js.map +1 -0
  641. package/src/ts/dynamodb/trpc-connection/schema.d.ts +1 -0
  642. package/src/ts/dynamodb/trpc-connection/schema.json +5 -0
  643. package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +4 -4
  644. package/src/ts/lambda-function/generator.d.ts +3 -3
  645. package/src/ts/lambda-function/generator.js +59 -56
  646. package/src/ts/lambda-function/generator.js.map +1 -1
  647. package/src/ts/lambda-function/io.js +83 -52
  648. package/src/ts/lambda-function/io.js.map +1 -1
  649. package/src/ts/lambda-function/schema.d.js +6 -0
  650. package/src/ts/lambda-function/schema.d.js.map +1 -0
  651. package/src/ts/lambda-function/schema.d.ts +1 -0
  652. package/src/ts/lambda-function/schema.json +5 -0
  653. package/src/ts/lib/__snapshots__/generator.spec.ts.snap +98 -93
  654. package/src/ts/lib/__snapshots__/vitest.spec.ts.snap +24 -0
  655. package/src/ts/lib/biome.d.ts +7 -0
  656. package/src/ts/lib/biome.js +91 -0
  657. package/src/ts/lib/biome.js.map +1 -0
  658. package/src/ts/lib/generator.d.ts +3 -3
  659. package/src/ts/lib/generator.js +107 -108
  660. package/src/ts/lib/generator.js.map +1 -1
  661. package/src/ts/lib/grit/vitest-pass-with-no-tests.grit +1 -4
  662. package/src/ts/lib/schema.d.js +6 -0
  663. package/src/ts/lib/schema.d.js.map +1 -0
  664. package/src/ts/lib/schema.d.ts +1 -1
  665. package/src/ts/lib/schema.json +5 -0
  666. package/src/ts/lib/ts-project-utils.d.ts +12 -2
  667. package/src/ts/lib/ts-project-utils.js +90 -67
  668. package/src/ts/lib/ts-project-utils.js.map +1 -1
  669. package/src/ts/lib/types.d.ts +6 -0
  670. package/src/ts/lib/types.js +5 -2
  671. package/src/ts/lib/types.js.map +1 -1
  672. package/src/ts/lib/vitest.d.ts +2 -2
  673. package/src/ts/lib/vitest.js +29 -26
  674. package/src/ts/lib/vitest.js.map +1 -1
  675. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +208 -42
  676. package/src/ts/mcp-server/files/Dockerfile.template +4 -1
  677. package/src/ts/mcp-server/generator.d.ts +3 -3
  678. package/src/ts/mcp-server/generator.js +181 -136
  679. package/src/ts/mcp-server/generator.js.map +1 -1
  680. package/src/ts/mcp-server/schema.d.js +6 -0
  681. package/src/ts/mcp-server/schema.d.js.map +1 -0
  682. package/src/ts/mcp-server/schema.d.ts +1 -0
  683. package/src/ts/mcp-server/schema.json +5 -0
  684. package/src/ts/nx-generator/__snapshots__/generator.spec.ts.snap +46 -26
  685. package/src/ts/nx-generator/files/common/schema.d.ts.template +1 -0
  686. package/src/ts/nx-generator/files/common/schema.json.template +5 -0
  687. package/src/ts/nx-generator/files/local/generator.ts.template +3 -3
  688. package/src/ts/nx-generator/files/nx-plugin-for-aws/generator/generator.ts.template +6 -7
  689. package/src/ts/nx-generator/generator.d.ts +2 -2
  690. package/src/ts/nx-generator/generator.js +113 -73
  691. package/src/ts/nx-generator/generator.js.map +1 -1
  692. package/src/ts/nx-generator/schema.d.js +6 -0
  693. package/src/ts/nx-generator/schema.d.js.map +1 -0
  694. package/src/ts/nx-generator/schema.d.ts +1 -0
  695. package/src/ts/nx-generator/schema.json +5 -0
  696. package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +30 -18
  697. package/src/ts/nx-plugin/files/mcp-server/server.ts.template +5 -5
  698. package/src/ts/nx-plugin/files/mcp-server/tools/create-workspace-command.ts.template +2 -2
  699. package/src/ts/nx-plugin/files/mcp-server/tools/general-guidance.ts.template +1 -1
  700. package/src/ts/nx-plugin/files/mcp-server/tools/generator-guide.ts.template +2 -2
  701. package/src/ts/nx-plugin/files/mcp-server/tools/list-generators.ts.template +2 -2
  702. package/src/ts/nx-plugin/files/mcp-server/utils.ts.template +3 -3
  703. package/src/ts/nx-plugin/generator.d.ts +3 -3
  704. package/src/ts/nx-plugin/generator.js +61 -50
  705. package/src/ts/nx-plugin/generator.js.map +1 -1
  706. package/src/ts/nx-plugin/schema.d.js +9 -0
  707. package/src/ts/nx-plugin/schema.d.js.map +1 -0
  708. package/src/ts/nx-plugin/schema.json +5 -0
  709. package/src/ts/nx-plugin/utils.d.ts +1 -1
  710. package/src/ts/nx-plugin/utils.js +36 -39
  711. package/src/ts/nx-plugin/utils.js.map +1 -1
  712. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +455 -646
  713. package/src/ts/rdb/agent-connection/__snapshots__/generator.spec.ts.snap +6 -6
  714. package/src/ts/rdb/agent-connection/generator.d.ts +3 -3
  715. package/src/ts/rdb/agent-connection/generator.js +38 -39
  716. package/src/ts/rdb/agent-connection/generator.js.map +1 -1
  717. package/src/ts/rdb/agent-connection/schema.d.js +8 -0
  718. package/src/ts/rdb/agent-connection/schema.d.js.map +1 -0
  719. package/src/ts/rdb/agent-connection/schema.d.ts +1 -0
  720. package/src/ts/rdb/agent-connection/schema.json +5 -0
  721. package/src/ts/rdb/files/Dockerfile.template +8 -1
  722. package/src/ts/rdb/files/config.json.template +14 -0
  723. package/src/ts/rdb/files/prisma.config.ts.template +6 -5
  724. package/src/ts/rdb/files/src/create-db-user-handler.ts.template +9 -11
  725. package/src/ts/rdb/files/src/index.ts.template +1 -2
  726. package/src/ts/rdb/files/src/migration-handler.ts.template +2 -29
  727. package/src/ts/rdb/files/src/prisma.ts.template +33 -25
  728. package/src/ts/rdb/files/src/utils.ts.template +3 -0
  729. package/src/ts/rdb/generator.d.ts +3 -7
  730. package/src/ts/rdb/generator.js +173 -131
  731. package/src/ts/rdb/generator.js.map +1 -1
  732. package/src/ts/rdb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +6 -6
  733. package/src/ts/rdb/mcp-server-connection/generator.d.ts +3 -3
  734. package/src/ts/rdb/mcp-server-connection/generator.js +36 -37
  735. package/src/ts/rdb/mcp-server-connection/generator.js.map +1 -1
  736. package/src/ts/rdb/mcp-server-connection/schema.d.js +8 -0
  737. package/src/ts/rdb/mcp-server-connection/schema.d.js.map +1 -0
  738. package/src/ts/rdb/mcp-server-connection/schema.d.ts +1 -0
  739. package/src/ts/rdb/mcp-server-connection/schema.json +5 -0
  740. package/src/ts/rdb/schema.d.js +6 -0
  741. package/src/ts/rdb/schema.d.js.map +1 -0
  742. package/src/ts/rdb/schema.d.ts +1 -0
  743. package/src/ts/rdb/schema.json +6 -1
  744. package/src/ts/rdb/smithy-connection/__snapshots__/generator.spec.ts.snap +3 -3
  745. package/src/ts/rdb/smithy-connection/generator.d.ts +3 -3
  746. package/src/ts/rdb/smithy-connection/generator.js +46 -43
  747. package/src/ts/rdb/smithy-connection/generator.js.map +1 -1
  748. package/src/ts/rdb/smithy-connection/schema.d.js +8 -0
  749. package/src/ts/rdb/smithy-connection/schema.d.js.map +1 -0
  750. package/src/ts/rdb/smithy-connection/schema.d.ts +1 -0
  751. package/src/ts/rdb/smithy-connection/schema.json +5 -0
  752. package/src/ts/rdb/trpc-connection/__snapshots__/generator.spec.ts.snap +3 -3
  753. package/src/ts/rdb/trpc-connection/generator.d.ts +3 -3
  754. package/src/ts/rdb/trpc-connection/generator.js +36 -31
  755. package/src/ts/rdb/trpc-connection/generator.js.map +1 -1
  756. package/src/ts/rdb/trpc-connection/schema.d.js +8 -0
  757. package/src/ts/rdb/trpc-connection/schema.d.js.map +1 -0
  758. package/src/ts/rdb/trpc-connection/schema.d.ts +1 -0
  759. package/src/ts/rdb/trpc-connection/schema.json +5 -0
  760. package/src/ts/rdb/utils.d.ts +1 -1
  761. package/src/ts/rdb/utils.js +9 -11
  762. package/src/ts/rdb/utils.js.map +1 -1
  763. package/src/ts/react-website/agui/files/common/src/hooks/useAgui__agentNameClassName__.tsx.template +1 -16
  764. package/src/ts/react-website/agui/generator.d.ts +1 -1
  765. package/src/ts/react-website/agui/generator.js +69 -62
  766. package/src/ts/react-website/agui/generator.js.map +1 -1
  767. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +1190 -799
  768. package/src/ts/react-website/app/generator.d.ts +4 -4
  769. package/src/ts/react-website/app/generator.js +217 -192
  770. package/src/ts/react-website/app/generator.js.map +1 -1
  771. package/src/ts/react-website/app/schema.d.js +6 -0
  772. package/src/ts/react-website/app/schema.d.js.map +1 -0
  773. package/src/ts/react-website/app/schema.d.ts +1 -1
  774. package/src/ts/react-website/app/schema.json +11 -6
  775. package/src/ts/react-website/cognito-auth/__snapshots__/generator.spec.ts.snap +129 -18
  776. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +36 -10
  777. package/src/ts/react-website/cognito-auth/__snapshots__/generator.ux-provider.spec.ts.snap +0 -20
  778. package/src/ts/react-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +2 -2
  779. package/src/ts/react-website/cognito-auth/generator.d.ts +4 -4
  780. package/src/ts/react-website/cognito-auth/generator.js +64 -63
  781. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  782. package/src/ts/react-website/cognito-auth/grit/cloudscape-auth-menu.grit +8 -6
  783. package/src/ts/react-website/cognito-auth/grit/cognito-auth-wrapper.grit +1 -1
  784. package/src/ts/react-website/cognito-auth/grit/none-auth-menu.grit +1 -0
  785. package/src/ts/react-website/cognito-auth/grit/shadcn-auth-menu.grit +3 -1
  786. package/src/ts/react-website/cognito-auth/grit/shadcn-state-declarations.grit +3 -1
  787. package/src/ts/react-website/cognito-auth/schema.d.js +6 -0
  788. package/src/ts/react-website/cognito-auth/schema.d.js.map +1 -0
  789. package/src/ts/react-website/cognito-auth/schema.d.ts +1 -0
  790. package/src/ts/react-website/cognito-auth/schema.json +5 -0
  791. package/src/ts/react-website/cognito-auth/utils.d.ts +1 -1
  792. package/src/ts/react-website/cognito-auth/utils.js +34 -32
  793. package/src/ts/react-website/cognito-auth/utils.js.map +1 -1
  794. package/src/ts/react-website/runtime-config/__snapshots__/generator.spec.ts.snap +2 -2
  795. package/src/ts/react-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +2 -2
  796. package/src/ts/react-website/runtime-config/generator.d.ts +3 -3
  797. package/src/ts/react-website/runtime-config/generator.js +29 -31
  798. package/src/ts/react-website/runtime-config/generator.js.map +1 -1
  799. package/src/ts/react-website/runtime-config/schema.d.js +6 -0
  800. package/src/ts/react-website/runtime-config/schema.d.js.map +1 -0
  801. package/src/ts/react-website/runtime-config/schema.d.ts +1 -0
  802. package/src/ts/react-website/runtime-config/schema.json +5 -0
  803. package/src/ts/sync/generator.d.ts +3 -3
  804. package/src/ts/sync/generator.js +58 -59
  805. package/src/ts/sync/generator.js.map +1 -1
  806. package/src/ts/website/app/generator.d.ts +3 -3
  807. package/src/ts/website/app/generator.js +10 -10
  808. package/src/ts/website/app/generator.js.map +1 -1
  809. package/src/ts/website/app/schema.d.js +6 -0
  810. package/src/ts/website/app/schema.d.js.map +1 -0
  811. package/src/ts/website/app/schema.d.ts +1 -1
  812. package/src/ts/website/app/schema.json +11 -6
  813. package/src/ts/website/auth/generator.d.ts +4 -4
  814. package/src/ts/website/auth/generator.js +11 -10
  815. package/src/ts/website/auth/generator.js.map +1 -1
  816. package/src/ts/website/auth/schema.d.js +6 -0
  817. package/src/ts/website/auth/schema.d.js.map +1 -0
  818. package/src/ts/website/auth/schema.d.ts +1 -0
  819. package/src/ts/website/auth/schema.json +5 -0
  820. package/src/utils/agent-chat/agent-chat.d.ts +31 -0
  821. package/src/utils/agent-chat/agent-chat.js +31 -0
  822. package/src/utils/agent-chat/agent-chat.js.map +1 -0
  823. package/src/utils/agent-chat/files/a2a/chat.ts.template +33 -0
  824. package/src/utils/agent-chat/files/ag-ui/chat.ts.template +17 -0
  825. package/src/utils/agent-chat/files/common/agentcore.ts.template +81 -0
  826. package/src/utils/agent-chat/files/http-py/chat.ts.template +43 -0
  827. package/src/utils/agent-chat/files/http-ts/chat.ts.template +54 -0
  828. package/src/utils/agent-connection/agent-connection.d.ts +117 -25
  829. package/src/utils/agent-connection/agent-connection.js +414 -103
  830. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  831. package/src/utils/agent-connection/files/core-a2a/agentcore-a2a-client-config.ts.template +93 -0
  832. package/src/utils/agent-connection/files/core-auth/agentcore-endpoints.ts.template +37 -0
  833. package/src/utils/agent-connection/files/core-auth/agentcore-fetch.ts.template +54 -0
  834. package/src/utils/agent-connection/files/core-gateway/agentcore-gateway-mcp-transport.ts.template +41 -0
  835. package/src/utils/agent-connection/files/core-mcp/agentcore-mcp-transport.ts.template +70 -0
  836. package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +22 -32
  837. package/src/utils/agent-connection/files/core-shared/agentcore-transport.ts.template +39 -0
  838. package/src/utils/agent-connection/files/core-strands/a2a/agentcore-a2a-client-strands.ts.template +61 -0
  839. package/src/utils/agent-connection/files/core-strands/base/model-errors-strands.ts.template +36 -0
  840. package/src/utils/agent-connection/files/{core-runtime-config/with-session-id.ts.template → core-strands/base/with-session-id-strands.ts.template} +1 -1
  841. package/src/utils/agent-connection/files/core-strands/gateway/agentcore-gateway-mcp-client-strands.ts.template +26 -0
  842. package/src/utils/agent-connection/files/core-strands/mcp/agentcore-mcp-client-strands.ts.template +27 -0
  843. package/src/utils/agent-connection/files/py-core-a2a/agentcore_a2a_client_config.py.template +43 -0
  844. package/src/utils/agent-connection/files/py-core-auth/agentcore_endpoints.py.template +47 -0
  845. package/src/utils/agent-connection/files/py-core-auth/auth/session.py.template +51 -0
  846. package/src/utils/agent-connection/files/py-core-gateway/agentcore_gateway_mcp_transport.py.template +28 -0
  847. package/src/utils/agent-connection/files/py-core-langchain/a2a/agentcore_a2a_client_langchain.py.template +99 -0
  848. package/src/utils/agent-connection/files/py-core-langchain/gateway/agentcore_gateway_mcp_client_langchain.py.template +57 -0
  849. package/src/utils/agent-connection/files/py-core-langchain/mcp/agentcore_mcp_client_langchain.py.template +64 -0
  850. package/src/utils/agent-connection/files/py-core-mcp/agentcore_mcp_transport.py.template +34 -0
  851. package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +5 -18
  852. package/src/utils/agent-connection/files/py-core-shared/agentcore_transport.py.template +40 -0
  853. package/src/utils/agent-connection/files/py-core-strands/a2a/agentcore_a2a_client_strands.py.template +66 -0
  854. package/src/utils/agent-connection/files/py-core-strands/base/model_errors_strands.py.template +40 -0
  855. package/src/utils/agent-connection/files/py-core-strands/gateway/agentcore_gateway_mcp_client_strands.py.template +22 -0
  856. package/src/utils/agent-connection/files/py-core-strands/mcp/agentcore_mcp_client_strands.py.template +30 -0
  857. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +11 -3
  858. package/src/utils/agent-core-constructs/agent-core-constructs.js +93 -38
  859. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  860. package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +31 -4
  861. package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +50 -0
  862. package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +487 -0
  863. package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/readiness-probe/index.js.template +55 -0
  864. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +32 -0
  865. package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +449 -0
  866. package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/render-cedar.cjs.template +13 -0
  867. package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +151 -13
  868. package/src/utils/agent-core-constructs/files/terraform/core/agentcore-gateway/gateway.tf.template +14 -0
  869. package/src/utils/api-constructs/api-constructs.d.ts +2 -2
  870. package/src/utils/api-constructs/api-constructs.js +36 -31
  871. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  872. package/src/utils/api-constructs/files/cdk/app/apis/http/__apiNameKebabCase__.ts.template +8 -8
  873. package/src/utils/api-constructs/files/cdk/app/apis/rest/__apiNameKebabCase__.ts.template +11 -8
  874. package/src/utils/api-constructs/files/cdk/core/api/http/http-api.ts.template +26 -9
  875. package/src/utils/api-constructs/files/cdk/core/api/rest/api-gateway-account/index.js.template +70 -0
  876. package/src/utils/api-constructs/files/cdk/core/api/rest/api-gateway-account.ts.template +82 -0
  877. package/src/utils/api-constructs/files/cdk/core/api/rest/rest-api.ts.template +54 -18
  878. package/src/utils/api-constructs/files/cdk/core/api/trpc/trpc-utils.ts.template +1 -1
  879. package/src/utils/api-constructs/files/cdk/core/api/utils/utils.ts.template +61 -7
  880. package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +101 -12
  881. package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +194 -8
  882. package/src/utils/api-constructs/files/terraform/core/api/http/http-api/http-api.tf.template +1 -1
  883. package/src/utils/api-constructs/files/terraform/core/api/rest/api-gateway-account/api-gateway-account.tf.template +83 -0
  884. package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +5 -11
  885. package/src/utils/api-constructs/open-api-metadata.d.ts +2 -2
  886. package/src/utils/api-constructs/open-api-metadata.js +22 -22
  887. package/src/utils/api-constructs/open-api-metadata.js.map +1 -1
  888. package/src/utils/ast/website.d.ts +5 -1
  889. package/src/utils/ast/website.js +18 -20
  890. package/src/utils/ast/website.js.map +1 -1
  891. package/src/utils/ast.d.ts +33 -1
  892. package/src/utils/ast.js +146 -70
  893. package/src/utils/ast.js.map +1 -1
  894. package/src/utils/base-tsconfig.d.ts +30 -0
  895. package/src/utils/base-tsconfig.js +32 -0
  896. package/src/utils/base-tsconfig.js.map +1 -0
  897. package/src/utils/bundle/bundle.d.ts +1 -1
  898. package/src/utils/bundle/bundle.js +50 -47
  899. package/src/utils/bundle/bundle.js.map +1 -1
  900. package/src/utils/commands.d.ts +10 -3
  901. package/src/utils/commands.js +60 -26
  902. package/src/utils/commands.js.map +1 -1
  903. package/src/utils/config/index.d.ts +5 -5
  904. package/src/utils/config/index.js +5 -4
  905. package/src/utils/config/index.js.map +1 -1
  906. package/src/utils/config/utils.d.ts +13 -3
  907. package/src/utils/config/utils.js +65 -43
  908. package/src/utils/config/utils.js.map +1 -1
  909. package/src/utils/connection/open-api/files/components/__apiNameClassName__Provider.tsx.template +1 -1
  910. package/src/utils/connection/open-api/react.d.ts +6 -6
  911. package/src/utils/connection/open-api/react.js +81 -77
  912. package/src/utils/connection/open-api/react.js.map +1 -1
  913. package/src/utils/containers.d.ts +1 -1
  914. package/src/utils/containers.js +22 -23
  915. package/src/utils/containers.js.map +1 -1
  916. package/src/utils/docker.d.ts +44 -0
  917. package/src/utils/docker.js +81 -0
  918. package/src/utils/docker.js.map +1 -0
  919. package/src/utils/dynamodb-constructs/dynamodb-constructs.d.ts +3 -3
  920. package/src/utils/dynamodb-constructs/dynamodb-constructs.js +39 -41
  921. package/src/utils/dynamodb-constructs/dynamodb-constructs.js.map +1 -1
  922. package/src/utils/dynamodb-constructs/files/cdk/app/dynamodb/__nameKebabCase__.ts.template +18 -5
  923. package/src/utils/dynamodb-constructs/files/cdk/core/dynamodb.ts.template +1 -1
  924. package/src/utils/dynamodb-constructs/files/terraform/app/dynamodb/__nameKebabCase__/__nameKebabCase__.tf.template +24 -17
  925. package/src/utils/dynamodb-constructs/files/terraform/core/dynamodb/dynamodb.tf.template +1 -1
  926. package/src/utils/files/common/constructs/src/core/index.ts.template +4 -4
  927. package/src/utils/files/common/constructs/src/index.ts.template +2 -2
  928. package/src/utils/files/common/infra-config/src/index.ts.template +3 -3
  929. package/src/utils/files/common/infra-config/src/resolve-stage.ts.template +2 -2
  930. package/src/utils/files/common/infra-config/src/stages.config.ts.template +1 -1
  931. package/src/{ts/dynamodb/files/scripts → utils/files/common/scripts/src/dynamodb}/create-local-table.ts.template +65 -31
  932. package/src/utils/files/common/scripts/src/dynamodb/pull-image.ts.template +13 -0
  933. package/src/utils/files/common/scripts/src/dynamodb/start-container.ts.template +106 -0
  934. package/src/utils/files/common/scripts/src/infra/infra-deploy.ts.template +2 -0
  935. package/src/utils/files/common/scripts/src/infra/infra-destroy.ts.template +2 -0
  936. package/src/utils/files/common/scripts/src/{stage-credentials → infra/stage-credentials}/cdk-command.ts.template +6 -3
  937. package/src/utils/files/common/scripts/src/{stage-credentials → infra/stage-credentials}/run.ts.template +3 -3
  938. package/src/utils/files/common/scripts/src/rdb/mysql/wait-for-mysql-db.ts.template +32 -0
  939. package/src/utils/files/common/scripts/src/rdb/postgres/wait-for-postgres-db.ts.template +32 -0
  940. package/src/utils/files/common/scripts/src/rdb/shared/pull-image.ts.template +16 -0
  941. package/src/utils/files/common/scripts/src/rdb/shared/start-container.ts.template +117 -0
  942. package/src/utils/files/common/shadcn/src/index.ts.template +2 -2
  943. package/src/utils/files/terraform/src/core/asset-bucket/asset-bucket.tf.template +63 -72
  944. package/src/utils/files/terraform/src/core/runtime-config/appconfig/appconfig.tf.template +1 -1
  945. package/src/utils/files/terraform/src/core/runtime-config/appconfig-deployment/appconfig-deployment.tf.template +12 -6
  946. package/src/utils/files/terraform/src/core/runtime-config/entry/entry.tf.template +1 -1
  947. package/src/utils/files/terraform/src/core/runtime-config/read/read.tf.template +9 -4
  948. package/src/utils/files/website/hooks/sigv4/useSigV4.tsx.template +1 -1
  949. package/src/utils/format.d.ts +45 -2
  950. package/src/utils/format.js +332 -81
  951. package/src/utils/format.js.map +1 -1
  952. package/src/utils/fs.d.ts +1 -1
  953. package/src/utils/fs.js +14 -13
  954. package/src/utils/fs.js.map +1 -1
  955. package/src/utils/function-constructs/files/cdk/app/lambda-functions/__nameKebabCase__.ts.template +1 -1
  956. package/src/utils/function-constructs/files/terraform/app/lambda-functions/__nameKebabCase__/__nameKebabCase__.tf.template +2 -2
  957. package/src/utils/function-constructs/function-constructs.d.ts +2 -2
  958. package/src/utils/function-constructs/function-constructs.js +22 -25
  959. package/src/utils/function-constructs/function-constructs.js.map +1 -1
  960. package/src/utils/generators.d.ts +4 -0
  961. package/src/utils/generators.js +18 -20
  962. package/src/utils/generators.js.map +1 -1
  963. package/src/utils/git.d.ts +1 -1
  964. package/src/utils/git.js +19 -34
  965. package/src/utils/git.js.map +1 -1
  966. package/src/utils/iac-providers.js +5 -5
  967. package/src/utils/iac-providers.js.map +1 -1
  968. package/src/utils/iac.d.ts +1 -1
  969. package/src/utils/iac.js +12 -14
  970. package/src/utils/iac.js.map +1 -1
  971. package/src/utils/identity-constructs/files/cdk/core/user-identity.ts.template +125 -16
  972. package/src/utils/identity-constructs/files/terraform/core/user-identity/add-callback-url/add-callback-url.tf.template +28 -9
  973. package/src/utils/identity-constructs/files/terraform/core/user-identity/identity/identity.tf.template +106 -6
  974. package/src/utils/identity-constructs/files/terraform/core/user-identity/main.tf.template +7 -0
  975. package/src/utils/identity-constructs/identity-constructs.d.ts +2 -2
  976. package/src/utils/identity-constructs/identity-constructs.js +28 -28
  977. package/src/utils/identity-constructs/identity-constructs.js.map +1 -1
  978. package/src/utils/init.d.ts +53 -0
  979. package/src/utils/init.js +252 -0
  980. package/src/utils/init.js.map +1 -0
  981. package/src/utils/install.d.ts +32 -0
  982. package/src/utils/install.js +56 -0
  983. package/src/utils/install.js.map +1 -0
  984. package/src/utils/js.d.ts +4 -0
  985. package/src/utils/js.js +27 -20
  986. package/src/utils/js.js.map +1 -1
  987. package/src/utils/mcp.d.ts +1 -1
  988. package/src/utils/mcp.js +34 -41
  989. package/src/utils/mcp.js.map +1 -1
  990. package/src/utils/metrics.d.ts +9 -3
  991. package/src/utils/metrics.js +61 -46
  992. package/src/utils/metrics.js.map +1 -1
  993. package/src/utils/mock-project-graph.js +8 -12
  994. package/src/utils/mock-project-graph.js.map +1 -1
  995. package/src/utils/module-format.d.ts +28 -0
  996. package/src/utils/module-format.js +28 -0
  997. package/src/utils/module-format.js.map +1 -0
  998. package/src/utils/names.d.ts +22 -0
  999. package/src/utils/names.js +44 -48
  1000. package/src/utils/names.js.map +1 -1
  1001. package/src/utils/npm-scope.d.ts +1 -1
  1002. package/src/utils/npm-scope.js +9 -17
  1003. package/src/utils/npm-scope.js.map +1 -1
  1004. package/src/utils/nx.d.ts +39 -4
  1005. package/src/utils/nx.js +169 -75
  1006. package/src/utils/nx.js.map +1 -1
  1007. package/src/utils/nxlv-python.d.ts +1 -1
  1008. package/src/utils/nxlv-python.js +27 -15
  1009. package/src/utils/nxlv-python.js.map +1 -1
  1010. package/src/utils/object.js +5 -11
  1011. package/src/utils/object.js.map +1 -1
  1012. package/src/utils/paths.d.ts +1 -1
  1013. package/src/utils/paths.js +11 -15
  1014. package/src/utils/paths.js.map +1 -1
  1015. package/src/utils/pkg-manager.js +4 -9
  1016. package/src/utils/pkg-manager.js.map +1 -1
  1017. package/src/utils/pnpm-workspace.d.ts +1 -1
  1018. package/src/utils/pnpm-workspace.js +22 -22
  1019. package/src/utils/pnpm-workspace.js.map +1 -1
  1020. package/src/utils/port.d.ts +29 -7
  1021. package/src/utils/port.js +67 -28
  1022. package/src/utils/port.js.map +1 -1
  1023. package/src/utils/py.d.ts +16 -3
  1024. package/src/utils/py.js +72 -47
  1025. package/src/utils/py.js.map +1 -1
  1026. package/src/utils/rdb-constructs/files/cdk/app/dbs/__nameKebabCase__.ts.template +72 -18
  1027. package/src/utils/rdb-constructs/files/cdk/core/rdb/aurora.ts.template +97 -88
  1028. package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +127 -53
  1029. package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +36 -48
  1030. package/src/utils/rdb-constructs/rdb-constructs.d.ts +16 -5
  1031. package/src/utils/rdb-constructs/rdb-constructs.js +38 -41
  1032. package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -1
  1033. package/src/utils/shared-constructs-constants.d.ts +1 -0
  1034. package/src/utils/shared-constructs-constants.js +16 -15
  1035. package/src/utils/shared-constructs-constants.js.map +1 -1
  1036. package/src/utils/shared-constructs.d.ts +2 -2
  1037. package/src/utils/shared-constructs.js +60 -67
  1038. package/src/utils/shared-constructs.js.map +1 -1
  1039. package/src/utils/shared-dynamodb-scripts.d.ts +11 -0
  1040. package/src/utils/shared-dynamodb-scripts.js +25 -0
  1041. package/src/utils/shared-dynamodb-scripts.js.map +1 -0
  1042. package/src/utils/shared-infra-config.d.ts +1 -1
  1043. package/src/utils/shared-infra-config.js +31 -30
  1044. package/src/utils/shared-infra-config.js.map +1 -1
  1045. package/src/utils/shared-infra-scripts.d.ts +11 -0
  1046. package/src/utils/shared-infra-scripts.js +42 -0
  1047. package/src/utils/shared-infra-scripts.js.map +1 -0
  1048. package/src/utils/shared-rdb-scripts.d.ts +16 -0
  1049. package/src/utils/shared-rdb-scripts.js +32 -0
  1050. package/src/utils/shared-rdb-scripts.js.map +1 -0
  1051. package/src/utils/shared-scripts.d.ts +2 -5
  1052. package/src/utils/shared-scripts.js +12 -38
  1053. package/src/utils/shared-scripts.js.map +1 -1
  1054. package/src/utils/shared-shadcn.d.ts +1 -1
  1055. package/src/utils/shared-shadcn.js +65 -71
  1056. package/src/utils/shared-shadcn.js.map +1 -1
  1057. package/src/utils/test.d.ts +15 -1
  1058. package/src/utils/test.js +41 -23
  1059. package/src/utils/test.js.map +1 -1
  1060. package/src/utils/toml.d.ts +1 -1
  1061. package/src/utils/toml.js +10 -14
  1062. package/src/utils/toml.js.map +1 -1
  1063. package/src/utils/versions.d.ts +150 -97
  1064. package/src/utils/versions.js +157 -115
  1065. package/src/utils/versions.js.map +1 -1
  1066. package/src/utils/warm-ruff-cache.d.ts +12 -0
  1067. package/src/utils/warm-ruff-cache.js +39 -0
  1068. package/src/utils/warm-ruff-cache.js.map +1 -0
  1069. package/src/utils/website-constructs/files/cdk/app/static-websites/__websiteNameKebabCase__.ts.template +2 -2
  1070. package/src/utils/website-constructs/files/cdk/core/static-website.ts.template +200 -41
  1071. package/src/utils/website-constructs/files/terraform/app/static-websites/__websiteNameKebabCase__/__websiteNameKebabCase__.tf.template +1 -1
  1072. package/src/utils/website-constructs/files/terraform/core/static-website/static-website.tf.template +145 -93
  1073. package/src/utils/website-constructs/website-constructs.d.ts +2 -2
  1074. package/src/utils/website-constructs/website-constructs.js +38 -30
  1075. package/src/utils/website-constructs/website-constructs.js.map +1 -1
  1076. package/bin/aws-nx-mcp.js +0 -17
  1077. package/bin/aws-nx-mcp.js.map +0 -1
  1078. package/sdk/connection.d.ts +0 -6
  1079. package/sdk/connection.js +0 -10
  1080. package/sdk/connection.js.map +0 -1
  1081. package/sdk/open-api.d.ts +0 -10
  1082. package/sdk/open-api.js +0 -15
  1083. package/sdk/open-api.js.map +0 -1
  1084. package/sdk/py.d.ts +0 -14
  1085. package/sdk/py.js +0 -18
  1086. package/sdk/py.js.map +0 -1
  1087. package/sdk/terraform.d.ts +0 -6
  1088. package/sdk/terraform.js +0 -11
  1089. package/sdk/terraform.js.map +0 -1
  1090. package/sdk/ts.d.ts +0 -29
  1091. package/sdk/ts.js +0 -47
  1092. package/sdk/ts.js.map +0 -1
  1093. package/sdk/utils/ast.js +0 -12
  1094. package/sdk/utils/ast.js.map +0 -1
  1095. package/sdk/utils/format.js +0 -10
  1096. package/sdk/utils/format.js.map +0 -1
  1097. package/sdk/utils/test.js +0 -10
  1098. package/sdk/utils/test.js.map +0 -1
  1099. package/src/connection/agent-serve-local.js +0 -48
  1100. package/src/connection/agent-serve-local.js.map +0 -1
  1101. package/src/connection/serve-local.d.ts +0 -15
  1102. package/src/connection/serve-local.js +0 -41
  1103. package/src/connection/serve-local.js.map +0 -1
  1104. package/src/py/agent/a2a-connection/files/agent-connection/app/__targetAgentSnakeCase___client.py.template +0 -22
  1105. package/src/py/agent/mcp-connection/files/agent-connection/app/__mcpServerSnakeCase___client.py.template +0 -22
  1106. package/src/py/agent/react-connection/serve-local.js +0 -30
  1107. package/src/py/agent/react-connection/serve-local.js.map +0 -1
  1108. package/src/py/agent/scripts/http/chat.ts.template +0 -38
  1109. package/src/ts/agent/a2a-connection/files/agent-connection/app/__targetAgentKebabCase__-client.ts.template +0 -19
  1110. package/src/ts/agent/mcp-connection/files/agent-connection/app/__mcpServerKebabCase__-client.ts.template +0 -19
  1111. package/src/ts/agent/react-connection/serve-local.d.ts +0 -13
  1112. package/src/ts/agent/react-connection/serve-local.js +0 -19
  1113. package/src/ts/agent/react-connection/serve-local.js.map +0 -1
  1114. package/src/ts/agent/scripts/http/chat.ts.template +0 -35
  1115. package/src/ts/dynamodb/files/scripts/pull-image.ts.template +0 -15
  1116. package/src/ts/dynamodb/files/scripts/start-container.ts.template +0 -81
  1117. package/src/ts/dynamodb/files/src/constants.ts.template +0 -9
  1118. package/src/ts/dynamodb/files/src/gsi.ts.template +0 -14
  1119. package/src/ts/lib/eslint.d.ts +0 -14
  1120. package/src/ts/lib/eslint.js +0 -90
  1121. package/src/ts/lib/eslint.js.map +0 -1
  1122. package/src/ts/lib/grit/eslint-dependency-checks-warn.grit +0 -1
  1123. package/src/ts/rdb/files/scripts/docker-pull.ts.template +0 -15
  1124. package/src/ts/rdb/files/scripts/docker-start.ts.template +0 -84
  1125. package/src/ts/rdb/files/scripts/wait-for-db.ts.template +0 -55
  1126. package/src/ts/rdb/files/src/constants.ts.template +0 -8
  1127. package/src/utils/agent-connection/files/core-a2a/agentcore-a2a-client.ts.template +0 -123
  1128. package/src/utils/agent-connection/files/core-mcp/agentcore-mcp-client.ts.template +0 -128
  1129. package/src/utils/agent-connection/files/py-core-a2a/agentcore_a2a_client.py.template +0 -120
  1130. package/src/utils/agent-connection/files/py-core-mcp/agentcore_mcp_client.py.template +0 -89
  1131. package/src/utils/files/common/scripts/src/infra-deploy.ts.template +0 -2
  1132. package/src/utils/files/common/scripts/src/infra-destroy.ts.template +0 -2
  1133. package/src/utils/files/terraform/scripts/reset-runtime-config.ts.template +0 -25
  1134. /package/{bin → src/bin}/aws-nx-mcp.d.ts +0 -0
  1135. /package/src/utils/agent-connection/files/{py-core-runtime-config/with_session_id.py.template → py-core-strands/base/with_session_id_strands.py.template} +0 -0
  1136. /package/src/utils/files/common/scripts/src/{index.ts.template → infra/index.ts.template} +0 -0
  1137. /package/src/utils/files/common/scripts/src/{stage-credentials → infra/stage-credentials}/credentials.ts.template +0 -0
  1138. /package/src/utils/files/common/scripts/src/{stage-credentials → infra/stage-credentials}/stage-parser.ts.template +0 -0
@@ -32,7 +32,7 @@ export default defineConfig(() => ({
32
32
  // plugins: [],
33
33
  // },
34
34
  build: {
35
- outDir: '../dist/test-app',
35
+ outDir: '../dist/test-app/bundle',
36
36
  emptyOutDir: true,
37
37
  reportCompressedSize: true,
38
38
  commonjsOptions: {
@@ -40,6 +40,7 @@ export default defineConfig(() => ({
40
40
  },
41
41
  },
42
42
  test: {
43
+ passWithNoTests: true,
43
44
  name: '@proj/test-app',
44
45
  watch: false,
45
46
  globals: true,
@@ -50,7 +51,6 @@ export default defineConfig(() => ({
50
51
  reportsDirectory: './test-output/vitest/coverage',
51
52
  provider: 'v8' as const,
52
53
  },
53
- passWithNoTests: true,
54
54
  },
55
55
  resolve: { tsconfigPaths: true },
56
56
  define: { global: {} },
@@ -88,7 +88,7 @@ export default defineConfig(() => ({
88
88
  // plugins: [],
89
89
  // },
90
90
  build: {
91
- outDir: '../dist/test-app',
91
+ outDir: '../dist/test-app/bundle',
92
92
  emptyOutDir: true,
93
93
  reportCompressedSize: true,
94
94
  commonjsOptions: {
@@ -96,6 +96,7 @@ export default defineConfig(() => ({
96
96
  },
97
97
  },
98
98
  test: {
99
+ passWithNoTests: true,
99
100
  name: '@proj/test-app',
100
101
  watch: false,
101
102
  globals: true,
@@ -106,7 +107,6 @@ export default defineConfig(() => ({
106
107
  reportsDirectory: './test-output/vitest/coverage',
107
108
  provider: 'v8' as const,
108
109
  },
109
- passWithNoTests: true,
110
110
  },
111
111
  resolve: { tsconfigPaths: true },
112
112
  define: { global: {} },
@@ -131,12 +131,12 @@ exports[`react-website generator > TailwindCSS integration > terraform iac > sho
131
131
  required_providers {
132
132
  aws = {
133
133
  source = "hashicorp/aws"
134
- version = "~> 6.0"
134
+ version = "6.54.0"
135
135
  configuration_aliases = [aws.us_east_1]
136
136
  }
137
137
  random = {
138
138
  source = "hashicorp/random"
139
- version = "~> 3.1"
139
+ version = "3.9.0"
140
140
  }
141
141
  }
142
142
  }
@@ -152,6 +152,31 @@ variable "website_file_path" {
152
152
  type = string
153
153
  }
154
154
 
155
+ variable "custom_domain_names" {
156
+ description = "Custom domain names (aliases) for the CloudFront distribution. Requires acm_certificate_arn."
157
+ type = list(string)
158
+ default = []
159
+ }
160
+
161
+ variable "acm_certificate_arn" {
162
+ description = "ARN of an ACM certificate (in us-east-1) for the custom domain names. When set, viewers are required to use TLS 1.2 or later."
163
+ type = string
164
+ default = null
165
+ }
166
+
167
+ # Content-Security-Policy enforced on all responses. Restricts scripts and
168
+ # framing to mitigate XSS and clickjacking, while permitting HTTPS/WSS calls
169
+ # (connect-src) to AWS service endpoints such as API Gateway, Cognito and
170
+ # Bedrock AgentCore which are only known at deploy time. Edit this to tighten
171
+ # connect-src to your specific origins once they are known.
172
+ locals {
173
+ content_security_policy = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https: wss:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'"
174
+
175
+ # Delivery source/destination names have a 60 character maximum. Truncate the
176
+ # website name so the longest delivery name stays within the limit.
177
+ access_logs_name_prefix = substr(lower(var.website_name), 0, 16)
178
+ }
179
+
155
180
 
156
181
  # Data sources
157
182
  data "aws_caller_identity" "current" {}
@@ -188,6 +213,26 @@ resource "aws_kms_key" "website_key" {
188
213
  ]
189
214
  Resource = "*"
190
215
  },
216
+ {
217
+ Sid = "AllowCloudWatchLogs"
218
+ Effect = "Allow"
219
+ Principal = {
220
+ Service = "logs.\${data.aws_region.current.region}.amazonaws.com"
221
+ }
222
+ Action = [
223
+ "kms:Encrypt",
224
+ "kms:Decrypt",
225
+ "kms:ReEncrypt*",
226
+ "kms:GenerateDataKey*",
227
+ "kms:DescribeKey"
228
+ ]
229
+ Resource = "*"
230
+ Condition = {
231
+ ArnLike = {
232
+ "kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:*"
233
+ }
234
+ }
235
+ },
191
236
  {
192
237
  Sid = "AllowCloudFrontServicePrincipalSSE-KMS"
193
238
  Effect = "Allow"
@@ -219,18 +264,12 @@ resource "aws_kms_alias" "website_key_alias" {
219
264
  target_key_id = aws_kms_key.website_key.key_id
220
265
  }
221
266
 
222
- # Access Logs Bucket
223
- resource "aws_s3_bucket" "access_logs" {
224
- #checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for access logs bucket
225
- #checkov:skip=CKV_AWS_144:Cross-region replication not required for access logs
226
- #checkov:skip=CKV2_AWS_62:Event notifications not required for access logs bucket
227
- #checkov:skip=CKV_AWS_21:Versioning disabled for access logs to reduce storage costs
228
- bucket = "\${lower(var.website_name)}-access-logs-\${random_id.bucket_suffix.hex}"
229
- force_destroy = true
230
-
231
- tags = {
232
- Name = "\${lower(var.website_name)}-access-logs"
233
- }
267
+ # CloudWatch log group receiving S3 server access logs for the website and
268
+ # distribution log buckets.
269
+ resource "aws_cloudwatch_log_group" "access_logs" {
270
+ name = "/aws/s3/\${lower(var.website_name)}-access-logs-\${random_id.bucket_suffix.hex}"
271
+ retention_in_days = 365
272
+ kms_key_id = aws_kms_key.website_key.arn
234
273
  }
235
274
 
236
275
  resource "random_id" "unique_suffix" {
@@ -241,63 +280,12 @@ resource "random_id" "bucket_suffix" {
241
280
  byte_length = 8
242
281
  }
243
282
 
244
- resource "aws_s3_bucket_versioning" "access_logs_versioning" {
245
- bucket = aws_s3_bucket.access_logs.id
246
- versioning_configuration {
247
- status = "Disabled"
248
- }
249
- }
250
-
251
- resource "aws_s3_bucket_server_side_encryption_configuration" "access_logs_encryption" {
252
- bucket = aws_s3_bucket.access_logs.id
253
-
254
- rule {
255
- apply_server_side_encryption_by_default {
256
- kms_master_key_id = aws_kms_key.website_key.arn
257
- sse_algorithm = "aws:kms"
258
- }
259
- }
260
- }
261
-
262
- resource "aws_s3_bucket_public_access_block" "access_logs_pab" {
263
- bucket = aws_s3_bucket.access_logs.id
264
-
265
- block_public_acls = true
266
- block_public_policy = true
267
- ignore_public_acls = true
268
- restrict_public_buckets = true
269
- }
270
-
271
- resource "aws_s3_bucket_policy" "access_logs_ssl_policy" {
272
- bucket = aws_s3_bucket.access_logs.id
273
-
274
- policy = jsonencode({
275
- Version = "2012-10-17"
276
- Statement = [
277
- {
278
- Sid = "DenyInsecureConnections"
279
- Effect = "Deny"
280
- Principal = "*"
281
- Action = "s3:*"
282
- Resource = [
283
- aws_s3_bucket.access_logs.arn,
284
- "\${aws_s3_bucket.access_logs.arn}/*"
285
- ]
286
- Condition = {
287
- Bool = {
288
- "aws:SecureTransport" = "false"
289
- }
290
- }
291
- }
292
- ]
293
- })
294
- }
295
-
296
283
  # Website Bucket
297
284
  resource "aws_s3_bucket" "website" {
298
285
  #checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for static website content
299
286
  #checkov:skip=CKV_AWS_144:Cross-region replication not required for static website
300
287
  #checkov:skip=CKV2_AWS_62:Event notifications not required for static website bucket
288
+ #checkov:skip=CKV_AWS_18:Server access logs are delivered to CloudWatch Logs (see aws_cloudwatch_log_delivery.website)
301
289
  bucket = "\${lower(var.website_name)}-website-\${random_id.bucket_suffix.hex}"
302
290
  force_destroy = true
303
291
 
@@ -341,20 +329,35 @@ resource "aws_s3_bucket_ownership_controls" "website_ownership" {
341
329
  }
342
330
  }
343
331
 
344
- resource "aws_s3_bucket_logging" "website_logging" {
345
- bucket = aws_s3_bucket.website.id
332
+ # Deliver the website bucket's server access logs to CloudWatch Logs.
333
+ resource "aws_cloudwatch_log_delivery_source" "website" {
334
+ name = "\${local.access_logs_name_prefix}-website-logs-\${random_id.bucket_suffix.hex}"
335
+ log_type = "S3_SERVER_ACCESS_LOGS"
336
+ resource_arn = aws_s3_bucket.website.arn
337
+ }
338
+
339
+ resource "aws_cloudwatch_log_delivery_destination" "access_logs" {
340
+ name = "\${local.access_logs_name_prefix}-access-logs-\${random_id.bucket_suffix.hex}"
346
341
 
347
- target_bucket = aws_s3_bucket.access_logs.id
348
- target_prefix = "website-access-logs/"
342
+ delivery_destination_configuration {
343
+ destination_resource_arn = aws_cloudwatch_log_group.access_logs.arn
344
+ }
345
+ }
346
+
347
+ resource "aws_cloudwatch_log_delivery" "website" {
348
+ delivery_source_name = aws_cloudwatch_log_delivery_source.website.name
349
+ delivery_destination_arn = aws_cloudwatch_log_delivery_destination.access_logs.arn
349
350
  }
350
351
 
351
352
 
352
- # Distribution Log Bucket
353
+ # Distribution Log Bucket — holds CloudFront standard access logs (CloudFront
354
+ # delivers only to S3). Its own S3 server access logs go to CloudWatch Logs.
353
355
  resource "aws_s3_bucket" "distribution_logs" {
354
356
  #checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for CloudFront logs
355
357
  #checkov:skip=CKV_AWS_144:Cross-region replication not required for CloudFront logs
356
358
  #checkov:skip=CKV2_AWS_62:Event notifications not required for CloudFront logs bucket
357
359
  #checkov:skip=CKV_AWS_21:Versioning not required for CloudFront access logs
360
+ #checkov:skip=CKV_AWS_18:Server access logs are delivered to CloudWatch Logs (see aws_cloudwatch_log_delivery.distribution_logs)
358
361
  bucket = "\${lower(var.website_name)}-distribution-logs-\${random_id.bucket_suffix.hex}"
359
362
  force_destroy = true
360
363
 
@@ -400,11 +403,16 @@ resource "aws_s3_bucket_acl" "distribution_logs_acl" {
400
403
  depends_on = [aws_s3_bucket_ownership_controls.distribution_logs_ownership]
401
404
  }
402
405
 
403
- resource "aws_s3_bucket_logging" "distribution_logs_logging" {
404
- bucket = aws_s3_bucket.distribution_logs.id
406
+ # Deliver the distribution log bucket's server access logs to CloudWatch Logs.
407
+ resource "aws_cloudwatch_log_delivery_source" "distribution_logs" {
408
+ name = "\${local.access_logs_name_prefix}-distribution-logs-\${random_id.bucket_suffix.hex}"
409
+ log_type = "S3_SERVER_ACCESS_LOGS"
410
+ resource_arn = aws_s3_bucket.distribution_logs.arn
411
+ }
405
412
 
406
- target_bucket = aws_s3_bucket.access_logs.id
407
- target_prefix = "distribution-access-logs/"
413
+ resource "aws_cloudwatch_log_delivery" "distribution_logs" {
414
+ delivery_source_name = aws_cloudwatch_log_delivery_source.distribution_logs.name
415
+ delivery_destination_arn = aws_cloudwatch_log_delivery_destination.access_logs.arn
408
416
  }
409
417
 
410
418
  resource "aws_s3_bucket_policy" "distribution_logs_ssl_policy" {
@@ -512,13 +520,42 @@ resource "aws_cloudfront_origin_access_control" "website_oac" {
512
520
  signing_protocol = "sigv4"
513
521
  }
514
522
 
523
+ # Security headers applied to all responses.
524
+ resource "aws_cloudfront_response_headers_policy" "website" {
525
+ name = "\${aws_s3_bucket.website.bucket}-security-headers"
526
+
527
+ security_headers_config {
528
+ strict_transport_security {
529
+ access_control_max_age_sec = 63072000
530
+ include_subdomains = true
531
+ preload = true
532
+ override = true
533
+ }
534
+ content_type_options {
535
+ override = true
536
+ }
537
+ frame_options {
538
+ frame_option = "DENY"
539
+ override = true
540
+ }
541
+ referrer_policy {
542
+ referrer_policy = "strict-origin-when-cross-origin"
543
+ override = true
544
+ }
545
+ content_security_policy {
546
+ content_security_policy = local.content_security_policy
547
+ override = true
548
+ }
549
+ }
550
+ }
551
+
515
552
  # CloudFront Distribution
516
553
  resource "aws_cloudfront_distribution" "website" {
554
+ # See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
517
555
  #checkov:skip=CKV_AWS_174:Using CloudFront default certificate which does not support TLS v1.2
518
556
  #checkov:skip=CKV_AWS_310:Origin failover not required for single S3 origin static website
519
557
  #checkov:skip=CKV_AWS_374:Geo restrictions not required for global web application
520
558
  #checkov:skip=CKV2_AWS_42:Custom SSL certificate not required for development - using CloudFront default
521
- #checkov:skip=CKV2_AWS_32:Response headers policy not required for basic static website
522
559
  #checkov:skip=CKV2_AWS_47:WAF includes AWSManagedRulesKnownBadInputsRuleSet which provides Log4j protection
523
560
  origin {
524
561
  domain_name = aws_s3_bucket.website.bucket_regional_domain_name
@@ -530,6 +567,7 @@ resource "aws_cloudfront_distribution" "website" {
530
567
  is_ipv6_enabled = true
531
568
  default_root_object = "index.html"
532
569
  web_acl_id = aws_wafv2_web_acl.cloudfront_waf.arn
570
+ aliases = var.custom_domain_names
533
571
 
534
572
  logging_config {
535
573
  include_cookies = false
@@ -548,11 +586,12 @@ resource "aws_cloudfront_distribution" "website" {
548
586
  }
549
587
  }
550
588
 
551
- viewer_protocol_policy = "redirect-to-https"
552
- min_ttl = 0
553
- default_ttl = 3600
554
- max_ttl = 86400
555
- compress = true
589
+ viewer_protocol_policy = "redirect-to-https"
590
+ response_headers_policy_id = aws_cloudfront_response_headers_policy.website.id
591
+ min_ttl = 0
592
+ default_ttl = 3600
593
+ max_ttl = 86400
594
+ compress = true
556
595
  }
557
596
 
558
597
  # Custom error responses for SPA routing
@@ -575,7 +614,10 @@ resource "aws_cloudfront_distribution" "website" {
575
614
  }
576
615
 
577
616
  viewer_certificate {
578
- cloudfront_default_certificate = true
617
+ cloudfront_default_certificate = var.acm_certificate_arn == null
618
+ acm_certificate_arn = var.acm_certificate_arn
619
+ ssl_support_method = var.acm_certificate_arn == null ? null : "sni-only"
620
+ minimum_protocol_version = var.acm_certificate_arn == null ? "TLSv1" : "TLSv1.2_2021"
579
621
  }
580
622
 
581
623
  tags = {
@@ -656,8 +698,8 @@ resource "null_resource" "upload_website_files" {
656
698
 
657
699
  provisioner "local-exec" {
658
700
  command = <<-EOT
659
- cd "\${path.root}"
660
- uv run --with boto3 python3 -c "
701
+ cd "$ROOT_PATH"
702
+ uv run --with boto3==1.43.46 python3 -c "
661
703
  import os
662
704
  import sys
663
705
  import boto3
@@ -745,9 +787,14 @@ def sync_to_s3(local_path, bucket_name):
745
787
  sys.exit(1)
746
788
 
747
789
  # Execute sync
748
- sync_to_s3('\${var.website_file_path}', '\${aws_s3_bucket.website.bucket}')
790
+ sync_to_s3(os.environ['WEBSITE_FILE_PATH'], os.environ['BUCKET_NAME'])
749
791
  "
750
792
  EOT
793
+ environment = {
794
+ ROOT_PATH = path.root
795
+ WEBSITE_FILE_PATH = var.website_file_path
796
+ BUCKET_NAME = aws_s3_bucket.website.bucket
797
+ }
751
798
  }
752
799
 
753
800
  depends_on = [aws_s3_bucket_policy.website_cloudfront_policy]
@@ -755,11 +802,12 @@ sync_to_s3('\${var.website_file_path}', '\${aws_s3_bucket.website.bucket}')
755
802
 
756
803
  # Upload runtime config file
757
804
  resource "aws_s3_object" "runtime_config" {
758
- bucket = aws_s3_bucket.website.id
759
- key = "runtime-config.json"
760
- content = module.runtime_config_reader.config_json
761
- content_type = "application/json"
762
- etag = md5(module.runtime_config_reader.config_json)
805
+ bucket = aws_s3_bucket.website.id
806
+ key = "runtime-config.json"
807
+ content = module.runtime_config_reader.config_json
808
+ content_type = "application/json"
809
+ cache_control = "no-cache"
810
+ etag = md5(module.runtime_config_reader.config_json)
763
811
 
764
812
  depends_on = [null_resource.upload_website_files]
765
813
  }
@@ -774,8 +822,9 @@ resource "null_resource" "cloudfront_invalidation" {
774
822
 
775
823
  provisioner "local-exec" {
776
824
  command = <<-EOT
777
- uv run --with boto3 python3 -c "
825
+ uv run --with boto3==1.43.46 python3 -c "
778
826
  import boto3
827
+ import os
779
828
  import sys
780
829
  from botocore.exceptions import ClientError, NoCredentialsError
781
830
 
@@ -797,7 +846,7 @@ def create_invalidation(distribution_id):
797
846
 
798
847
  invalidation_id = response['Invalidation']['Id']
799
848
  print(f'CloudFront cache invalidation created: {invalidation_id}')
800
- print(f'Distribution: \${aws_cloudfront_distribution.website.id}')
849
+ print(f'Distribution: {distribution_id}')
801
850
  print(f'Status: {response[\\"Invalidation\\"][\\"Status\\"]}')
802
851
 
803
852
  except NoCredentialsError:
@@ -811,9 +860,12 @@ def create_invalidation(distribution_id):
811
860
  sys.exit(1)
812
861
 
813
862
  # Execute invalidation
814
- create_invalidation('\${aws_cloudfront_distribution.website.id}')
863
+ create_invalidation(os.environ['DISTRIBUTION_ID'])
815
864
  "
816
865
  EOT
866
+ environment = {
867
+ DISTRIBUTION_ID = aws_cloudfront_distribution.website.id
868
+ }
817
869
  }
818
870
 
819
871
  depends_on = [
@@ -856,7 +908,7 @@ output "waf_web_acl_arn" {
856
908
  required_providers {
857
909
  aws = {
858
910
  source = "hashicorp/aws"
859
- version = "~> 6.0"
911
+ version = "6.54.0"
860
912
  configuration_aliases = [aws.us_east_1]
861
913
  }
862
914
  }
@@ -905,61 +957,63 @@ vitest.config.*.timestamp*
905
957
  runtime-config.json"
906
958
  `;
907
959
 
908
- exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > .prettierrc 1`] = `
909
- "{ "singleQuote": true }
910
- "
911
- `;
960
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > .prettierrc 1`] = `"{"singleQuote":true}"`;
912
961
 
913
- exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > eslint.config.mjs 1`] = `
914
- "import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
915
- import nx from '@nx/eslint-plugin';
916
-
917
- export default [
918
- eslintPluginPrettierRecommended,
919
- ...nx.configs['flat/base'],
920
- ...nx.configs['flat/typescript'],
921
- ...nx.configs['flat/javascript'],
922
- {
923
- ignores: [
924
- '**/dist',
925
- '**/out-tsc',
926
- '**/vite.config.*.timestamp*',
927
- '**/vitest.config.*.timestamp*',
928
- ],
962
+ exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > biome.json 1`] = `
963
+ "{
964
+ "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
965
+ "root": true,
966
+ "formatter": {
967
+ "enabled": true,
968
+ "indentStyle": "space",
969
+ "indentWidth": 2,
970
+ "lineWidth": 80
929
971
  },
930
- {
931
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
932
- rules: {
933
- '@nx/enforce-module-boundaries': [
934
- 'error',
935
- {
936
- enforceBuildableLibDependency: true,
937
- allow: ['^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?[jt]s$'],
938
- depConstraints: [
939
- {
940
- sourceTag: '*',
941
- onlyDependOnLibsWithTags: ['*'],
942
- },
943
- ],
944
- },
945
- ],
972
+ "javascript": {
973
+ "formatter": {
974
+ "quoteStyle": "single",
975
+ "trailingCommas": "all"
976
+ }
977
+ },
978
+ "css": {
979
+ "formatter": {
980
+ "quoteStyle": "single"
946
981
  },
982
+ "linter": {
983
+ "enabled": false
984
+ }
947
985
  },
948
- {
949
- files: [
950
- '**/*.ts',
951
- '**/*.tsx',
952
- '**/*.cts',
953
- '**/*.mts',
954
- '**/*.js',
955
- '**/*.jsx',
956
- '**/*.cjs',
957
- '**/*.mjs',
958
- ],
959
- // Override or add rules here
960
- rules: {},
986
+ "linter": {
987
+ "enabled": true,
988
+ "rules": {
989
+ "recommended": false,
990
+ "correctness": {
991
+ "noUndeclaredDependencies": "warn"
992
+ }
993
+ }
961
994
  },
962
- ];
995
+ "assist": {
996
+ "actions": {
997
+ "source": {
998
+ "organizeImports": "on"
999
+ }
1000
+ }
1001
+ },
1002
+ "files": {
1003
+ "includes": [
1004
+ "**",
1005
+ "!**/dist",
1006
+ "!**/out-tsc",
1007
+ "!**/node_modules",
1008
+ "!**/.nx",
1009
+ "!**/.venv",
1010
+ "!**/*.css",
1011
+ "!**/*.gen.*",
1012
+ "!**/generated/**",
1013
+ "!**/tsconfig*.json"
1014
+ ]
1015
+ }
1016
+ }
963
1017
  "
964
1018
  `;
965
1019
 
@@ -971,52 +1025,72 @@ exports[`react-website generator > Tanstack router integration > should generate
971
1025
  "targetDefaults": {
972
1026
  "build": {
973
1027
  "cache": true,
974
- "dependsOn": ["^build"],
975
1028
  "inputs": ["default"]
976
1029
  },
977
1030
  "lint": {
978
1031
  "cache": true
979
1032
  },
980
- "@nx/eslint:lint": {
981
- "cache": true,
982
- "inputs": [
983
- "default",
984
- "^default",
985
- "{workspaceRoot}/.eslintrc.json",
986
- "{workspaceRoot}/.eslintignore",
987
- "{workspaceRoot}/eslint.config.mjs",
988
- "{workspaceRoot}/tools/eslint-rules/**/*"
989
- ]
990
- },
991
- "@nx/vite:build": {
992
- "cache": true,
1033
+ "test": {
993
1034
  "dependsOn": ["^build"],
994
- "inputs": ["default", "^default"]
1035
+ "inputs": ["default"]
995
1036
  },
996
1037
  "@nx/vitest:test": {
997
1038
  "cache": true,
998
- "inputs": ["default", "^default"],
1039
+ "inputs": ["default", "^production"],
999
1040
  "configurations": {
1000
1041
  "update-snapshot": {
1001
1042
  "args": "--update"
1002
1043
  }
1003
1044
  }
1004
1045
  },
1005
- "test": {
1006
- "dependsOn": ["^build"],
1007
- "inputs": ["default"]
1008
- },
1009
1046
  "compile": {
1010
1047
  "cache": true,
1011
1048
  "inputs": ["default"]
1012
1049
  }
1013
1050
  },
1051
+ "plugins": [
1052
+ {
1053
+ "plugin": "@nx/js/typescript",
1054
+ "options": {
1055
+ "typecheck": {
1056
+ "targetName": "typecheck"
1057
+ },
1058
+ "build": {
1059
+ "targetName": "compile",
1060
+ "configName": "tsconfig.lib.json",
1061
+ "buildDepsName": "build-deps",
1062
+ "watchDepsName": "watch-deps"
1063
+ }
1064
+ }
1065
+ },
1066
+ {
1067
+ "plugin": "@nx/vite/plugin",
1068
+ "options": {
1069
+ "buildTargetName": "bundle",
1070
+ "serveTargetName": "serve",
1071
+ "devTargetName": "serve",
1072
+ "previewTargetName": "preview",
1073
+ "serveStaticTargetName": "serve-static",
1074
+ "typecheckTargetName": "vite:typecheck",
1075
+ "buildDepsTargetName": "build-deps",
1076
+ "watchDepsTargetName": "watch-deps"
1077
+ }
1078
+ },
1079
+ {
1080
+ "plugin": "@nx/vitest",
1081
+ "options": {
1082
+ "testTargetName": "test",
1083
+ "ciTargetName": "test-ci",
1084
+ "testMode": "watch"
1085
+ }
1086
+ }
1087
+ ],
1014
1088
  "generators": {
1015
1089
  "@nx/react": {
1016
1090
  "application": {
1017
1091
  "babel": true,
1018
1092
  "style": "css",
1019
- "linter": "eslint",
1093
+ "linter": "none",
1020
1094
  "bundler": "vite"
1021
1095
  },
1022
1096
  "component": {
@@ -1024,39 +1098,19 @@ exports[`react-website generator > Tanstack router integration > should generate
1024
1098
  },
1025
1099
  "library": {
1026
1100
  "style": "css",
1027
- "linter": "eslint"
1101
+ "linter": "none"
1028
1102
  }
1029
1103
  }
1030
1104
  },
1031
1105
  "namedInputs": {
1032
- "eslint": [
1033
- "default",
1034
- "{workspaceRoot}/eslint.config.mjs",
1035
- "{projectRoot}/eslint.config.mjs"
1036
- ],
1106
+ "biome": ["default", "{workspaceRoot}/biome.json"],
1037
1107
  "default": [
1038
1108
  {
1039
1109
  "dependentTasksOutputFiles": "**/*",
1040
1110
  "transitive": true
1041
1111
  }
1042
1112
  ]
1043
- },
1044
- "plugins": [
1045
- {
1046
- "plugin": "@nx/js/typescript",
1047
- "options": {
1048
- "typecheck": {
1049
- "targetName": "typecheck"
1050
- },
1051
- "build": {
1052
- "targetName": "compile",
1053
- "configName": "tsconfig.lib.json",
1054
- "buildDepsName": "build-deps",
1055
- "watchDepsName": "watch-deps"
1056
- }
1057
- }
1058
- }
1059
- ]
1113
+ }
1060
1114
  }
1061
1115
  "
1062
1116
  `;
@@ -1065,57 +1119,38 @@ exports[`react-website generator > Tanstack router integration > should generate
1065
1119
  "{
1066
1120
  "name": "@proj/source",
1067
1121
  "dependencies": {
1068
- "@cloudscape-design/board-components": "3.0.187",
1069
- "@cloudscape-design/components": "3.0.1304",
1070
- "@cloudscape-design/global-styles": "1.0.59",
1071
- "aws-cdk-lib": "2.257.0",
1122
+ "@cloudscape-design/board-components": "3.0.201",
1123
+ "@cloudscape-design/components": "3.0.1325",
1124
+ "@cloudscape-design/global-styles": "1.0.62",
1125
+ "aws-cdk-lib": "2.261.0",
1072
1126
  "constructs": "10.6.0",
1073
1127
  "react": "19.2.7",
1074
1128
  "react-dom": "19.2.7",
1075
- "tailwindcss": "4.3.0"
1129
+ "tailwindcss": "4.3.2"
1076
1130
  },
1077
1131
  "devDependencies": {
1078
- "@eslint/js": "^9.8.0",
1079
- "@nx/eslint": "22.7.5",
1080
- "@nx/eslint-plugin": "22.7.5",
1081
- "@nx/js": "22.7.5",
1082
- "@nx/react": "22.7.5",
1083
- "@nx/vite": "22.7.5",
1084
- "@nx/vitest": "22.7.5",
1085
- "@nx/web": "22.7.5",
1086
- "@swc-node/register": "~1.11.1",
1087
- "@swc/cli": "~0.8.0",
1088
- "@swc/core": "~1.15.5",
1132
+ "@nx/js": "23.1.0",
1133
+ "@nx/react": "23.1.0",
1134
+ "@nx/vite": "23.1.0",
1135
+ "@nx/vitest": "23.1.0",
1136
+ "@nx/web": "23.1.0",
1089
1137
  "@swc/helpers": "~0.5.18",
1090
- "@tailwindcss/vite": "4.3.0",
1138
+ "@tailwindcss/vite": "4.3.2",
1091
1139
  "@testing-library/dom": "10.4.0",
1092
1140
  "@testing-library/react": "16.3.0",
1093
- "@types/node": "25.9.1",
1141
+ "@types/node": "26.1.1",
1094
1142
  "@types/react": "^19.0.0",
1095
1143
  "@types/react-dom": "^19.0.0",
1096
1144
  "@vitejs/plugin-react": "^6.0.0",
1097
- "@vitest/coverage-v8": "4.1.7",
1098
- "@vitest/ui": "4.1.7",
1099
- "eslint": "^9.8.0",
1100
- "eslint-config-prettier": "^10.0.0",
1101
- "eslint-plugin-import": "2.31.0",
1102
- "eslint-plugin-jsx-a11y": "6.10.1",
1103
- "eslint-plugin-prettier": "5.5.6",
1104
- "eslint-plugin-react": "7.35.0",
1105
- "eslint-plugin-react-hooks": "5.0.0",
1145
+ "@vitest/coverage-v8": "4.1.10",
1146
+ "@vitest/ui": "4.1.10",
1106
1147
  "jiti": "2.4.2",
1107
- "jsdom": "~22.1.0",
1108
- "jsonc-eslint-parser": "3.1.0",
1109
- "prettier": "3.8.3",
1110
- "typescript": "~5.9.2",
1111
- "typescript-eslint": "^8.40.0",
1112
- "vite": "8.0.14",
1113
- "vitest": "4.1.7"
1148
+ "jsdom": "^27.1.0",
1149
+ "typescript": "~6.0.3",
1150
+ "vite": "8.1.4",
1151
+ "vitest": "4.1.10"
1114
1152
  },
1115
- "type": "module",
1116
- "scripts": {
1117
- "dev": "nx serve-local @proj/test-app"
1118
- }
1153
+ "type": "module"
1119
1154
  }
1120
1155
  "
1121
1156
  `;
@@ -1153,35 +1188,7 @@ You can also automatiaclly fix some lint errors by running the following command
1153
1188
 
1154
1189
  - [common-constructs reference docs](TODO)
1155
1190
  - [Learn more about NX](https://nx.dev/getting-started/intro)
1156
- "
1157
- `;
1158
-
1159
- exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > packages/common/constructs/eslint.config.mjs 1`] = `
1160
- "import baseConfig from '../../../eslint.config.mjs';
1161
1191
 
1162
- export default [
1163
- ...baseConfig,
1164
- {
1165
- files: ['**/*.json'],
1166
- rules: {
1167
- '@nx/dependency-checks': [
1168
- 'warn',
1169
- {
1170
- ignoredFiles: [
1171
- '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
1172
- '{projectRoot}/vitest.config.{js,ts,mjs,mts}',
1173
- ],
1174
- },
1175
- ],
1176
- },
1177
- languageOptions: {
1178
- parser: await import('jsonc-eslint-parser'),
1179
- },
1180
- },
1181
- {
1182
- ignores: ['**/out-tsc'],
1183
- },
1184
- ];
1185
1192
  "
1186
1193
  `;
1187
1194
 
@@ -1192,6 +1199,9 @@ exports[`react-website generator > Tanstack router integration > should generate
1192
1199
  "sourceRoot": "packages/common/constructs/src",
1193
1200
  "projectType": "library",
1194
1201
  "tags": [],
1202
+ "metadata": {
1203
+ "generator": "ts#project"
1204
+ },
1195
1205
  "targets": {
1196
1206
  "build": {
1197
1207
  "dependsOn": ["lint", "compile", "test", "@proj/test-app:build"]
@@ -1204,29 +1214,39 @@ exports[`react-website generator > Tanstack router integration > should generate
1204
1214
  "cwd": "{projectRoot}"
1205
1215
  }
1206
1216
  },
1207
- "lint": {
1208
- "executor": "@nx/eslint:lint",
1217
+ "format": {
1218
+ "executor": "nx:run-commands",
1209
1219
  "cache": true,
1210
- "inputs": ["eslint"],
1220
+ "inputs": ["biome"],
1221
+ "options": {
1222
+ "command": "biome format {projectRoot}"
1223
+ },
1211
1224
  "configurations": {
1212
1225
  "fix": {
1213
- "fix": true
1226
+ "command": "biome format --write {projectRoot}"
1214
1227
  },
1215
1228
  "skip-lint": {
1216
- "force": true
1229
+ "command": "node -e \\"\\""
1217
1230
  }
1218
1231
  }
1219
1232
  },
1220
- "test": {
1221
- "executor": "@nx/vitest:test",
1222
- "outputs": ["{options.reportsDirectory}"],
1233
+ "lint": {
1234
+ "executor": "nx:run-commands",
1235
+ "cache": true,
1236
+ "inputs": ["biome"],
1237
+ "dependsOn": ["format"],
1223
1238
  "options": {
1224
- "reportsDirectory": "{workspaceRoot}/coverage/{projectRoot}"
1239
+ "command": "biome lint {projectRoot}"
1240
+ },
1241
+ "configurations": {
1242
+ "fix": {
1243
+ "command": "biome check --write {projectRoot}"
1244
+ },
1245
+ "skip-lint": {
1246
+ "command": "node -e \\"\\""
1247
+ }
1225
1248
  }
1226
1249
  }
1227
- },
1228
- "metadata": {
1229
- "generator": "ts#project"
1230
1250
  }
1231
1251
  }
1232
1252
  "
@@ -1536,11 +1556,21 @@ exports[`react-website generator > Tanstack router integration > should generate
1536
1556
  "import {
1537
1557
  CfnOutput,
1538
1558
  CfnResource,
1559
+ Duration,
1539
1560
  Lazy,
1561
+ Names,
1540
1562
  RemovalPolicy,
1541
1563
  Stack,
1542
1564
  } from 'aws-cdk-lib';
1543
- import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
1565
+ import {
1566
+ Distribution,
1567
+ HeadersFrameOption,
1568
+ HeadersReferrerPolicy,
1569
+ ResponseHeadersPolicy,
1570
+ SecurityPolicyProtocol,
1571
+ ViewerProtocolPolicy,
1572
+ } from 'aws-cdk-lib/aws-cloudfront';
1573
+ import { ICertificate } from 'aws-cdk-lib/aws-certificatemanager';
1544
1574
  import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
1545
1575
  import {
1546
1576
  BlockPublicAccess,
@@ -1549,18 +1579,56 @@ import {
1549
1579
  IBucket,
1550
1580
  ObjectOwnership,
1551
1581
  } from 'aws-cdk-lib/aws-s3';
1552
- import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
1582
+ import {
1583
+ BucketDeployment,
1584
+ CacheControl,
1585
+ Source,
1586
+ } from 'aws-cdk-lib/aws-s3-deployment';
1553
1587
  import { Construct } from 'constructs';
1554
1588
  import { RuntimeConfig } from './runtime-config.js';
1555
1589
  import { Key } from 'aws-cdk-lib/aws-kms';
1590
+ import {
1591
+ CfnDelivery,
1592
+ CfnDeliveryDestination,
1593
+ CfnDeliverySource,
1594
+ LogGroup,
1595
+ RetentionDays,
1596
+ } from 'aws-cdk-lib/aws-logs';
1597
+ import { Effect, PolicyStatement, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
1556
1598
  import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
1557
1599
  import { suppressRules } from './checkov.js';
1558
1600
 
1559
1601
  const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
1560
1602
 
1603
+ // Content-Security-Policy enforced on all responses. Restricts scripts and
1604
+ // framing to mitigate XSS and clickjacking, while permitting HTTPS/WSS calls
1605
+ // (connect-src) to AWS service endpoints such as API Gateway, Cognito and
1606
+ // Bedrock AgentCore which are only known at deploy time. Edit this to tighten
1607
+ // connect-src to your specific origins once they are known.
1608
+ const CONTENT_SECURITY_POLICY = [
1609
+ "default-src 'self'",
1610
+ "script-src 'self'",
1611
+ "style-src 'self' 'unsafe-inline'",
1612
+ "img-src 'self' data:",
1613
+ "font-src 'self' data:",
1614
+ "connect-src 'self' https: wss:",
1615
+ "object-src 'none'",
1616
+ "base-uri 'self'",
1617
+ "frame-ancestors 'none'",
1618
+ ].join('; ');
1619
+
1561
1620
  export interface StaticWebsiteProps {
1562
1621
  readonly websiteName: string;
1563
1622
  readonly websiteFilePath: string;
1623
+ /**
1624
+ * Custom domain names for the CloudFront distribution. Requires \`certificate\`.
1625
+ */
1626
+ readonly domainNames?: string[];
1627
+ /**
1628
+ * ACM certificate for the custom domain names. Must be in us-east-1.
1629
+ * When provided, viewers are required to use TLS 1.2 or later.
1630
+ */
1631
+ readonly certificate?: ICertificate;
1564
1632
  }
1565
1633
 
1566
1634
  /**
@@ -1579,39 +1647,48 @@ export class StaticWebsite extends Construct {
1579
1647
  constructor(
1580
1648
  scope: Construct,
1581
1649
  id: string,
1582
- { websiteFilePath, websiteName }: StaticWebsiteProps,
1650
+ {
1651
+ websiteFilePath,
1652
+ websiteName,
1653
+ domainNames,
1654
+ certificate,
1655
+ }: StaticWebsiteProps,
1583
1656
  ) {
1584
1657
  super(scope, id);
1585
- this.node.setContext(
1586
- '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
1587
- true,
1588
- );
1589
1658
 
1590
1659
  const websiteKey = new Key(this, 'WebsiteKey', {
1591
1660
  enableKeyRotation: true,
1592
1661
  });
1593
1662
 
1594
- const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
1595
- versioned: false,
1596
- enforceSSL: true,
1597
- autoDeleteObjects: true,
1598
- removalPolicy: RemovalPolicy.DESTROY,
1599
- encryption: BucketEncryption.KMS,
1663
+ // Allow CloudWatch Logs to use the website key for server access log delivery.
1664
+ const stack = Stack.of(this);
1665
+ websiteKey.addToResourcePolicy(
1666
+ new PolicyStatement({
1667
+ effect: Effect.ALLOW,
1668
+ principals: [
1669
+ new ServicePrincipal(\`logs.\${stack.region}.amazonaws.com\`),
1670
+ ],
1671
+ actions: [
1672
+ 'kms:Encrypt',
1673
+ 'kms:Decrypt',
1674
+ 'kms:ReEncrypt*',
1675
+ 'kms:GenerateDataKey*',
1676
+ 'kms:DescribeKey',
1677
+ ],
1678
+ resources: ['*'],
1679
+ conditions: {
1680
+ ArnLike: {
1681
+ 'kms:EncryptionContext:aws:logs:arn': \`arn:aws:logs:\${stack.region}:\${stack.account}:log-group:*\`,
1682
+ },
1683
+ },
1684
+ }),
1685
+ );
1686
+
1687
+ const accessLogs = new LogGroup(this, 'AccessLogs', {
1688
+ retention: RetentionDays.ONE_YEAR,
1600
1689
  encryptionKey: websiteKey,
1601
- objectOwnership: ObjectOwnership.OBJECT_WRITER,
1602
- publicReadAccess: false,
1603
- blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
1690
+ removalPolicy: RemovalPolicy.DESTROY,
1604
1691
  });
1605
- suppressRules(
1606
- accessLogsBucket,
1607
- ['CKV_AWS_21'],
1608
- 'Access log bucket does not need versioning enabled',
1609
- );
1610
- suppressRules(
1611
- accessLogsBucket,
1612
- ['CKV_AWS_18'],
1613
- 'Access log bucket does not need an access log bucket',
1614
- );
1615
1692
 
1616
1693
  // S3 Bucket to hold website files
1617
1694
  this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
@@ -1624,13 +1701,23 @@ export class StaticWebsite extends Construct {
1624
1701
  objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
1625
1702
  publicReadAccess: false,
1626
1703
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
1627
- serverAccessLogsPrefix: 'website-access-logs',
1628
- serverAccessLogsBucket: accessLogsBucket,
1629
1704
  });
1705
+ suppressRules(
1706
+ this.websiteBucket,
1707
+ ['CKV_AWS_18'],
1708
+ 'Server access logs are delivered to CloudWatch Logs',
1709
+ );
1710
+ this.deliverAccessLogsToCloudWatch(
1711
+ 'Website',
1712
+ this.websiteBucket,
1713
+ accessLogs,
1714
+ );
1630
1715
  // Web ACL
1631
1716
  const wafStack = new CloudfrontWebAcl(this, 'waf');
1632
1717
 
1633
- // Cloudfront Distribution
1718
+ // Bucket holding CloudFront standard access logs. CloudFront delivers its
1719
+ // own logs to S3 only, so this bucket is retained; its S3 server access
1720
+ // logs are delivered to CloudWatch Logs.
1634
1721
  const logBucket = new Bucket(this, 'DistributionLogBucket', {
1635
1722
  enforceSSL: true,
1636
1723
  autoDeleteObjects: true,
@@ -1640,14 +1727,48 @@ export class StaticWebsite extends Construct {
1640
1727
  objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
1641
1728
  publicReadAccess: false,
1642
1729
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
1643
- serverAccessLogsPrefix: 'distribution-access-logs',
1644
- serverAccessLogsBucket: accessLogsBucket,
1645
1730
  });
1646
1731
  suppressRules(
1647
1732
  logBucket,
1648
1733
  ['CKV_AWS_21'],
1649
1734
  'Distribution log bucket does not need versioning enabled',
1650
1735
  );
1736
+ suppressRules(
1737
+ logBucket,
1738
+ ['CKV_AWS_18'],
1739
+ 'Server access logs are delivered to CloudWatch Logs',
1740
+ );
1741
+ this.deliverAccessLogsToCloudWatch('Distribution', logBucket, accessLogs);
1742
+
1743
+ // Security headers applied to all responses.
1744
+ const responseHeadersPolicy = new ResponseHeadersPolicy(
1745
+ this,
1746
+ 'ResponseHeadersPolicy',
1747
+ {
1748
+ securityHeadersBehavior: {
1749
+ strictTransportSecurity: {
1750
+ accessControlMaxAge: Duration.days(730),
1751
+ includeSubdomains: true,
1752
+ preload: true,
1753
+ override: true,
1754
+ },
1755
+ contentTypeOptions: { override: true },
1756
+ frameOptions: {
1757
+ frameOption: HeadersFrameOption.DENY,
1758
+ override: true,
1759
+ },
1760
+ referrerPolicy: {
1761
+ referrerPolicy:
1762
+ HeadersReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN,
1763
+ override: true,
1764
+ },
1765
+ contentSecurityPolicy: {
1766
+ contentSecurityPolicy: CONTENT_SECURITY_POLICY,
1767
+ override: true,
1768
+ },
1769
+ },
1770
+ },
1771
+ );
1651
1772
 
1652
1773
  const defaultRootObject = 'index.html';
1653
1774
  this.cloudFrontDistribution = new Distribution(
@@ -1657,9 +1778,17 @@ export class StaticWebsite extends Construct {
1657
1778
  webAclId: wafStack.wafArn,
1658
1779
  enableLogging: true,
1659
1780
  logBucket: logBucket,
1781
+ ...(certificate
1782
+ ? {
1783
+ certificate,
1784
+ domainNames,
1785
+ minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2021,
1786
+ }
1787
+ : {}),
1660
1788
  defaultBehavior: {
1661
1789
  origin: S3BucketOrigin.withOriginAccessControl(this.websiteBucket),
1662
1790
  viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
1791
+ responseHeadersPolicy,
1663
1792
  },
1664
1793
  defaultRootObject,
1665
1794
  errorResponses: [
@@ -1676,16 +1805,28 @@ export class StaticWebsite extends Construct {
1676
1805
  ],
1677
1806
  },
1678
1807
  );
1679
- suppressRules(
1680
- this.cloudFrontDistribution,
1681
- ['CKV_AWS_174'],
1682
- 'Cloudfront default certificate does not use TLS 1.2',
1683
- );
1808
+ if (!certificate) {
1809
+ // See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
1810
+ suppressRules(
1811
+ this.cloudFrontDistribution,
1812
+ ['CKV_AWS_174'],
1813
+ 'Cloudfront default certificate does not use TLS 1.2',
1814
+ );
1815
+ }
1684
1816
 
1685
1817
  // Deploy Website
1686
1818
  this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
1819
+ sources: [Source.asset(websiteFilePath)],
1820
+ destinationBucket: this.websiteBucket,
1821
+ // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
1822
+ distribution: this.cloudFrontDistribution,
1823
+ memoryLimit: 1024,
1824
+ });
1825
+
1826
+ // Deploy runtime-config.json separately so it is never cached - clients
1827
+ // must always fetch the latest configuration.
1828
+ new BucketDeployment(this, 'RuntimeConfigDeployment', {
1687
1829
  sources: [
1688
- Source.asset(websiteFilePath),
1689
1830
  Source.data(
1690
1831
  DEFAULT_RUNTIME_CONFIG_FILENAME,
1691
1832
  Lazy.string({
@@ -1697,8 +1838,9 @@ export class StaticWebsite extends Construct {
1697
1838
  ),
1698
1839
  ],
1699
1840
  destinationBucket: this.websiteBucket,
1700
- // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
1701
1841
  distribution: this.cloudFrontDistribution,
1842
+ cacheControl: [CacheControl.noCache()],
1843
+ prune: false,
1702
1844
  memoryLimit: 1024,
1703
1845
  });
1704
1846
 
@@ -1719,6 +1861,44 @@ export class StaticWebsite extends Construct {
1719
1861
  value: this.websiteBucket.bucketName,
1720
1862
  });
1721
1863
  }
1864
+
1865
+ /**
1866
+ * Delivers a bucket's S3 server access logs to a CloudWatch log group using
1867
+ * CloudWatch Logs vended log delivery.
1868
+ */
1869
+ private deliverAccessLogsToCloudWatch(
1870
+ id: string,
1871
+ bucket: IBucket,
1872
+ logGroup: LogGroup,
1873
+ ) {
1874
+ const source: CfnDeliverySource = new CfnDeliverySource(
1875
+ this,
1876
+ \`\${id}AccessLogsSource\`,
1877
+ {
1878
+ name: Lazy.string({
1879
+ produce: () => Names.uniqueResourceName(source, { maxLength: 60 }),
1880
+ }),
1881
+ logType: 'S3_SERVER_ACCESS_LOGS',
1882
+ resourceArn: bucket.bucketArn,
1883
+ },
1884
+ );
1885
+ const destination: CfnDeliveryDestination = new CfnDeliveryDestination(
1886
+ this,
1887
+ \`\${id}AccessLogsDestination\`,
1888
+ {
1889
+ name: Lazy.string({
1890
+ produce: () =>
1891
+ Names.uniqueResourceName(destination, { maxLength: 60 }),
1892
+ }),
1893
+ destinationResourceArn: logGroup.logGroupArn,
1894
+ },
1895
+ );
1896
+ const delivery = new CfnDelivery(this, \`\${id}AccessLogsDelivery\`, {
1897
+ deliverySourceName: source.name,
1898
+ deliveryDestinationArn: destination.attrArn,
1899
+ });
1900
+ delivery.addDependency(source);
1901
+ }
1722
1902
  }
1723
1903
 
1724
1904
  export class CloudfrontWebAcl extends Stack {
@@ -1841,9 +2021,13 @@ exports[`react-website generator > Tanstack router integration > should generate
1841
2021
  "emitDeclarationOnly": false,
1842
2022
  "module": "nodenext",
1843
2023
  "moduleResolution": "nodenext",
1844
- "types": ["node"]
2024
+ "types": [
2025
+ "node"
2026
+ ]
1845
2027
  },
1846
- "include": ["src/**/*.ts"],
2028
+ "include": [
2029
+ "src/**/*.ts"
2030
+ ],
1847
2031
  "references": [],
1848
2032
  "exclude": [
1849
2033
  "vite.config.ts",
@@ -1909,6 +2093,7 @@ export default defineConfig(() => ({
1909
2093
  root: __dirname,
1910
2094
  cacheDir: '../../../node_modules/.vite/packages/common/constructs',
1911
2095
  test: {
2096
+ passWithNoTests: true,
1912
2097
  name: '@proj/common-constructs',
1913
2098
  watch: false,
1914
2099
  globals: true,
@@ -1919,7 +2104,6 @@ export default defineConfig(() => ({
1919
2104
  reportsDirectory: './test-output/vitest/coverage',
1920
2105
  provider: 'v8' as const,
1921
2106
  },
1922
- passWithNoTests: true,
1923
2107
  },
1924
2108
  }));
1925
2109
  "
@@ -1927,15 +2111,14 @@ export default defineConfig(() => ({
1927
2111
 
1928
2112
  exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > pnpm-workspace.yaml 1`] = `
1929
2113
  "packages:
1930
- - 'packages/*'
1931
- - 'test-app'
1932
- - 'packages/common/*'
2114
+ - "packages/*"
2115
+ - "test-app"
2116
+ - "packages/common/*"
1933
2117
  "
1934
2118
  `;
1935
2119
 
1936
2120
  exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/README.md 1`] = `
1937
2121
  "# @proj/test-app
1938
-
1939
2122
  This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
1940
2123
 
1941
2124
  ## Building
@@ -1984,24 +2167,8 @@ In order to integrate with cognito or trpc backends, you need to have a \`runtim
1984
2167
  "
1985
2168
  `;
1986
2169
 
1987
- exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/eslint.config.mjs 1`] = `
1988
- "import nx from '@nx/eslint-plugin';
1989
- import baseConfig from '../eslint.config.mjs';
1990
-
1991
- export default [
1992
- ...nx.configs['flat/react'],
1993
- ...baseConfig,
1994
- {
1995
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
1996
- // Override or add rules here
1997
- rules: {},
1998
- },
1999
- ];
2000
- "
2001
- `;
2002
-
2003
2170
  exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/index.html 1`] = `
2004
- "<!doctype html>
2171
+ "<!DOCTYPE html>
2005
2172
  <html lang="en">
2006
2173
  <head>
2007
2174
  <meta charset="utf-8" />
@@ -2035,29 +2202,10 @@ exports[`react-website generator > Tanstack router integration > should generate
2035
2202
  },
2036
2203
  "targets": {
2037
2204
  "build": {
2038
- "dependsOn": ["lint", "compile", "bundle", "test"],
2039
- "options": {
2040
- "outputPath": "dist/{projectRoot}/bundle"
2041
- }
2042
- },
2043
- "bundle": {
2044
- "executor": "@nx/vite:build",
2045
- "outputs": ["{options.outputPath}"],
2046
- "defaultConfiguration": "production",
2047
- "options": {
2048
- "outputPath": "dist/{projectRoot}/bundle"
2049
- },
2050
- "configurations": {
2051
- "development": {
2052
- "mode": "development"
2053
- },
2054
- "production": {
2055
- "mode": "production"
2056
- }
2057
- }
2205
+ "dependsOn": ["lint", "compile", "test", "bundle"]
2058
2206
  },
2059
2207
  "compile": {
2060
- "dependsOn": ["bundle"],
2208
+ "dependsOn": ["^build"],
2061
2209
  "executor": "nx:run-commands",
2062
2210
  "outputs": ["{workspaceRoot}/dist/{projectRoot}/tsc"],
2063
2211
  "options": {
@@ -2065,83 +2213,54 @@ exports[`react-website generator > Tanstack router integration > should generate
2065
2213
  "cwd": "{projectRoot}"
2066
2214
  }
2067
2215
  },
2068
- "lint": {
2069
- "executor": "@nx/eslint:lint",
2070
- "cache": true,
2071
- "inputs": ["eslint"],
2072
- "configurations": {
2073
- "fix": {
2074
- "fix": true
2075
- },
2076
- "skip-lint": {
2077
- "force": true
2078
- }
2079
- }
2080
- },
2081
- "load:runtime-config": {
2216
+ "dev": {
2082
2217
  "executor": "nx:run-commands",
2083
- "metadata": {
2084
- "description": "Load runtime config from your deployed stack for dev purposes. You must set your AWS CLI credentials whilst calling 'pnpm nx run @proj/test-app:load:runtime-config'"
2085
- },
2218
+ "continuous": true,
2086
2219
  "options": {
2087
- "command": "aws s3 cp s3://\`aws cloudformation describe-stacks --query \\"Stacks[?starts_with(StackName, 'proj-')][].Outputs[] | [?contains(OutputKey, 'TestAppWebsiteBucketName')].OutputValue\\" --output text\`/runtime-config.json \\"{projectRoot}/public/runtime-config.json\\""
2220
+ "command": "vite --mode local-dev",
2221
+ "cwd": "{projectRoot}"
2088
2222
  }
2089
2223
  },
2090
- "preview": {
2091
- "dependsOn": ["build"],
2092
- "executor": "@nx/vite:preview-server",
2093
- "defaultConfiguration": "development",
2224
+ "format": {
2225
+ "executor": "nx:run-commands",
2226
+ "cache": true,
2227
+ "inputs": ["biome"],
2094
2228
  "options": {
2095
- "buildTarget": "@proj/test-app:build"
2229
+ "command": "biome format {projectRoot}"
2096
2230
  },
2097
2231
  "configurations": {
2098
- "development": {
2099
- "buildTarget": "@proj/test-app:build:development"
2232
+ "fix": {
2233
+ "command": "biome format --write {projectRoot}"
2100
2234
  },
2101
- "production": {
2102
- "buildTarget": "@proj/test-app:build:production"
2235
+ "skip-lint": {
2236
+ "command": "node -e \\"\\""
2103
2237
  }
2104
2238
  }
2105
2239
  },
2106
- "serve": {
2107
- "executor": "@nx/vite:dev-server",
2108
- "defaultConfiguration": "development",
2240
+ "lint": {
2241
+ "executor": "nx:run-commands",
2242
+ "cache": true,
2243
+ "inputs": ["biome"],
2109
2244
  "options": {
2110
- "buildTarget": "@proj/test-app:build"
2245
+ "command": "biome lint {projectRoot}"
2111
2246
  },
2112
2247
  "configurations": {
2113
- "development": {
2114
- "buildTarget": "@proj/test-app:build:development",
2115
- "hmr": true
2248
+ "fix": {
2249
+ "command": "biome check --write {projectRoot}"
2116
2250
  },
2117
- "production": {
2118
- "buildTarget": "@proj/test-app:build:production",
2119
- "hmr": false
2251
+ "skip-lint": {
2252
+ "command": "node -e \\"\\""
2120
2253
  }
2121
- }
2122
- },
2123
- "serve-local": {
2124
- "executor": "@nx/vite:dev-server",
2125
- "options": {
2126
- "buildTarget": "@proj/test-app:build:development",
2127
- "hmr": true,
2128
- "mode": "serve-local"
2129
2254
  },
2130
- "continuous": true
2255
+ "dependsOn": ["format"]
2131
2256
  },
2132
- "serve-static": {
2133
- "executor": "@nx/web:file-server",
2134
- "dependsOn": ["build"],
2135
- "options": {
2136
- "buildTarget": "@proj/test-app:build",
2137
- "spa": true
2138
- }
2139
- },
2140
- "test": {
2141
- "executor": "@nx/vitest:test",
2142
- "outputs": ["{options.reportsDirectory}"],
2257
+ "load:runtime-config": {
2258
+ "executor": "nx:run-commands",
2259
+ "metadata": {
2260
+ "description": "Load runtime config from your deployed stack for dev purposes. You must set your AWS CLI credentials whilst calling 'pnpm nx run @proj/test-app:load:runtime-config'"
2261
+ },
2143
2262
  "options": {
2144
- "reportsDirectory": "{workspaceRoot}/coverage/{projectRoot}"
2263
+ "command": "aws s3 cp s3://\`aws cloudformation describe-stacks --query \\"Stacks[?starts_with(StackName, 'proj-')][].Outputs[] | [?contains(OutputKey, 'TestAppWebsiteBucketName')].OutputValue\\" --output text\`/runtime-config.json \\"{projectRoot}/public/runtime-config.json\\""
2145
2264
  }
2146
2265
  }
2147
2266
  }
@@ -2349,15 +2468,22 @@ exports[`react-website generator > Tanstack router integration > should generate
2349
2468
  "outDir": "../dist/test-app/tsc",
2350
2469
  "tsBuildInfoFile": "../dist/test-app/tsc/tsconfig.lib.tsbuildinfo",
2351
2470
  "jsx": "react-jsx",
2352
- "lib": ["DOM"],
2471
+ "lib": [
2472
+ "DOM"
2473
+ ],
2353
2474
  "types": [
2354
2475
  "node",
2355
2476
  "@nx/react/typings/cssmodule.d.ts",
2356
2477
  "@nx/react/typings/image.d.ts",
2357
2478
  "vite/client"
2358
- ]
2479
+ ],
2480
+ "rootDir": "src",
2481
+ "module": "esnext",
2482
+ "moduleResolution": "bundler"
2359
2483
  },
2360
2484
  "exclude": [
2485
+ "out-tsc",
2486
+ "dist",
2361
2487
  "src/**/*.spec.ts",
2362
2488
  "src/**/*.test.ts",
2363
2489
  "src/**/*.spec.tsx",
@@ -2371,7 +2497,12 @@ exports[`react-website generator > Tanstack router integration > should generate
2371
2497
  "vitest.config.ts",
2372
2498
  "vitest.config.mts"
2373
2499
  ],
2374
- "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
2500
+ "include": [
2501
+ "src/**/*.js",
2502
+ "src/**/*.jsx",
2503
+ "src/**/*.ts",
2504
+ "src/**/*.tsx"
2505
+ ]
2375
2506
  }
2376
2507
  "
2377
2508
  `;
@@ -2410,7 +2541,10 @@ exports[`react-website generator > Tanstack router integration > should generate
2410
2541
  "vitest",
2411
2542
  "@nx/react/typings/cssmodule.d.ts",
2412
2543
  "@nx/react/typings/image.d.ts"
2413
- ]
2544
+ ],
2545
+ "jsx": "react-jsx",
2546
+ "module": "esnext",
2547
+ "moduleResolution": "bundler"
2414
2548
  },
2415
2549
  "include": [
2416
2550
  "vite.config.ts",
@@ -2459,7 +2593,7 @@ export default defineConfig(() => ({
2459
2593
  // plugins: [],
2460
2594
  // },
2461
2595
  build: {
2462
- outDir: '../dist/test-app',
2596
+ outDir: '../dist/test-app/bundle',
2463
2597
  emptyOutDir: true,
2464
2598
  reportCompressedSize: true,
2465
2599
  commonjsOptions: {
@@ -2467,6 +2601,7 @@ export default defineConfig(() => ({
2467
2601
  },
2468
2602
  },
2469
2603
  test: {
2604
+ passWithNoTests: true,
2470
2605
  name: '@proj/test-app',
2471
2606
  watch: false,
2472
2607
  globals: true,
@@ -2477,7 +2612,6 @@ export default defineConfig(() => ({
2477
2612
  reportsDirectory: './test-output/vitest/coverage',
2478
2613
  provider: 'v8' as const,
2479
2614
  },
2480
- passWithNoTests: true,
2481
2615
  },
2482
2616
  resolve: { tsconfigPaths: true },
2483
2617
  define: { global: {} },
@@ -2489,9 +2623,14 @@ exports[`react-website generator > Tanstack router integration > should generate
2489
2623
  "{
2490
2624
  "compilerOptions": {
2491
2625
  "paths": {
2492
- ":proj/test-app": ["./test-app/src/index.ts"],
2493
- ":proj/common-constructs": ["./packages/common/constructs/src/index.ts"]
2626
+ ":proj/test-app": [
2627
+ "./test-app/src/index.ts"
2628
+ ],
2629
+ ":proj/common-constructs": [
2630
+ "./packages/common/constructs/src/index.ts"
2631
+ ]
2494
2632
  },
2633
+ "composite": true,
2495
2634
  "rootDir": "."
2496
2635
  }
2497
2636
  }
@@ -2500,6 +2639,9 @@ exports[`react-website generator > Tanstack router integration > should generate
2500
2639
 
2501
2640
  exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > tsconfig.json 1`] = `
2502
2641
  "{
2642
+ "extends": "./tsconfig.base.json",
2643
+ "files": [],
2644
+ "include": [],
2503
2645
  "references": [
2504
2646
  {
2505
2647
  "path": "./test-app"
@@ -2528,61 +2670,63 @@ vitest.config.*.timestamp*
2528
2670
  runtime-config.json"
2529
2671
  `;
2530
2672
 
2531
- exports[`react-website generator > Tanstack router integration > should generate website with router correctly > .prettierrc 1`] = `
2532
- "{ "singleQuote": true }
2533
- "
2534
- `;
2673
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > .prettierrc 1`] = `"{"singleQuote":true}"`;
2535
2674
 
2536
- exports[`react-website generator > Tanstack router integration > should generate website with router correctly > eslint.config.mjs 1`] = `
2537
- "import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
2538
- import nx from '@nx/eslint-plugin';
2539
-
2540
- export default [
2541
- eslintPluginPrettierRecommended,
2542
- ...nx.configs['flat/base'],
2543
- ...nx.configs['flat/typescript'],
2544
- ...nx.configs['flat/javascript'],
2545
- {
2546
- ignores: [
2547
- '**/dist',
2548
- '**/out-tsc',
2549
- '**/vite.config.*.timestamp*',
2550
- '**/vitest.config.*.timestamp*',
2551
- ],
2675
+ exports[`react-website generator > Tanstack router integration > should generate website with router correctly > biome.json 1`] = `
2676
+ "{
2677
+ "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
2678
+ "root": true,
2679
+ "formatter": {
2680
+ "enabled": true,
2681
+ "indentStyle": "space",
2682
+ "indentWidth": 2,
2683
+ "lineWidth": 80
2552
2684
  },
2553
- {
2554
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
2555
- rules: {
2556
- '@nx/enforce-module-boundaries': [
2557
- 'error',
2558
- {
2559
- enforceBuildableLibDependency: true,
2560
- allow: ['^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?[jt]s$'],
2561
- depConstraints: [
2562
- {
2563
- sourceTag: '*',
2564
- onlyDependOnLibsWithTags: ['*'],
2565
- },
2566
- ],
2567
- },
2568
- ],
2685
+ "javascript": {
2686
+ "formatter": {
2687
+ "quoteStyle": "single",
2688
+ "trailingCommas": "all"
2689
+ }
2690
+ },
2691
+ "css": {
2692
+ "formatter": {
2693
+ "quoteStyle": "single"
2569
2694
  },
2695
+ "linter": {
2696
+ "enabled": false
2697
+ }
2570
2698
  },
2571
- {
2572
- files: [
2573
- '**/*.ts',
2574
- '**/*.tsx',
2575
- '**/*.cts',
2576
- '**/*.mts',
2577
- '**/*.js',
2578
- '**/*.jsx',
2579
- '**/*.cjs',
2580
- '**/*.mjs',
2581
- ],
2582
- // Override or add rules here
2583
- rules: {},
2699
+ "linter": {
2700
+ "enabled": true,
2701
+ "rules": {
2702
+ "recommended": false,
2703
+ "correctness": {
2704
+ "noUndeclaredDependencies": "warn"
2705
+ }
2706
+ }
2584
2707
  },
2585
- ];
2708
+ "assist": {
2709
+ "actions": {
2710
+ "source": {
2711
+ "organizeImports": "on"
2712
+ }
2713
+ }
2714
+ },
2715
+ "files": {
2716
+ "includes": [
2717
+ "**",
2718
+ "!**/dist",
2719
+ "!**/out-tsc",
2720
+ "!**/node_modules",
2721
+ "!**/.nx",
2722
+ "!**/.venv",
2723
+ "!**/*.css",
2724
+ "!**/*.gen.*",
2725
+ "!**/generated/**",
2726
+ "!**/tsconfig*.json"
2727
+ ]
2728
+ }
2729
+ }
2586
2730
  "
2587
2731
  `;
2588
2732
 
@@ -2594,76 +2738,29 @@ exports[`react-website generator > Tanstack router integration > should generate
2594
2738
  "targetDefaults": {
2595
2739
  "build": {
2596
2740
  "cache": true,
2597
- "dependsOn": ["^build"],
2598
2741
  "inputs": ["default"]
2599
2742
  },
2600
2743
  "lint": {
2601
2744
  "cache": true
2602
2745
  },
2603
- "@nx/eslint:lint": {
2604
- "cache": true,
2605
- "inputs": [
2606
- "default",
2607
- "^default",
2608
- "{workspaceRoot}/.eslintrc.json",
2609
- "{workspaceRoot}/.eslintignore",
2610
- "{workspaceRoot}/eslint.config.mjs",
2611
- "{workspaceRoot}/tools/eslint-rules/**/*"
2612
- ]
2613
- },
2614
- "@nx/vite:build": {
2615
- "cache": true,
2746
+ "test": {
2616
2747
  "dependsOn": ["^build"],
2617
- "inputs": ["default", "^default"]
2748
+ "inputs": ["default"]
2618
2749
  },
2619
2750
  "@nx/vitest:test": {
2620
2751
  "cache": true,
2621
- "inputs": ["default", "^default"],
2752
+ "inputs": ["default", "^production"],
2622
2753
  "configurations": {
2623
2754
  "update-snapshot": {
2624
2755
  "args": "--update"
2625
2756
  }
2626
2757
  }
2627
2758
  },
2628
- "test": {
2629
- "dependsOn": ["^build"],
2630
- "inputs": ["default"]
2631
- },
2632
2759
  "compile": {
2633
2760
  "cache": true,
2634
2761
  "inputs": ["default"]
2635
2762
  }
2636
2763
  },
2637
- "generators": {
2638
- "@nx/react": {
2639
- "application": {
2640
- "babel": true,
2641
- "style": "css",
2642
- "linter": "eslint",
2643
- "bundler": "vite"
2644
- },
2645
- "component": {
2646
- "style": "css"
2647
- },
2648
- "library": {
2649
- "style": "css",
2650
- "linter": "eslint"
2651
- }
2652
- }
2653
- },
2654
- "namedInputs": {
2655
- "eslint": [
2656
- "default",
2657
- "{workspaceRoot}/eslint.config.mjs",
2658
- "{projectRoot}/eslint.config.mjs"
2659
- ],
2660
- "default": [
2661
- {
2662
- "dependentTasksOutputFiles": "**/*",
2663
- "transitive": true
2664
- }
2665
- ]
2666
- },
2667
2764
  "plugins": [
2668
2765
  {
2669
2766
  "plugin": "@nx/js/typescript",
@@ -2678,8 +2775,55 @@ exports[`react-website generator > Tanstack router integration > should generate
2678
2775
  "watchDepsName": "watch-deps"
2679
2776
  }
2680
2777
  }
2778
+ },
2779
+ {
2780
+ "plugin": "@nx/vite/plugin",
2781
+ "options": {
2782
+ "buildTargetName": "bundle",
2783
+ "serveTargetName": "serve",
2784
+ "devTargetName": "serve",
2785
+ "previewTargetName": "preview",
2786
+ "serveStaticTargetName": "serve-static",
2787
+ "typecheckTargetName": "vite:typecheck",
2788
+ "buildDepsTargetName": "build-deps",
2789
+ "watchDepsTargetName": "watch-deps"
2790
+ }
2791
+ },
2792
+ {
2793
+ "plugin": "@nx/vitest",
2794
+ "options": {
2795
+ "testTargetName": "test",
2796
+ "ciTargetName": "test-ci",
2797
+ "testMode": "watch"
2798
+ }
2799
+ }
2800
+ ],
2801
+ "generators": {
2802
+ "@nx/react": {
2803
+ "application": {
2804
+ "babel": true,
2805
+ "style": "css",
2806
+ "linter": "none",
2807
+ "bundler": "vite"
2808
+ },
2809
+ "component": {
2810
+ "style": "css"
2811
+ },
2812
+ "library": {
2813
+ "style": "css",
2814
+ "linter": "none"
2815
+ }
2681
2816
  }
2682
- ]
2817
+ },
2818
+ "namedInputs": {
2819
+ "biome": ["default", "{workspaceRoot}/biome.json"],
2820
+ "default": [
2821
+ {
2822
+ "dependentTasksOutputFiles": "**/*",
2823
+ "transitive": true
2824
+ }
2825
+ ]
2826
+ }
2683
2827
  }
2684
2828
  "
2685
2829
  `;
@@ -2688,62 +2832,43 @@ exports[`react-website generator > Tanstack router integration > should generate
2688
2832
  "{
2689
2833
  "name": "@proj/source",
2690
2834
  "dependencies": {
2691
- "@cloudscape-design/board-components": "3.0.187",
2692
- "@cloudscape-design/components": "3.0.1304",
2693
- "@cloudscape-design/global-styles": "1.0.59",
2694
- "@tanstack/react-router": "1.170.10",
2695
- "aws-cdk-lib": "2.257.0",
2835
+ "@cloudscape-design/board-components": "3.0.201",
2836
+ "@cloudscape-design/components": "3.0.1325",
2837
+ "@cloudscape-design/global-styles": "1.0.62",
2838
+ "@tanstack/react-router": "1.170.17",
2839
+ "aws-cdk-lib": "2.261.0",
2696
2840
  "constructs": "10.6.0",
2697
2841
  "react": "19.2.7",
2698
2842
  "react-dom": "19.2.7",
2699
- "tailwindcss": "4.3.0"
2843
+ "tailwindcss": "4.3.2"
2700
2844
  },
2701
2845
  "devDependencies": {
2702
- "@eslint/js": "^9.8.0",
2703
- "@nx/eslint": "22.7.5",
2704
- "@nx/eslint-plugin": "22.7.5",
2705
- "@nx/js": "22.7.5",
2706
- "@nx/react": "22.7.5",
2707
- "@nx/vite": "22.7.5",
2708
- "@nx/vitest": "22.7.5",
2709
- "@nx/web": "22.7.5",
2710
- "@swc-node/register": "~1.11.1",
2711
- "@swc/cli": "~0.8.0",
2712
- "@swc/core": "~1.15.5",
2846
+ "@nx/js": "23.1.0",
2847
+ "@nx/react": "23.1.0",
2848
+ "@nx/vite": "23.1.0",
2849
+ "@nx/vitest": "23.1.0",
2850
+ "@nx/web": "23.1.0",
2713
2851
  "@swc/helpers": "~0.5.18",
2714
- "@tailwindcss/vite": "4.3.0",
2715
- "@tanstack/router-generator": "1.167.12",
2716
- "@tanstack/router-plugin": "1.168.13",
2717
- "@tanstack/router-utils": "1.162.1",
2852
+ "@tailwindcss/vite": "4.3.2",
2853
+ "@tanstack/router-generator": "1.167.18",
2854
+ "@tanstack/router-plugin": "1.168.19",
2855
+ "@tanstack/router-utils": "1.162.2",
2718
2856
  "@tanstack/virtual-file-routes": "1.162.0",
2719
2857
  "@testing-library/dom": "10.4.0",
2720
2858
  "@testing-library/react": "16.3.0",
2721
- "@types/node": "25.9.1",
2859
+ "@types/node": "26.1.1",
2722
2860
  "@types/react": "^19.0.0",
2723
2861
  "@types/react-dom": "^19.0.0",
2724
2862
  "@vitejs/plugin-react": "^6.0.0",
2725
- "@vitest/coverage-v8": "4.1.7",
2726
- "@vitest/ui": "4.1.7",
2727
- "eslint": "^9.8.0",
2728
- "eslint-config-prettier": "^10.0.0",
2729
- "eslint-plugin-import": "2.31.0",
2730
- "eslint-plugin-jsx-a11y": "6.10.1",
2731
- "eslint-plugin-prettier": "5.5.6",
2732
- "eslint-plugin-react": "7.35.0",
2733
- "eslint-plugin-react-hooks": "5.0.0",
2863
+ "@vitest/coverage-v8": "4.1.10",
2864
+ "@vitest/ui": "4.1.10",
2734
2865
  "jiti": "2.4.2",
2735
- "jsdom": "~22.1.0",
2736
- "jsonc-eslint-parser": "3.1.0",
2737
- "prettier": "3.8.3",
2738
- "typescript": "~5.9.2",
2739
- "typescript-eslint": "^8.40.0",
2740
- "vite": "8.0.14",
2741
- "vitest": "4.1.7"
2866
+ "jsdom": "^27.1.0",
2867
+ "typescript": "~6.0.3",
2868
+ "vite": "8.1.4",
2869
+ "vitest": "4.1.10"
2742
2870
  },
2743
- "type": "module",
2744
- "scripts": {
2745
- "dev": "nx serve-local @proj/test-app"
2746
- }
2871
+ "type": "module"
2747
2872
  }
2748
2873
  "
2749
2874
  `;
@@ -2781,35 +2906,7 @@ You can also automatiaclly fix some lint errors by running the following command
2781
2906
 
2782
2907
  - [common-constructs reference docs](TODO)
2783
2908
  - [Learn more about NX](https://nx.dev/getting-started/intro)
2784
- "
2785
- `;
2786
-
2787
- exports[`react-website generator > Tanstack router integration > should generate website with router correctly > packages/common/constructs/eslint.config.mjs 1`] = `
2788
- "import baseConfig from '../../../eslint.config.mjs';
2789
2909
 
2790
- export default [
2791
- ...baseConfig,
2792
- {
2793
- files: ['**/*.json'],
2794
- rules: {
2795
- '@nx/dependency-checks': [
2796
- 'warn',
2797
- {
2798
- ignoredFiles: [
2799
- '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
2800
- '{projectRoot}/vitest.config.{js,ts,mjs,mts}',
2801
- ],
2802
- },
2803
- ],
2804
- },
2805
- languageOptions: {
2806
- parser: await import('jsonc-eslint-parser'),
2807
- },
2808
- },
2809
- {
2810
- ignores: ['**/out-tsc'],
2811
- },
2812
- ];
2813
2910
  "
2814
2911
  `;
2815
2912
 
@@ -2820,6 +2917,9 @@ exports[`react-website generator > Tanstack router integration > should generate
2820
2917
  "sourceRoot": "packages/common/constructs/src",
2821
2918
  "projectType": "library",
2822
2919
  "tags": [],
2920
+ "metadata": {
2921
+ "generator": "ts#project"
2922
+ },
2823
2923
  "targets": {
2824
2924
  "build": {
2825
2925
  "dependsOn": ["lint", "compile", "test", "@proj/test-app:build"]
@@ -2832,29 +2932,39 @@ exports[`react-website generator > Tanstack router integration > should generate
2832
2932
  "cwd": "{projectRoot}"
2833
2933
  }
2834
2934
  },
2835
- "lint": {
2836
- "executor": "@nx/eslint:lint",
2935
+ "format": {
2936
+ "executor": "nx:run-commands",
2837
2937
  "cache": true,
2838
- "inputs": ["eslint"],
2938
+ "inputs": ["biome"],
2939
+ "options": {
2940
+ "command": "biome format {projectRoot}"
2941
+ },
2839
2942
  "configurations": {
2840
2943
  "fix": {
2841
- "fix": true
2944
+ "command": "biome format --write {projectRoot}"
2842
2945
  },
2843
2946
  "skip-lint": {
2844
- "force": true
2947
+ "command": "node -e \\"\\""
2845
2948
  }
2846
2949
  }
2847
2950
  },
2848
- "test": {
2849
- "executor": "@nx/vitest:test",
2850
- "outputs": ["{options.reportsDirectory}"],
2951
+ "lint": {
2952
+ "executor": "nx:run-commands",
2953
+ "cache": true,
2954
+ "inputs": ["biome"],
2955
+ "dependsOn": ["format"],
2851
2956
  "options": {
2852
- "reportsDirectory": "{workspaceRoot}/coverage/{projectRoot}"
2957
+ "command": "biome lint {projectRoot}"
2958
+ },
2959
+ "configurations": {
2960
+ "fix": {
2961
+ "command": "biome check --write {projectRoot}"
2962
+ },
2963
+ "skip-lint": {
2964
+ "command": "node -e \\"\\""
2965
+ }
2853
2966
  }
2854
2967
  }
2855
- },
2856
- "metadata": {
2857
- "generator": "ts#project"
2858
2968
  }
2859
2969
  }
2860
2970
  "
@@ -3164,11 +3274,21 @@ exports[`react-website generator > Tanstack router integration > should generate
3164
3274
  "import {
3165
3275
  CfnOutput,
3166
3276
  CfnResource,
3277
+ Duration,
3167
3278
  Lazy,
3279
+ Names,
3168
3280
  RemovalPolicy,
3169
3281
  Stack,
3170
3282
  } from 'aws-cdk-lib';
3171
- import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
3283
+ import {
3284
+ Distribution,
3285
+ HeadersFrameOption,
3286
+ HeadersReferrerPolicy,
3287
+ ResponseHeadersPolicy,
3288
+ SecurityPolicyProtocol,
3289
+ ViewerProtocolPolicy,
3290
+ } from 'aws-cdk-lib/aws-cloudfront';
3291
+ import { ICertificate } from 'aws-cdk-lib/aws-certificatemanager';
3172
3292
  import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
3173
3293
  import {
3174
3294
  BlockPublicAccess,
@@ -3177,18 +3297,56 @@ import {
3177
3297
  IBucket,
3178
3298
  ObjectOwnership,
3179
3299
  } from 'aws-cdk-lib/aws-s3';
3180
- import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
3300
+ import {
3301
+ BucketDeployment,
3302
+ CacheControl,
3303
+ Source,
3304
+ } from 'aws-cdk-lib/aws-s3-deployment';
3181
3305
  import { Construct } from 'constructs';
3182
3306
  import { RuntimeConfig } from './runtime-config.js';
3183
3307
  import { Key } from 'aws-cdk-lib/aws-kms';
3308
+ import {
3309
+ CfnDelivery,
3310
+ CfnDeliveryDestination,
3311
+ CfnDeliverySource,
3312
+ LogGroup,
3313
+ RetentionDays,
3314
+ } from 'aws-cdk-lib/aws-logs';
3315
+ import { Effect, PolicyStatement, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
3184
3316
  import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
3185
3317
  import { suppressRules } from './checkov.js';
3186
3318
 
3187
3319
  const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
3188
3320
 
3321
+ // Content-Security-Policy enforced on all responses. Restricts scripts and
3322
+ // framing to mitigate XSS and clickjacking, while permitting HTTPS/WSS calls
3323
+ // (connect-src) to AWS service endpoints such as API Gateway, Cognito and
3324
+ // Bedrock AgentCore which are only known at deploy time. Edit this to tighten
3325
+ // connect-src to your specific origins once they are known.
3326
+ const CONTENT_SECURITY_POLICY = [
3327
+ "default-src 'self'",
3328
+ "script-src 'self'",
3329
+ "style-src 'self' 'unsafe-inline'",
3330
+ "img-src 'self' data:",
3331
+ "font-src 'self' data:",
3332
+ "connect-src 'self' https: wss:",
3333
+ "object-src 'none'",
3334
+ "base-uri 'self'",
3335
+ "frame-ancestors 'none'",
3336
+ ].join('; ');
3337
+
3189
3338
  export interface StaticWebsiteProps {
3190
3339
  readonly websiteName: string;
3191
3340
  readonly websiteFilePath: string;
3341
+ /**
3342
+ * Custom domain names for the CloudFront distribution. Requires \`certificate\`.
3343
+ */
3344
+ readonly domainNames?: string[];
3345
+ /**
3346
+ * ACM certificate for the custom domain names. Must be in us-east-1.
3347
+ * When provided, viewers are required to use TLS 1.2 or later.
3348
+ */
3349
+ readonly certificate?: ICertificate;
3192
3350
  }
3193
3351
 
3194
3352
  /**
@@ -3207,39 +3365,48 @@ export class StaticWebsite extends Construct {
3207
3365
  constructor(
3208
3366
  scope: Construct,
3209
3367
  id: string,
3210
- { websiteFilePath, websiteName }: StaticWebsiteProps,
3368
+ {
3369
+ websiteFilePath,
3370
+ websiteName,
3371
+ domainNames,
3372
+ certificate,
3373
+ }: StaticWebsiteProps,
3211
3374
  ) {
3212
3375
  super(scope, id);
3213
- this.node.setContext(
3214
- '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
3215
- true,
3216
- );
3217
3376
 
3218
3377
  const websiteKey = new Key(this, 'WebsiteKey', {
3219
3378
  enableKeyRotation: true,
3220
3379
  });
3221
3380
 
3222
- const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
3223
- versioned: false,
3224
- enforceSSL: true,
3225
- autoDeleteObjects: true,
3226
- removalPolicy: RemovalPolicy.DESTROY,
3227
- encryption: BucketEncryption.KMS,
3381
+ // Allow CloudWatch Logs to use the website key for server access log delivery.
3382
+ const stack = Stack.of(this);
3383
+ websiteKey.addToResourcePolicy(
3384
+ new PolicyStatement({
3385
+ effect: Effect.ALLOW,
3386
+ principals: [
3387
+ new ServicePrincipal(\`logs.\${stack.region}.amazonaws.com\`),
3388
+ ],
3389
+ actions: [
3390
+ 'kms:Encrypt',
3391
+ 'kms:Decrypt',
3392
+ 'kms:ReEncrypt*',
3393
+ 'kms:GenerateDataKey*',
3394
+ 'kms:DescribeKey',
3395
+ ],
3396
+ resources: ['*'],
3397
+ conditions: {
3398
+ ArnLike: {
3399
+ 'kms:EncryptionContext:aws:logs:arn': \`arn:aws:logs:\${stack.region}:\${stack.account}:log-group:*\`,
3400
+ },
3401
+ },
3402
+ }),
3403
+ );
3404
+
3405
+ const accessLogs = new LogGroup(this, 'AccessLogs', {
3406
+ retention: RetentionDays.ONE_YEAR,
3228
3407
  encryptionKey: websiteKey,
3229
- objectOwnership: ObjectOwnership.OBJECT_WRITER,
3230
- publicReadAccess: false,
3231
- blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
3408
+ removalPolicy: RemovalPolicy.DESTROY,
3232
3409
  });
3233
- suppressRules(
3234
- accessLogsBucket,
3235
- ['CKV_AWS_21'],
3236
- 'Access log bucket does not need versioning enabled',
3237
- );
3238
- suppressRules(
3239
- accessLogsBucket,
3240
- ['CKV_AWS_18'],
3241
- 'Access log bucket does not need an access log bucket',
3242
- );
3243
3410
 
3244
3411
  // S3 Bucket to hold website files
3245
3412
  this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
@@ -3252,13 +3419,23 @@ export class StaticWebsite extends Construct {
3252
3419
  objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
3253
3420
  publicReadAccess: false,
3254
3421
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
3255
- serverAccessLogsPrefix: 'website-access-logs',
3256
- serverAccessLogsBucket: accessLogsBucket,
3257
3422
  });
3423
+ suppressRules(
3424
+ this.websiteBucket,
3425
+ ['CKV_AWS_18'],
3426
+ 'Server access logs are delivered to CloudWatch Logs',
3427
+ );
3428
+ this.deliverAccessLogsToCloudWatch(
3429
+ 'Website',
3430
+ this.websiteBucket,
3431
+ accessLogs,
3432
+ );
3258
3433
  // Web ACL
3259
3434
  const wafStack = new CloudfrontWebAcl(this, 'waf');
3260
3435
 
3261
- // Cloudfront Distribution
3436
+ // Bucket holding CloudFront standard access logs. CloudFront delivers its
3437
+ // own logs to S3 only, so this bucket is retained; its S3 server access
3438
+ // logs are delivered to CloudWatch Logs.
3262
3439
  const logBucket = new Bucket(this, 'DistributionLogBucket', {
3263
3440
  enforceSSL: true,
3264
3441
  autoDeleteObjects: true,
@@ -3268,14 +3445,48 @@ export class StaticWebsite extends Construct {
3268
3445
  objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
3269
3446
  publicReadAccess: false,
3270
3447
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
3271
- serverAccessLogsPrefix: 'distribution-access-logs',
3272
- serverAccessLogsBucket: accessLogsBucket,
3273
3448
  });
3274
3449
  suppressRules(
3275
3450
  logBucket,
3276
3451
  ['CKV_AWS_21'],
3277
3452
  'Distribution log bucket does not need versioning enabled',
3278
3453
  );
3454
+ suppressRules(
3455
+ logBucket,
3456
+ ['CKV_AWS_18'],
3457
+ 'Server access logs are delivered to CloudWatch Logs',
3458
+ );
3459
+ this.deliverAccessLogsToCloudWatch('Distribution', logBucket, accessLogs);
3460
+
3461
+ // Security headers applied to all responses.
3462
+ const responseHeadersPolicy = new ResponseHeadersPolicy(
3463
+ this,
3464
+ 'ResponseHeadersPolicy',
3465
+ {
3466
+ securityHeadersBehavior: {
3467
+ strictTransportSecurity: {
3468
+ accessControlMaxAge: Duration.days(730),
3469
+ includeSubdomains: true,
3470
+ preload: true,
3471
+ override: true,
3472
+ },
3473
+ contentTypeOptions: { override: true },
3474
+ frameOptions: {
3475
+ frameOption: HeadersFrameOption.DENY,
3476
+ override: true,
3477
+ },
3478
+ referrerPolicy: {
3479
+ referrerPolicy:
3480
+ HeadersReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN,
3481
+ override: true,
3482
+ },
3483
+ contentSecurityPolicy: {
3484
+ contentSecurityPolicy: CONTENT_SECURITY_POLICY,
3485
+ override: true,
3486
+ },
3487
+ },
3488
+ },
3489
+ );
3279
3490
 
3280
3491
  const defaultRootObject = 'index.html';
3281
3492
  this.cloudFrontDistribution = new Distribution(
@@ -3285,9 +3496,17 @@ export class StaticWebsite extends Construct {
3285
3496
  webAclId: wafStack.wafArn,
3286
3497
  enableLogging: true,
3287
3498
  logBucket: logBucket,
3499
+ ...(certificate
3500
+ ? {
3501
+ certificate,
3502
+ domainNames,
3503
+ minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2021,
3504
+ }
3505
+ : {}),
3288
3506
  defaultBehavior: {
3289
3507
  origin: S3BucketOrigin.withOriginAccessControl(this.websiteBucket),
3290
3508
  viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
3509
+ responseHeadersPolicy,
3291
3510
  },
3292
3511
  defaultRootObject,
3293
3512
  errorResponses: [
@@ -3304,16 +3523,28 @@ export class StaticWebsite extends Construct {
3304
3523
  ],
3305
3524
  },
3306
3525
  );
3307
- suppressRules(
3308
- this.cloudFrontDistribution,
3309
- ['CKV_AWS_174'],
3310
- 'Cloudfront default certificate does not use TLS 1.2',
3311
- );
3526
+ if (!certificate) {
3527
+ // See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
3528
+ suppressRules(
3529
+ this.cloudFrontDistribution,
3530
+ ['CKV_AWS_174'],
3531
+ 'Cloudfront default certificate does not use TLS 1.2',
3532
+ );
3533
+ }
3312
3534
 
3313
3535
  // Deploy Website
3314
3536
  this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
3537
+ sources: [Source.asset(websiteFilePath)],
3538
+ destinationBucket: this.websiteBucket,
3539
+ // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
3540
+ distribution: this.cloudFrontDistribution,
3541
+ memoryLimit: 1024,
3542
+ });
3543
+
3544
+ // Deploy runtime-config.json separately so it is never cached - clients
3545
+ // must always fetch the latest configuration.
3546
+ new BucketDeployment(this, 'RuntimeConfigDeployment', {
3315
3547
  sources: [
3316
- Source.asset(websiteFilePath),
3317
3548
  Source.data(
3318
3549
  DEFAULT_RUNTIME_CONFIG_FILENAME,
3319
3550
  Lazy.string({
@@ -3325,8 +3556,9 @@ export class StaticWebsite extends Construct {
3325
3556
  ),
3326
3557
  ],
3327
3558
  destinationBucket: this.websiteBucket,
3328
- // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
3329
3559
  distribution: this.cloudFrontDistribution,
3560
+ cacheControl: [CacheControl.noCache()],
3561
+ prune: false,
3330
3562
  memoryLimit: 1024,
3331
3563
  });
3332
3564
 
@@ -3347,6 +3579,44 @@ export class StaticWebsite extends Construct {
3347
3579
  value: this.websiteBucket.bucketName,
3348
3580
  });
3349
3581
  }
3582
+
3583
+ /**
3584
+ * Delivers a bucket's S3 server access logs to a CloudWatch log group using
3585
+ * CloudWatch Logs vended log delivery.
3586
+ */
3587
+ private deliverAccessLogsToCloudWatch(
3588
+ id: string,
3589
+ bucket: IBucket,
3590
+ logGroup: LogGroup,
3591
+ ) {
3592
+ const source: CfnDeliverySource = new CfnDeliverySource(
3593
+ this,
3594
+ \`\${id}AccessLogsSource\`,
3595
+ {
3596
+ name: Lazy.string({
3597
+ produce: () => Names.uniqueResourceName(source, { maxLength: 60 }),
3598
+ }),
3599
+ logType: 'S3_SERVER_ACCESS_LOGS',
3600
+ resourceArn: bucket.bucketArn,
3601
+ },
3602
+ );
3603
+ const destination: CfnDeliveryDestination = new CfnDeliveryDestination(
3604
+ this,
3605
+ \`\${id}AccessLogsDestination\`,
3606
+ {
3607
+ name: Lazy.string({
3608
+ produce: () =>
3609
+ Names.uniqueResourceName(destination, { maxLength: 60 }),
3610
+ }),
3611
+ destinationResourceArn: logGroup.logGroupArn,
3612
+ },
3613
+ );
3614
+ const delivery = new CfnDelivery(this, \`\${id}AccessLogsDelivery\`, {
3615
+ deliverySourceName: source.name,
3616
+ deliveryDestinationArn: destination.attrArn,
3617
+ });
3618
+ delivery.addDependency(source);
3619
+ }
3350
3620
  }
3351
3621
 
3352
3622
  export class CloudfrontWebAcl extends Stack {
@@ -3469,9 +3739,13 @@ exports[`react-website generator > Tanstack router integration > should generate
3469
3739
  "emitDeclarationOnly": false,
3470
3740
  "module": "nodenext",
3471
3741
  "moduleResolution": "nodenext",
3472
- "types": ["node"]
3742
+ "types": [
3743
+ "node"
3744
+ ]
3473
3745
  },
3474
- "include": ["src/**/*.ts"],
3746
+ "include": [
3747
+ "src/**/*.ts"
3748
+ ],
3475
3749
  "references": [],
3476
3750
  "exclude": [
3477
3751
  "vite.config.ts",
@@ -3537,6 +3811,7 @@ export default defineConfig(() => ({
3537
3811
  root: __dirname,
3538
3812
  cacheDir: '../../../node_modules/.vite/packages/common/constructs',
3539
3813
  test: {
3814
+ passWithNoTests: true,
3540
3815
  name: '@proj/common-constructs',
3541
3816
  watch: false,
3542
3817
  globals: true,
@@ -3547,7 +3822,6 @@ export default defineConfig(() => ({
3547
3822
  reportsDirectory: './test-output/vitest/coverage',
3548
3823
  provider: 'v8' as const,
3549
3824
  },
3550
- passWithNoTests: true,
3551
3825
  },
3552
3826
  }));
3553
3827
  "
@@ -3555,15 +3829,14 @@ export default defineConfig(() => ({
3555
3829
 
3556
3830
  exports[`react-website generator > Tanstack router integration > should generate website with router correctly > pnpm-workspace.yaml 1`] = `
3557
3831
  "packages:
3558
- - 'packages/*'
3559
- - 'test-app'
3560
- - 'packages/common/*'
3832
+ - "packages/*"
3833
+ - "test-app"
3834
+ - "packages/common/*"
3561
3835
  "
3562
3836
  `;
3563
3837
 
3564
3838
  exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/README.md 1`] = `
3565
3839
  "# @proj/test-app
3566
-
3567
3840
  This library was generated with [@aws/nx-plugin](https://github.com/awslabs/nx-plugin-for-aws/).
3568
3841
 
3569
3842
  ## Building
@@ -3612,24 +3885,8 @@ In order to integrate with cognito or trpc backends, you need to have a \`runtim
3612
3885
  "
3613
3886
  `;
3614
3887
 
3615
- exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/eslint.config.mjs 1`] = `
3616
- "import nx from '@nx/eslint-plugin';
3617
- import baseConfig from '../eslint.config.mjs';
3618
-
3619
- export default [
3620
- ...nx.configs['flat/react'],
3621
- ...baseConfig,
3622
- {
3623
- files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
3624
- // Override or add rules here
3625
- rules: {},
3626
- },
3627
- ];
3628
- "
3629
- `;
3630
-
3631
3888
  exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/index.html 1`] = `
3632
- "<!doctype html>
3889
+ "<!DOCTYPE html>
3633
3890
  <html lang="en">
3634
3891
  <head>
3635
3892
  <meta charset="utf-8" />
@@ -3663,29 +3920,10 @@ exports[`react-website generator > Tanstack router integration > should generate
3663
3920
  },
3664
3921
  "targets": {
3665
3922
  "build": {
3666
- "dependsOn": ["lint", "compile", "bundle", "test"],
3667
- "options": {
3668
- "outputPath": "dist/{projectRoot}/bundle"
3669
- }
3670
- },
3671
- "bundle": {
3672
- "executor": "@nx/vite:build",
3673
- "outputs": ["{options.outputPath}"],
3674
- "defaultConfiguration": "production",
3675
- "options": {
3676
- "outputPath": "dist/{projectRoot}/bundle"
3677
- },
3678
- "configurations": {
3679
- "development": {
3680
- "mode": "development"
3681
- },
3682
- "production": {
3683
- "mode": "production"
3684
- }
3685
- }
3923
+ "dependsOn": ["lint", "compile", "test", "bundle"]
3686
3924
  },
3687
3925
  "compile": {
3688
- "dependsOn": ["bundle"],
3926
+ "dependsOn": ["^build"],
3689
3927
  "executor": "nx:run-commands",
3690
3928
  "outputs": ["{workspaceRoot}/dist/{projectRoot}/tsc"],
3691
3929
  "options": {
@@ -3693,83 +3931,54 @@ exports[`react-website generator > Tanstack router integration > should generate
3693
3931
  "cwd": "{projectRoot}"
3694
3932
  }
3695
3933
  },
3696
- "lint": {
3697
- "executor": "@nx/eslint:lint",
3698
- "cache": true,
3699
- "inputs": ["eslint"],
3700
- "configurations": {
3701
- "fix": {
3702
- "fix": true
3703
- },
3704
- "skip-lint": {
3705
- "force": true
3706
- }
3707
- }
3708
- },
3709
- "load:runtime-config": {
3934
+ "dev": {
3710
3935
  "executor": "nx:run-commands",
3711
- "metadata": {
3712
- "description": "Load runtime config from your deployed stack for dev purposes. You must set your AWS CLI credentials whilst calling 'pnpm nx run @proj/test-app:load:runtime-config'"
3713
- },
3936
+ "continuous": true,
3714
3937
  "options": {
3715
- "command": "aws s3 cp s3://\`aws cloudformation describe-stacks --query \\"Stacks[?starts_with(StackName, 'proj-')][].Outputs[] | [?contains(OutputKey, 'TestAppWebsiteBucketName')].OutputValue\\" --output text\`/runtime-config.json \\"{projectRoot}/public/runtime-config.json\\""
3938
+ "command": "vite --mode local-dev",
3939
+ "cwd": "{projectRoot}"
3716
3940
  }
3717
3941
  },
3718
- "preview": {
3719
- "dependsOn": ["build"],
3720
- "executor": "@nx/vite:preview-server",
3721
- "defaultConfiguration": "development",
3942
+ "format": {
3943
+ "executor": "nx:run-commands",
3944
+ "cache": true,
3945
+ "inputs": ["biome"],
3722
3946
  "options": {
3723
- "buildTarget": "@proj/test-app:build"
3947
+ "command": "biome format {projectRoot}"
3724
3948
  },
3725
3949
  "configurations": {
3726
- "development": {
3727
- "buildTarget": "@proj/test-app:build:development"
3950
+ "fix": {
3951
+ "command": "biome format --write {projectRoot}"
3728
3952
  },
3729
- "production": {
3730
- "buildTarget": "@proj/test-app:build:production"
3953
+ "skip-lint": {
3954
+ "command": "node -e \\"\\""
3731
3955
  }
3732
3956
  }
3733
3957
  },
3734
- "serve": {
3735
- "executor": "@nx/vite:dev-server",
3736
- "defaultConfiguration": "development",
3958
+ "lint": {
3959
+ "executor": "nx:run-commands",
3960
+ "cache": true,
3961
+ "inputs": ["biome"],
3737
3962
  "options": {
3738
- "buildTarget": "@proj/test-app:build"
3963
+ "command": "biome lint {projectRoot}"
3739
3964
  },
3740
3965
  "configurations": {
3741
- "development": {
3742
- "buildTarget": "@proj/test-app:build:development",
3743
- "hmr": true
3966
+ "fix": {
3967
+ "command": "biome check --write {projectRoot}"
3744
3968
  },
3745
- "production": {
3746
- "buildTarget": "@proj/test-app:build:production",
3747
- "hmr": false
3969
+ "skip-lint": {
3970
+ "command": "node -e \\"\\""
3748
3971
  }
3749
- }
3750
- },
3751
- "serve-local": {
3752
- "executor": "@nx/vite:dev-server",
3753
- "options": {
3754
- "buildTarget": "@proj/test-app:build:development",
3755
- "hmr": true,
3756
- "mode": "serve-local"
3757
3972
  },
3758
- "continuous": true
3759
- },
3760
- "serve-static": {
3761
- "executor": "@nx/web:file-server",
3762
- "dependsOn": ["build"],
3763
- "options": {
3764
- "buildTarget": "@proj/test-app:build",
3765
- "spa": true
3766
- }
3973
+ "dependsOn": ["format"]
3767
3974
  },
3768
- "test": {
3769
- "executor": "@nx/vitest:test",
3770
- "outputs": ["{options.reportsDirectory}"],
3975
+ "load:runtime-config": {
3976
+ "executor": "nx:run-commands",
3977
+ "metadata": {
3978
+ "description": "Load runtime config from your deployed stack for dev purposes. You must set your AWS CLI credentials whilst calling 'pnpm nx run @proj/test-app:load:runtime-config'"
3979
+ },
3771
3980
  "options": {
3772
- "reportsDirectory": "{workspaceRoot}/coverage/{projectRoot}"
3981
+ "command": "aws s3 cp s3://\`aws cloudformation describe-stacks --query \\"Stacks[?starts_with(StackName, 'proj-')][].Outputs[] | [?contains(OutputKey, 'TestAppWebsiteBucketName')].OutputValue\\" --output text\`/runtime-config.json \\"{projectRoot}/public/runtime-config.json\\""
3773
3982
  }
3774
3983
  }
3775
3984
  }
@@ -4161,15 +4370,22 @@ exports[`react-website generator > Tanstack router integration > should generate
4161
4370
  "outDir": "../dist/test-app/tsc",
4162
4371
  "tsBuildInfoFile": "../dist/test-app/tsc/tsconfig.lib.tsbuildinfo",
4163
4372
  "jsx": "react-jsx",
4164
- "lib": ["DOM"],
4373
+ "lib": [
4374
+ "DOM"
4375
+ ],
4165
4376
  "types": [
4166
4377
  "node",
4167
4378
  "@nx/react/typings/cssmodule.d.ts",
4168
4379
  "@nx/react/typings/image.d.ts",
4169
4380
  "vite/client"
4170
- ]
4381
+ ],
4382
+ "rootDir": "src",
4383
+ "module": "esnext",
4384
+ "moduleResolution": "bundler"
4171
4385
  },
4172
4386
  "exclude": [
4387
+ "out-tsc",
4388
+ "dist",
4173
4389
  "src/**/*.spec.ts",
4174
4390
  "src/**/*.test.ts",
4175
4391
  "src/**/*.spec.tsx",
@@ -4183,7 +4399,12 @@ exports[`react-website generator > Tanstack router integration > should generate
4183
4399
  "vitest.config.ts",
4184
4400
  "vitest.config.mts"
4185
4401
  ],
4186
- "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
4402
+ "include": [
4403
+ "src/**/*.js",
4404
+ "src/**/*.jsx",
4405
+ "src/**/*.ts",
4406
+ "src/**/*.tsx"
4407
+ ]
4187
4408
  }
4188
4409
  "
4189
4410
  `;
@@ -4222,7 +4443,10 @@ exports[`react-website generator > Tanstack router integration > should generate
4222
4443
  "vitest",
4223
4444
  "@nx/react/typings/cssmodule.d.ts",
4224
4445
  "@nx/react/typings/image.d.ts"
4225
- ]
4446
+ ],
4447
+ "jsx": "react-jsx",
4448
+ "module": "esnext",
4449
+ "moduleResolution": "bundler"
4226
4450
  },
4227
4451
  "include": [
4228
4452
  "vite.config.ts",
@@ -4280,7 +4504,7 @@ export default defineConfig(() => ({
4280
4504
  // plugins: [],
4281
4505
  // },
4282
4506
  build: {
4283
- outDir: '../dist/test-app',
4507
+ outDir: '../dist/test-app/bundle',
4284
4508
  emptyOutDir: true,
4285
4509
  reportCompressedSize: true,
4286
4510
  commonjsOptions: {
@@ -4288,6 +4512,7 @@ export default defineConfig(() => ({
4288
4512
  },
4289
4513
  },
4290
4514
  test: {
4515
+ passWithNoTests: true,
4291
4516
  name: '@proj/test-app',
4292
4517
  watch: false,
4293
4518
  globals: true,
@@ -4298,7 +4523,6 @@ export default defineConfig(() => ({
4298
4523
  reportsDirectory: './test-output/vitest/coverage',
4299
4524
  provider: 'v8' as const,
4300
4525
  },
4301
- passWithNoTests: true,
4302
4526
  },
4303
4527
  resolve: { tsconfigPaths: true },
4304
4528
  define: { global: {} },
@@ -4310,9 +4534,14 @@ exports[`react-website generator > Tanstack router integration > should generate
4310
4534
  "{
4311
4535
  "compilerOptions": {
4312
4536
  "paths": {
4313
- ":proj/test-app": ["./test-app/src/index.ts"],
4314
- ":proj/common-constructs": ["./packages/common/constructs/src/index.ts"]
4537
+ ":proj/test-app": [
4538
+ "./test-app/src/index.ts"
4539
+ ],
4540
+ ":proj/common-constructs": [
4541
+ "./packages/common/constructs/src/index.ts"
4542
+ ]
4315
4543
  },
4544
+ "composite": true,
4316
4545
  "rootDir": "."
4317
4546
  }
4318
4547
  }
@@ -4321,6 +4550,9 @@ exports[`react-website generator > Tanstack router integration > should generate
4321
4550
 
4322
4551
  exports[`react-website generator > Tanstack router integration > should generate website with router correctly > tsconfig.json 1`] = `
4323
4552
  "{
4553
+ "extends": "./tsconfig.base.json",
4554
+ "files": [],
4555
+ "include": [],
4324
4556
  "references": [
4325
4557
  {
4326
4558
  "path": "./test-app"
@@ -4393,7 +4625,7 @@ export default defineConfig(() => ({
4393
4625
  // plugins: [],
4394
4626
  // },
4395
4627
  build: {
4396
- outDir: '../dist/test-app',
4628
+ outDir: '../dist/test-app/bundle',
4397
4629
  emptyOutDir: true,
4398
4630
  reportCompressedSize: true,
4399
4631
  commonjsOptions: {
@@ -4401,6 +4633,7 @@ export default defineConfig(() => ({
4401
4633
  },
4402
4634
  },
4403
4635
  test: {
4636
+ passWithNoTests: true,
4404
4637
  name: '@proj/test-app',
4405
4638
  watch: false,
4406
4639
  globals: true,
@@ -4411,7 +4644,6 @@ export default defineConfig(() => ({
4411
4644
  reportsDirectory: './test-output/vitest/coverage',
4412
4645
  provider: 'v8' as const,
4413
4646
  },
4414
- passWithNoTests: true,
4415
4647
  },
4416
4648
  resolve: { tsconfigPaths: true },
4417
4649
  define: { global: {} },
@@ -4667,11 +4899,21 @@ exports[`react-website generator > should generate shared constructs > common/co
4667
4899
  "import {
4668
4900
  CfnOutput,
4669
4901
  CfnResource,
4902
+ Duration,
4670
4903
  Lazy,
4904
+ Names,
4671
4905
  RemovalPolicy,
4672
4906
  Stack,
4673
4907
  } from 'aws-cdk-lib';
4674
- import { Distribution, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
4908
+ import {
4909
+ Distribution,
4910
+ HeadersFrameOption,
4911
+ HeadersReferrerPolicy,
4912
+ ResponseHeadersPolicy,
4913
+ SecurityPolicyProtocol,
4914
+ ViewerProtocolPolicy,
4915
+ } from 'aws-cdk-lib/aws-cloudfront';
4916
+ import { ICertificate } from 'aws-cdk-lib/aws-certificatemanager';
4675
4917
  import { S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
4676
4918
  import {
4677
4919
  BlockPublicAccess,
@@ -4680,18 +4922,56 @@ import {
4680
4922
  IBucket,
4681
4923
  ObjectOwnership,
4682
4924
  } from 'aws-cdk-lib/aws-s3';
4683
- import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment';
4925
+ import {
4926
+ BucketDeployment,
4927
+ CacheControl,
4928
+ Source,
4929
+ } from 'aws-cdk-lib/aws-s3-deployment';
4684
4930
  import { Construct } from 'constructs';
4685
4931
  import { RuntimeConfig } from './runtime-config.js';
4686
4932
  import { Key } from 'aws-cdk-lib/aws-kms';
4933
+ import {
4934
+ CfnDelivery,
4935
+ CfnDeliveryDestination,
4936
+ CfnDeliverySource,
4937
+ LogGroup,
4938
+ RetentionDays,
4939
+ } from 'aws-cdk-lib/aws-logs';
4940
+ import { Effect, PolicyStatement, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
4687
4941
  import { CfnWebACL } from 'aws-cdk-lib/aws-wafv2';
4688
4942
  import { suppressRules } from './checkov.js';
4689
4943
 
4690
4944
  const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';
4691
4945
 
4946
+ // Content-Security-Policy enforced on all responses. Restricts scripts and
4947
+ // framing to mitigate XSS and clickjacking, while permitting HTTPS/WSS calls
4948
+ // (connect-src) to AWS service endpoints such as API Gateway, Cognito and
4949
+ // Bedrock AgentCore which are only known at deploy time. Edit this to tighten
4950
+ // connect-src to your specific origins once they are known.
4951
+ const CONTENT_SECURITY_POLICY = [
4952
+ "default-src 'self'",
4953
+ "script-src 'self'",
4954
+ "style-src 'self' 'unsafe-inline'",
4955
+ "img-src 'self' data:",
4956
+ "font-src 'self' data:",
4957
+ "connect-src 'self' https: wss:",
4958
+ "object-src 'none'",
4959
+ "base-uri 'self'",
4960
+ "frame-ancestors 'none'",
4961
+ ].join('; ');
4962
+
4692
4963
  export interface StaticWebsiteProps {
4693
4964
  readonly websiteName: string;
4694
4965
  readonly websiteFilePath: string;
4966
+ /**
4967
+ * Custom domain names for the CloudFront distribution. Requires \`certificate\`.
4968
+ */
4969
+ readonly domainNames?: string[];
4970
+ /**
4971
+ * ACM certificate for the custom domain names. Must be in us-east-1.
4972
+ * When provided, viewers are required to use TLS 1.2 or later.
4973
+ */
4974
+ readonly certificate?: ICertificate;
4695
4975
  }
4696
4976
 
4697
4977
  /**
@@ -4710,39 +4990,48 @@ export class StaticWebsite extends Construct {
4710
4990
  constructor(
4711
4991
  scope: Construct,
4712
4992
  id: string,
4713
- { websiteFilePath, websiteName }: StaticWebsiteProps,
4993
+ {
4994
+ websiteFilePath,
4995
+ websiteName,
4996
+ domainNames,
4997
+ certificate,
4998
+ }: StaticWebsiteProps,
4714
4999
  ) {
4715
5000
  super(scope, id);
4716
- this.node.setContext(
4717
- '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy',
4718
- true,
4719
- );
4720
5001
 
4721
5002
  const websiteKey = new Key(this, 'WebsiteKey', {
4722
5003
  enableKeyRotation: true,
4723
5004
  });
4724
5005
 
4725
- const accessLogsBucket = new Bucket(this, 'AccessLogsBucket', {
4726
- versioned: false,
4727
- enforceSSL: true,
4728
- autoDeleteObjects: true,
4729
- removalPolicy: RemovalPolicy.DESTROY,
4730
- encryption: BucketEncryption.KMS,
5006
+ // Allow CloudWatch Logs to use the website key for server access log delivery.
5007
+ const stack = Stack.of(this);
5008
+ websiteKey.addToResourcePolicy(
5009
+ new PolicyStatement({
5010
+ effect: Effect.ALLOW,
5011
+ principals: [
5012
+ new ServicePrincipal(\`logs.\${stack.region}.amazonaws.com\`),
5013
+ ],
5014
+ actions: [
5015
+ 'kms:Encrypt',
5016
+ 'kms:Decrypt',
5017
+ 'kms:ReEncrypt*',
5018
+ 'kms:GenerateDataKey*',
5019
+ 'kms:DescribeKey',
5020
+ ],
5021
+ resources: ['*'],
5022
+ conditions: {
5023
+ ArnLike: {
5024
+ 'kms:EncryptionContext:aws:logs:arn': \`arn:aws:logs:\${stack.region}:\${stack.account}:log-group:*\`,
5025
+ },
5026
+ },
5027
+ }),
5028
+ );
5029
+
5030
+ const accessLogs = new LogGroup(this, 'AccessLogs', {
5031
+ retention: RetentionDays.ONE_YEAR,
4731
5032
  encryptionKey: websiteKey,
4732
- objectOwnership: ObjectOwnership.OBJECT_WRITER,
4733
- publicReadAccess: false,
4734
- blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
5033
+ removalPolicy: RemovalPolicy.DESTROY,
4735
5034
  });
4736
- suppressRules(
4737
- accessLogsBucket,
4738
- ['CKV_AWS_21'],
4739
- 'Access log bucket does not need versioning enabled',
4740
- );
4741
- suppressRules(
4742
- accessLogsBucket,
4743
- ['CKV_AWS_18'],
4744
- 'Access log bucket does not need an access log bucket',
4745
- );
4746
5035
 
4747
5036
  // S3 Bucket to hold website files
4748
5037
  this.websiteBucket = new Bucket(this, 'WebsiteBucket', {
@@ -4755,13 +5044,23 @@ export class StaticWebsite extends Construct {
4755
5044
  objectOwnership: ObjectOwnership.BUCKET_OWNER_ENFORCED,
4756
5045
  publicReadAccess: false,
4757
5046
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
4758
- serverAccessLogsPrefix: 'website-access-logs',
4759
- serverAccessLogsBucket: accessLogsBucket,
4760
5047
  });
5048
+ suppressRules(
5049
+ this.websiteBucket,
5050
+ ['CKV_AWS_18'],
5051
+ 'Server access logs are delivered to CloudWatch Logs',
5052
+ );
5053
+ this.deliverAccessLogsToCloudWatch(
5054
+ 'Website',
5055
+ this.websiteBucket,
5056
+ accessLogs,
5057
+ );
4761
5058
  // Web ACL
4762
5059
  const wafStack = new CloudfrontWebAcl(this, 'waf');
4763
5060
 
4764
- // Cloudfront Distribution
5061
+ // Bucket holding CloudFront standard access logs. CloudFront delivers its
5062
+ // own logs to S3 only, so this bucket is retained; its S3 server access
5063
+ // logs are delivered to CloudWatch Logs.
4765
5064
  const logBucket = new Bucket(this, 'DistributionLogBucket', {
4766
5065
  enforceSSL: true,
4767
5066
  autoDeleteObjects: true,
@@ -4771,14 +5070,48 @@ export class StaticWebsite extends Construct {
4771
5070
  objectOwnership: ObjectOwnership.BUCKET_OWNER_PREFERRED,
4772
5071
  publicReadAccess: false,
4773
5072
  blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
4774
- serverAccessLogsPrefix: 'distribution-access-logs',
4775
- serverAccessLogsBucket: accessLogsBucket,
4776
5073
  });
4777
5074
  suppressRules(
4778
5075
  logBucket,
4779
5076
  ['CKV_AWS_21'],
4780
5077
  'Distribution log bucket does not need versioning enabled',
4781
5078
  );
5079
+ suppressRules(
5080
+ logBucket,
5081
+ ['CKV_AWS_18'],
5082
+ 'Server access logs are delivered to CloudWatch Logs',
5083
+ );
5084
+ this.deliverAccessLogsToCloudWatch('Distribution', logBucket, accessLogs);
5085
+
5086
+ // Security headers applied to all responses.
5087
+ const responseHeadersPolicy = new ResponseHeadersPolicy(
5088
+ this,
5089
+ 'ResponseHeadersPolicy',
5090
+ {
5091
+ securityHeadersBehavior: {
5092
+ strictTransportSecurity: {
5093
+ accessControlMaxAge: Duration.days(730),
5094
+ includeSubdomains: true,
5095
+ preload: true,
5096
+ override: true,
5097
+ },
5098
+ contentTypeOptions: { override: true },
5099
+ frameOptions: {
5100
+ frameOption: HeadersFrameOption.DENY,
5101
+ override: true,
5102
+ },
5103
+ referrerPolicy: {
5104
+ referrerPolicy:
5105
+ HeadersReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN,
5106
+ override: true,
5107
+ },
5108
+ contentSecurityPolicy: {
5109
+ contentSecurityPolicy: CONTENT_SECURITY_POLICY,
5110
+ override: true,
5111
+ },
5112
+ },
5113
+ },
5114
+ );
4782
5115
 
4783
5116
  const defaultRootObject = 'index.html';
4784
5117
  this.cloudFrontDistribution = new Distribution(
@@ -4788,9 +5121,17 @@ export class StaticWebsite extends Construct {
4788
5121
  webAclId: wafStack.wafArn,
4789
5122
  enableLogging: true,
4790
5123
  logBucket: logBucket,
5124
+ ...(certificate
5125
+ ? {
5126
+ certificate,
5127
+ domainNames,
5128
+ minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2021,
5129
+ }
5130
+ : {}),
4791
5131
  defaultBehavior: {
4792
5132
  origin: S3BucketOrigin.withOriginAccessControl(this.websiteBucket),
4793
5133
  viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
5134
+ responseHeadersPolicy,
4794
5135
  },
4795
5136
  defaultRootObject,
4796
5137
  errorResponses: [
@@ -4807,16 +5148,28 @@ export class StaticWebsite extends Construct {
4807
5148
  ],
4808
5149
  },
4809
5150
  );
4810
- suppressRules(
4811
- this.cloudFrontDistribution,
4812
- ['CKV_AWS_174'],
4813
- 'Cloudfront default certificate does not use TLS 1.2',
4814
- );
5151
+ if (!certificate) {
5152
+ // See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
5153
+ suppressRules(
5154
+ this.cloudFrontDistribution,
5155
+ ['CKV_AWS_174'],
5156
+ 'Cloudfront default certificate does not use TLS 1.2',
5157
+ );
5158
+ }
4815
5159
 
4816
5160
  // Deploy Website
4817
5161
  this.bucketDeployment = new BucketDeployment(this, 'WebsiteDeployment', {
5162
+ sources: [Source.asset(websiteFilePath)],
5163
+ destinationBucket: this.websiteBucket,
5164
+ // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
5165
+ distribution: this.cloudFrontDistribution,
5166
+ memoryLimit: 1024,
5167
+ });
5168
+
5169
+ // Deploy runtime-config.json separately so it is never cached - clients
5170
+ // must always fetch the latest configuration.
5171
+ new BucketDeployment(this, 'RuntimeConfigDeployment', {
4818
5172
  sources: [
4819
- Source.asset(websiteFilePath),
4820
5173
  Source.data(
4821
5174
  DEFAULT_RUNTIME_CONFIG_FILENAME,
4822
5175
  Lazy.string({
@@ -4828,8 +5181,9 @@ export class StaticWebsite extends Construct {
4828
5181
  ),
4829
5182
  ],
4830
5183
  destinationBucket: this.websiteBucket,
4831
- // Files in the distribution's edge caches will be invalidated after files are uploaded to the destination bucket.
4832
5184
  distribution: this.cloudFrontDistribution,
5185
+ cacheControl: [CacheControl.noCache()],
5186
+ prune: false,
4833
5187
  memoryLimit: 1024,
4834
5188
  });
4835
5189
 
@@ -4850,6 +5204,44 @@ export class StaticWebsite extends Construct {
4850
5204
  value: this.websiteBucket.bucketName,
4851
5205
  });
4852
5206
  }
5207
+
5208
+ /**
5209
+ * Delivers a bucket's S3 server access logs to a CloudWatch log group using
5210
+ * CloudWatch Logs vended log delivery.
5211
+ */
5212
+ private deliverAccessLogsToCloudWatch(
5213
+ id: string,
5214
+ bucket: IBucket,
5215
+ logGroup: LogGroup,
5216
+ ) {
5217
+ const source: CfnDeliverySource = new CfnDeliverySource(
5218
+ this,
5219
+ \`\${id}AccessLogsSource\`,
5220
+ {
5221
+ name: Lazy.string({
5222
+ produce: () => Names.uniqueResourceName(source, { maxLength: 60 }),
5223
+ }),
5224
+ logType: 'S3_SERVER_ACCESS_LOGS',
5225
+ resourceArn: bucket.bucketArn,
5226
+ },
5227
+ );
5228
+ const destination: CfnDeliveryDestination = new CfnDeliveryDestination(
5229
+ this,
5230
+ \`\${id}AccessLogsDestination\`,
5231
+ {
5232
+ name: Lazy.string({
5233
+ produce: () =>
5234
+ Names.uniqueResourceName(destination, { maxLength: 60 }),
5235
+ }),
5236
+ destinationResourceArn: logGroup.logGroupArn,
5237
+ },
5238
+ );
5239
+ const delivery = new CfnDelivery(this, \`\${id}AccessLogsDelivery\`, {
5240
+ deliverySourceName: source.name,
5241
+ deliveryDestinationArn: destination.attrArn,
5242
+ });
5243
+ delivery.addDependency(source);
5244
+ }
4853
5245
  }
4854
5246
 
4855
5247
  export class CloudfrontWebAcl extends Stack {
@@ -4975,15 +5367,15 @@ root &&
4975
5367
 
4976
5368
  exports[`react-website generator > should handle npm scope prefix correctly > scoped-dependencies 1`] = `
4977
5369
  {
4978
- "@cloudscape-design/board-components": "3.0.187",
4979
- "@cloudscape-design/components": "3.0.1304",
4980
- "@cloudscape-design/global-styles": "1.0.59",
4981
- "@tanstack/react-router": "1.170.10",
4982
- "aws-cdk-lib": "2.257.0",
5370
+ "@cloudscape-design/board-components": "3.0.201",
5371
+ "@cloudscape-design/components": "3.0.1325",
5372
+ "@cloudscape-design/global-styles": "1.0.62",
5373
+ "@tanstack/react-router": "1.170.17",
5374
+ "aws-cdk-lib": "2.261.0",
4983
5375
  "constructs": "10.6.0",
4984
5376
  "react": "19.2.7",
4985
5377
  "react-dom": "19.2.7",
4986
- "tailwindcss": "4.3.0",
5378
+ "tailwindcss": "4.3.2",
4987
5379
  }
4988
5380
  `;
4989
5381
 
@@ -5687,6 +6079,5 @@ function RouteComponent() {
5687
6079
 
5688
6080
  exports[`react-website generator ux tests > Shadcn > should update package.json with required dependencies > test-app/src/styles.css 1`] = `
5689
6081
  "@import '../../packages/common/shadcn/src/styles/globals.css';
5690
- @source './**/*.{ts,tsx}';
5691
- "
6082
+ @source './**/*.{ts,tsx}';"
5692
6083
  `;