@aws-blocks/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (394) hide show
  1. package/LICENSE +174 -0
  2. package/dist/api.d.ts +147 -0
  3. package/dist/api.d.ts.map +1 -0
  4. package/dist/api.js +10 -0
  5. package/dist/api.test.d.ts +2 -0
  6. package/dist/api.test.d.ts.map +1 -0
  7. package/dist/api.test.js +19 -0
  8. package/dist/bb-utils.d.ts +11 -0
  9. package/dist/bb-utils.d.ts.map +1 -0
  10. package/dist/bb-utils.js +12 -0
  11. package/dist/builtin-routes.d.ts +6 -0
  12. package/dist/builtin-routes.d.ts.map +1 -0
  13. package/dist/builtin-routes.js +57 -0
  14. package/dist/cdk/__fixtures__/factory-backend.d.ts +3 -0
  15. package/dist/cdk/__fixtures__/factory-backend.d.ts.map +1 -0
  16. package/dist/cdk/__fixtures__/factory-backend.js +6 -0
  17. package/dist/cdk/__fixtures__/fullid-construct-backend.d.ts +2 -0
  18. package/dist/cdk/__fixtures__/fullid-construct-backend.d.ts.map +1 -0
  19. package/dist/cdk/__fixtures__/fullid-construct-backend.js +37 -0
  20. package/dist/cdk/__fixtures__/handler.d.ts +5 -0
  21. package/dist/cdk/__fixtures__/handler.d.ts.map +1 -0
  22. package/dist/cdk/__fixtures__/handler.js +3 -0
  23. package/dist/cdk/__fixtures__/side-effect-backend.d.ts +2 -0
  24. package/dist/cdk/__fixtures__/side-effect-backend.d.ts.map +1 -0
  25. package/dist/cdk/__fixtures__/side-effect-backend.js +5 -0
  26. package/dist/cdk/blocks-backend.d.ts +68 -0
  27. package/dist/cdk/blocks-backend.d.ts.map +1 -0
  28. package/dist/cdk/blocks-backend.js +214 -0
  29. package/dist/cdk/blocks-backend.test.d.ts +2 -0
  30. package/dist/cdk/blocks-backend.test.d.ts.map +1 -0
  31. package/dist/cdk/blocks-backend.test.js +151 -0
  32. package/dist/cdk/blocks-stack.test.d.ts +2 -0
  33. package/dist/cdk/blocks-stack.test.d.ts.map +1 -0
  34. package/dist/cdk/blocks-stack.test.js +78 -0
  35. package/dist/cdk/config-registry.d.ts +26 -0
  36. package/dist/cdk/config-registry.d.ts.map +1 -0
  37. package/dist/cdk/config-registry.js +80 -0
  38. package/dist/cdk/index.d.ts +35 -0
  39. package/dist/cdk/index.d.ts.map +1 -0
  40. package/dist/cdk/index.js +90 -0
  41. package/dist/cdk/mixins.d.ts +28 -0
  42. package/dist/cdk/mixins.d.ts.map +1 -0
  43. package/dist/cdk/mixins.js +37 -0
  44. package/dist/cdk/mixins.test.d.ts +2 -0
  45. package/dist/cdk/mixins.test.d.ts.map +1 -0
  46. package/dist/cdk/mixins.test.js +108 -0
  47. package/dist/cdk/node-version.d.ts +14 -0
  48. package/dist/cdk/node-version.d.ts.map +1 -0
  49. package/dist/cdk/node-version.js +15 -0
  50. package/dist/cdk/stack-metadata.d.ts +12 -0
  51. package/dist/cdk/stack-metadata.d.ts.map +1 -0
  52. package/dist/cdk/stack-metadata.js +22 -0
  53. package/dist/cdk/stack-metadata.test.d.ts +2 -0
  54. package/dist/cdk/stack-metadata.test.d.ts.map +1 -0
  55. package/dist/cdk/stack-metadata.test.js +56 -0
  56. package/dist/cdk/synth-guard.d.ts +14 -0
  57. package/dist/cdk/synth-guard.d.ts.map +1 -0
  58. package/dist/cdk/synth-guard.js +20 -0
  59. package/dist/cdk/synth-guard.test.d.ts +2 -0
  60. package/dist/cdk/synth-guard.test.d.ts.map +1 -0
  61. package/dist/cdk/synth-guard.test.js +15 -0
  62. package/dist/client/index.d.ts +97 -0
  63. package/dist/client/index.d.ts.map +1 -0
  64. package/dist/client/index.js +238 -0
  65. package/dist/client/index.test.d.ts +2 -0
  66. package/dist/client/index.test.d.ts.map +1 -0
  67. package/dist/client/index.test.js +113 -0
  68. package/dist/common/config.d.ts +45 -0
  69. package/dist/common/config.d.ts.map +1 -0
  70. package/dist/common/config.js +154 -0
  71. package/dist/common/config.test.d.ts +2 -0
  72. package/dist/common/config.test.d.ts.map +1 -0
  73. package/dist/common/config.test.js +173 -0
  74. package/dist/common/constants.d.ts +11 -0
  75. package/dist/common/constants.d.ts.map +1 -0
  76. package/dist/common/constants.js +12 -0
  77. package/dist/common/crypto.d.ts +6 -0
  78. package/dist/common/crypto.d.ts.map +1 -0
  79. package/dist/common/crypto.js +14 -0
  80. package/dist/common/index.d.ts +220 -0
  81. package/dist/common/index.d.ts.map +1 -0
  82. package/dist/common/index.js +180 -0
  83. package/dist/common/index.test.d.ts +2 -0
  84. package/dist/common/index.test.d.ts.map +1 -0
  85. package/dist/common/index.test.js +195 -0
  86. package/dist/common/mock-data.d.ts +40 -0
  87. package/dist/common/mock-data.d.ts.map +1 -0
  88. package/dist/common/mock-data.js +39 -0
  89. package/dist/common/official-bb-names.generated.d.ts +7 -0
  90. package/dist/common/official-bb-names.generated.d.ts.map +1 -0
  91. package/dist/common/official-bb-names.generated.js +28 -0
  92. package/dist/common/sdk-registry.d.ts +136 -0
  93. package/dist/common/sdk-registry.d.ts.map +1 -0
  94. package/dist/common/sdk-registry.js +125 -0
  95. package/dist/constants.d.ts +27 -0
  96. package/dist/constants.d.ts.map +1 -0
  97. package/dist/constants.js +28 -0
  98. package/dist/cors.d.ts +39 -0
  99. package/dist/cors.d.ts.map +1 -0
  100. package/dist/cors.js +85 -0
  101. package/dist/cors.test.d.ts +2 -0
  102. package/dist/cors.test.d.ts.map +1 -0
  103. package/dist/cors.test.js +241 -0
  104. package/dist/db-naming.d.ts +21 -0
  105. package/dist/db-naming.d.ts.map +1 -0
  106. package/dist/db-naming.js +38 -0
  107. package/dist/db-naming.test.d.ts +2 -0
  108. package/dist/db-naming.test.d.ts.map +1 -0
  109. package/dist/db-naming.test.js +29 -0
  110. package/dist/errors.d.ts +67 -0
  111. package/dist/errors.d.ts.map +1 -0
  112. package/dist/errors.js +69 -0
  113. package/dist/hosting.d.ts +258 -0
  114. package/dist/hosting.d.ts.map +1 -0
  115. package/dist/hosting.js +340 -0
  116. package/dist/hosting.test.d.ts +2 -0
  117. package/dist/hosting.test.d.ts.map +1 -0
  118. package/dist/hosting.test.js +1077 -0
  119. package/dist/index.cdk.d.ts +13 -0
  120. package/dist/index.cdk.d.ts.map +1 -0
  121. package/dist/index.cdk.js +13 -0
  122. package/dist/index.d.ts +9 -0
  123. package/dist/index.d.ts.map +1 -0
  124. package/dist/index.js +10 -0
  125. package/dist/lambda-handler.d.ts +131 -0
  126. package/dist/lambda-handler.d.ts.map +1 -0
  127. package/dist/lambda-handler.js +610 -0
  128. package/dist/lambda-handler.test.d.ts +2 -0
  129. package/dist/lambda-handler.test.d.ts.map +1 -0
  130. package/dist/lambda-handler.test.js +835 -0
  131. package/dist/pipeline/index.d.ts +4 -0
  132. package/dist/pipeline/index.d.ts.map +1 -0
  133. package/dist/pipeline/index.js +3 -0
  134. package/dist/pipeline/pipeline-construct.d.ts +130 -0
  135. package/dist/pipeline/pipeline-construct.d.ts.map +1 -0
  136. package/dist/pipeline/pipeline-construct.js +484 -0
  137. package/dist/pipeline/pipeline.test.d.ts +2 -0
  138. package/dist/pipeline/pipeline.test.d.ts.map +1 -0
  139. package/dist/pipeline/pipeline.test.js +1231 -0
  140. package/dist/pipeline/types.d.ts +351 -0
  141. package/dist/pipeline/types.d.ts.map +1 -0
  142. package/dist/pipeline/types.js +3 -0
  143. package/dist/raw-route.cdk.d.ts +47 -0
  144. package/dist/raw-route.cdk.d.ts.map +1 -0
  145. package/dist/raw-route.cdk.js +51 -0
  146. package/dist/raw-route.d.ts +119 -0
  147. package/dist/raw-route.d.ts.map +1 -0
  148. package/dist/raw-route.js +239 -0
  149. package/dist/raw-route.mock.d.ts +47 -0
  150. package/dist/raw-route.mock.d.ts.map +1 -0
  151. package/dist/raw-route.mock.js +51 -0
  152. package/dist/raw-route.test.d.ts +2 -0
  153. package/dist/raw-route.test.d.ts.map +1 -0
  154. package/dist/raw-route.test.js +597 -0
  155. package/dist/redact.d.ts +51 -0
  156. package/dist/redact.d.ts.map +1 -0
  157. package/dist/redact.js +134 -0
  158. package/dist/redact.test.d.ts +2 -0
  159. package/dist/redact.test.d.ts.map +1 -0
  160. package/dist/redact.test.js +199 -0
  161. package/dist/rpc.d.ts +54 -0
  162. package/dist/rpc.d.ts.map +1 -0
  163. package/dist/rpc.js +127 -0
  164. package/dist/rpc.test.d.ts +2 -0
  165. package/dist/rpc.test.d.ts.map +1 -0
  166. package/dist/rpc.test.js +60 -0
  167. package/dist/scripts/cdk-telemetry-env.d.ts +13 -0
  168. package/dist/scripts/cdk-telemetry-env.d.ts.map +1 -0
  169. package/dist/scripts/cdk-telemetry-env.js +21 -0
  170. package/dist/scripts/cdk-telemetry-env.test.d.ts +2 -0
  171. package/dist/scripts/cdk-telemetry-env.test.d.ts.map +1 -0
  172. package/dist/scripts/cdk-telemetry-env.test.js +56 -0
  173. package/dist/scripts/cleanup.d.ts +3 -0
  174. package/dist/scripts/cleanup.d.ts.map +1 -0
  175. package/dist/scripts/cleanup.js +35 -0
  176. package/dist/scripts/console.d.ts +6 -0
  177. package/dist/scripts/console.d.ts.map +1 -0
  178. package/dist/scripts/console.js +25 -0
  179. package/dist/scripts/deploy.d.ts +6 -0
  180. package/dist/scripts/deploy.d.ts.map +1 -0
  181. package/dist/scripts/deploy.js +82 -0
  182. package/dist/scripts/destroy.d.ts +6 -0
  183. package/dist/scripts/destroy.d.ts.map +1 -0
  184. package/dist/scripts/destroy.js +30 -0
  185. package/dist/scripts/dev-server-cors.test.d.ts +2 -0
  186. package/dist/scripts/dev-server-cors.test.d.ts.map +1 -0
  187. package/dist/scripts/dev-server-cors.test.js +23 -0
  188. package/dist/scripts/dev-server-telemetry.test.d.ts +2 -0
  189. package/dist/scripts/dev-server-telemetry.test.d.ts.map +1 -0
  190. package/dist/scripts/dev-server-telemetry.test.js +113 -0
  191. package/dist/scripts/dev-server.d.ts +21 -0
  192. package/dist/scripts/dev-server.d.ts.map +1 -0
  193. package/dist/scripts/dev-server.js +456 -0
  194. package/dist/scripts/ensure-secrets.d.ts +31 -0
  195. package/dist/scripts/ensure-secrets.d.ts.map +1 -0
  196. package/dist/scripts/ensure-secrets.js +100 -0
  197. package/dist/scripts/ensure-secrets.test.d.ts +2 -0
  198. package/dist/scripts/ensure-secrets.test.d.ts.map +1 -0
  199. package/dist/scripts/ensure-secrets.test.js +44 -0
  200. package/dist/scripts/external-migrations-step.d.ts +62 -0
  201. package/dist/scripts/external-migrations-step.d.ts.map +1 -0
  202. package/dist/scripts/external-migrations-step.js +243 -0
  203. package/dist/scripts/external-migrations-step.test.d.ts +2 -0
  204. package/dist/scripts/external-migrations-step.test.d.ts.map +1 -0
  205. package/dist/scripts/external-migrations-step.test.js +47 -0
  206. package/dist/scripts/extract-ts-types.d.ts +65 -0
  207. package/dist/scripts/extract-ts-types.d.ts.map +1 -0
  208. package/dist/scripts/extract-ts-types.js +664 -0
  209. package/dist/scripts/extract-ts-types.test.d.ts +2 -0
  210. package/dist/scripts/extract-ts-types.test.d.ts.map +1 -0
  211. package/dist/scripts/extract-ts-types.test.js +497 -0
  212. package/dist/scripts/generate-client-worker.d.ts +2 -0
  213. package/dist/scripts/generate-client-worker.d.ts.map +1 -0
  214. package/dist/scripts/generate-client-worker.js +13 -0
  215. package/dist/scripts/generate-client.d.ts +14 -0
  216. package/dist/scripts/generate-client.d.ts.map +1 -0
  217. package/dist/scripts/generate-client.js +73 -0
  218. package/dist/scripts/generate-client.test.d.ts +2 -0
  219. package/dist/scripts/generate-client.test.d.ts.map +1 -0
  220. package/dist/scripts/generate-client.test.js +48 -0
  221. package/dist/scripts/generate-spec-cli.d.ts +3 -0
  222. package/dist/scripts/generate-spec-cli.d.ts.map +1 -0
  223. package/dist/scripts/generate-spec-cli.js +77 -0
  224. package/dist/scripts/generate-spec-cli.test.d.ts +14 -0
  225. package/dist/scripts/generate-spec-cli.test.d.ts.map +1 -0
  226. package/dist/scripts/generate-spec-cli.test.js +90 -0
  227. package/dist/scripts/generate-spec.d.ts +61 -0
  228. package/dist/scripts/generate-spec.d.ts.map +1 -0
  229. package/dist/scripts/generate-spec.js +746 -0
  230. package/dist/scripts/generate-spec.test.d.ts +12 -0
  231. package/dist/scripts/generate-spec.test.d.ts.map +1 -0
  232. package/dist/scripts/generate-spec.test.js +88 -0
  233. package/dist/scripts/index.d.ts +12 -0
  234. package/dist/scripts/index.d.ts.map +1 -0
  235. package/dist/scripts/index.js +13 -0
  236. package/dist/scripts/sandbox.d.ts +11 -0
  237. package/dist/scripts/sandbox.d.ts.map +1 -0
  238. package/dist/scripts/sandbox.js +200 -0
  239. package/dist/scripts/telemetry-cli.d.ts +3 -0
  240. package/dist/scripts/telemetry-cli.d.ts.map +1 -0
  241. package/dist/scripts/telemetry-cli.js +8 -0
  242. package/dist/scripts/telemetry.d.ts +17 -0
  243. package/dist/scripts/telemetry.d.ts.map +1 -0
  244. package/dist/scripts/telemetry.js +150 -0
  245. package/dist/scripts/telemetry.test.d.ts +2 -0
  246. package/dist/scripts/telemetry.test.d.ts.map +1 -0
  247. package/dist/scripts/telemetry.test.js +203 -0
  248. package/dist/scripts/validate-spec.d.ts +22 -0
  249. package/dist/scripts/validate-spec.d.ts.map +1 -0
  250. package/dist/scripts/validate-spec.js +159 -0
  251. package/dist/server/index.d.ts +3 -0
  252. package/dist/server/index.d.ts.map +1 -0
  253. package/dist/server/index.js +3 -0
  254. package/dist/server/withAuth.d.ts +142 -0
  255. package/dist/server/withAuth.d.ts.map +1 -0
  256. package/dist/server/withAuth.js +261 -0
  257. package/dist/server/withAuth.test.d.ts +2 -0
  258. package/dist/server/withAuth.test.d.ts.map +1 -0
  259. package/dist/server/withAuth.test.js +278 -0
  260. package/dist/telemetry/client.d.ts +59 -0
  261. package/dist/telemetry/client.d.ts.map +1 -0
  262. package/dist/telemetry/client.js +215 -0
  263. package/dist/telemetry/config-writer.d.ts +16 -0
  264. package/dist/telemetry/config-writer.d.ts.map +1 -0
  265. package/dist/telemetry/config-writer.js +36 -0
  266. package/dist/telemetry/consent-commands.test.d.ts +2 -0
  267. package/dist/telemetry/consent-commands.test.d.ts.map +1 -0
  268. package/dist/telemetry/consent-commands.test.js +161 -0
  269. package/dist/telemetry/consent.d.ts +60 -0
  270. package/dist/telemetry/consent.d.ts.map +1 -0
  271. package/dist/telemetry/consent.js +122 -0
  272. package/dist/telemetry/environment.d.ts +33 -0
  273. package/dist/telemetry/environment.d.ts.map +1 -0
  274. package/dist/telemetry/environment.js +87 -0
  275. package/dist/telemetry/identifiers.d.ts +20 -0
  276. package/dist/telemetry/identifiers.d.ts.map +1 -0
  277. package/dist/telemetry/identifiers.js +86 -0
  278. package/dist/telemetry/index.d.ts +6 -0
  279. package/dist/telemetry/index.d.ts.map +1 -0
  280. package/dist/telemetry/index.js +4 -0
  281. package/dist/telemetry/telemetry.test.d.ts +2 -0
  282. package/dist/telemetry/telemetry.test.d.ts.map +1 -0
  283. package/dist/telemetry/telemetry.test.js +1131 -0
  284. package/dist/telemetry/trackCommand.d.ts +32 -0
  285. package/dist/telemetry/trackCommand.d.ts.map +1 -0
  286. package/dist/telemetry/trackCommand.js +102 -0
  287. package/dist/telemetry/types.d.ts +92 -0
  288. package/dist/telemetry/types.d.ts.map +1 -0
  289. package/dist/telemetry/types.js +1 -0
  290. package/dist/types.d.ts +24 -0
  291. package/dist/types.d.ts.map +1 -0
  292. package/dist/types.js +3 -0
  293. package/dist/version.d.ts +2 -0
  294. package/dist/version.d.ts.map +1 -0
  295. package/dist/version.js +2 -0
  296. package/package.json +83 -0
  297. package/src/api.test.ts +25 -0
  298. package/src/api.ts +163 -0
  299. package/src/bb-utils.ts +13 -0
  300. package/src/builtin-routes.ts +62 -0
  301. package/src/cdk/__fixtures__/factory-backend.ts +8 -0
  302. package/src/cdk/__fixtures__/fullid-construct-backend.ts +42 -0
  303. package/src/cdk/__fixtures__/handler.ts +4 -0
  304. package/src/cdk/__fixtures__/side-effect-backend.ts +7 -0
  305. package/src/cdk/blocks-backend.test.ts +207 -0
  306. package/src/cdk/blocks-backend.ts +249 -0
  307. package/src/cdk/blocks-stack.test.ts +106 -0
  308. package/src/cdk/config-registry.ts +106 -0
  309. package/src/cdk/index.ts +115 -0
  310. package/src/cdk/mixins.test.ts +129 -0
  311. package/src/cdk/mixins.ts +41 -0
  312. package/src/cdk/node-version.ts +17 -0
  313. package/src/cdk/stack-metadata.test.ts +71 -0
  314. package/src/cdk/stack-metadata.ts +29 -0
  315. package/src/cdk/synth-guard.test.ts +21 -0
  316. package/src/cdk/synth-guard.ts +23 -0
  317. package/src/client/index.test.ts +118 -0
  318. package/src/client/index.ts +320 -0
  319. package/src/common/config.test.ts +236 -0
  320. package/src/common/config.ts +169 -0
  321. package/src/common/constants.ts +15 -0
  322. package/src/common/crypto.ts +15 -0
  323. package/src/common/index.test.ts +242 -0
  324. package/src/common/index.ts +335 -0
  325. package/src/common/mock-data.ts +52 -0
  326. package/src/common/official-bb-names.generated.ts +29 -0
  327. package/src/common/sdk-registry.ts +150 -0
  328. package/src/constants.ts +31 -0
  329. package/src/cors.test.ts +279 -0
  330. package/src/cors.ts +91 -0
  331. package/src/db-naming.test.ts +48 -0
  332. package/src/db-naming.ts +41 -0
  333. package/src/errors.ts +72 -0
  334. package/src/hosting.test.ts +1431 -0
  335. package/src/hosting.ts +626 -0
  336. package/src/index.cdk.ts +45 -0
  337. package/src/index.ts +22 -0
  338. package/src/lambda-handler.test.ts +1005 -0
  339. package/src/lambda-handler.ts +706 -0
  340. package/src/pipeline/index.ts +12 -0
  341. package/src/pipeline/pipeline-construct.ts +662 -0
  342. package/src/pipeline/pipeline.test.ts +1565 -0
  343. package/src/pipeline/types.ts +384 -0
  344. package/src/raw-route.cdk.ts +56 -0
  345. package/src/raw-route.mock.ts +56 -0
  346. package/src/raw-route.test.ts +819 -0
  347. package/src/raw-route.ts +316 -0
  348. package/src/redact.test.ts +222 -0
  349. package/src/redact.ts +143 -0
  350. package/src/rpc.test.ts +73 -0
  351. package/src/rpc.ts +174 -0
  352. package/src/scripts/cdk-telemetry-env.test.ts +75 -0
  353. package/src/scripts/cdk-telemetry-env.ts +23 -0
  354. package/src/scripts/cleanup.ts +39 -0
  355. package/src/scripts/console.ts +34 -0
  356. package/src/scripts/deploy.ts +106 -0
  357. package/src/scripts/destroy.ts +42 -0
  358. package/src/scripts/dev-server-cors.test.ts +28 -0
  359. package/src/scripts/dev-server-telemetry.test.ts +127 -0
  360. package/src/scripts/dev-server.ts +515 -0
  361. package/src/scripts/ensure-secrets.test.ts +50 -0
  362. package/src/scripts/ensure-secrets.ts +113 -0
  363. package/src/scripts/external-migrations-step.test.ts +64 -0
  364. package/src/scripts/external-migrations-step.ts +269 -0
  365. package/src/scripts/extract-ts-types.test.ts +516 -0
  366. package/src/scripts/extract-ts-types.ts +773 -0
  367. package/src/scripts/generate-client-worker.ts +15 -0
  368. package/src/scripts/generate-client.test.ts +69 -0
  369. package/src/scripts/generate-client.ts +86 -0
  370. package/src/scripts/generate-spec-cli.test.ts +106 -0
  371. package/src/scripts/generate-spec-cli.ts +92 -0
  372. package/src/scripts/generate-spec.test.ts +99 -0
  373. package/src/scripts/generate-spec.ts +833 -0
  374. package/src/scripts/index.ts +21 -0
  375. package/src/scripts/sandbox.ts +230 -0
  376. package/src/scripts/telemetry-cli.ts +10 -0
  377. package/src/scripts/telemetry.test.ts +239 -0
  378. package/src/scripts/telemetry.ts +173 -0
  379. package/src/scripts/validate-spec.ts +199 -0
  380. package/src/server/index.ts +5 -0
  381. package/src/server/withAuth.test.ts +348 -0
  382. package/src/server/withAuth.ts +323 -0
  383. package/src/telemetry/client.ts +226 -0
  384. package/src/telemetry/config-writer.ts +52 -0
  385. package/src/telemetry/consent-commands.test.ts +196 -0
  386. package/src/telemetry/consent.ts +154 -0
  387. package/src/telemetry/environment.ts +100 -0
  388. package/src/telemetry/identifiers.ts +94 -0
  389. package/src/telemetry/index.ts +11 -0
  390. package/src/telemetry/telemetry.test.ts +1343 -0
  391. package/src/telemetry/trackCommand.ts +110 -0
  392. package/src/telemetry/types.ts +92 -0
  393. package/src/types.ts +33 -0
  394. package/src/version.ts +2 -0
@@ -0,0 +1,42 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ /**
5
+ * Test fixture: a child Scope that embeds its `fullId` directly into a CDK
6
+ * construct ID.
7
+ *
8
+ * Why this matters
9
+ * ----------------
10
+ * Building Blocks routinely use their `fullId` as part of a construct ID, e.g.
11
+ * a DSQL block creating its migration Lambda as
12
+ * `new lambda.NodejsFunction(stack, `${this.fullId}DsqlMigrationFn`, ...)`.
13
+ * CDK forbids unresolved tokens in construct IDs (it throws
14
+ * "ID components may not include unresolved tokens" at synth time).
15
+ *
16
+ * `fullId` is derived from the enclosing stack name. In a nested-stack topology
17
+ * (e.g. Amplify Gen2's `backend.createStack('blocks')`) that stack name is a
18
+ * deploy-time token, so a naive `fullId` would carry a token and break synth.
19
+ *
20
+ * This fixture reproduces that exact pattern: importing it builds a construct
21
+ * whose ID is `${this.fullId}Marker`. If `fullId` ever contains a token, this
22
+ * side-effect import throws at synth time — which is what the test asserts must
23
+ * NOT happen.
24
+ */
25
+ import * as cdk from 'aws-cdk-lib';
26
+ import { Construct } from 'constructs';
27
+ import { Scope } from '../index.js';
28
+ import type { ScopeParent } from '../../common/index.js';
29
+
30
+ class FullIdConstructBlock extends Scope {
31
+ constructor(scope: ScopeParent, id: string) {
32
+ super(id, { parent: scope });
33
+ const stack = cdk.Stack.of(this);
34
+ // Use fullId as a construct ID, the same way real Building Blocks do.
35
+ new cdk.CfnResource(stack, `${this.fullId}Marker`, {
36
+ type: 'AWS::CloudFormation::WaitConditionHandle',
37
+ });
38
+ }
39
+ }
40
+
41
+ const parent = (globalThis as any).CURRENT_BLOCKS_STACK;
42
+ new FullIdConstructBlock(parent, 'db');
@@ -0,0 +1,4 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export const handler = async () => ({ statusCode: 200, body: '{}' });
@@ -0,0 +1,7 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { Construct } from 'constructs';
5
+
6
+ const parent = (globalThis as any).CURRENT_BLOCKS_STACK;
7
+ new Construct(parent, 'SideEffectMarker');
@@ -0,0 +1,207 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { test, describe, before } from 'node:test';
5
+ import assert from 'node:assert';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { dirname, join } from 'node:path';
8
+ import * as cdk from 'aws-cdk-lib';
9
+ import { Template } from 'aws-cdk-lib/assertions';
10
+ import { BlocksBackend } from './blocks-backend.js';
11
+
12
+ // Simulate the CDK condition being active (tests import CDK files directly)
13
+ before(() => {
14
+ process.env.NODE_OPTIONS = (process.env.NODE_OPTIONS ?? '') + ' --conditions=cdk';
15
+ });
16
+
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const handlerPath = join(__dirname, '__fixtures__', 'handler.js');
19
+ const sideEffectBackendPath = join(__dirname, '__fixtures__', 'side-effect-backend.js');
20
+ const factoryBackendPath = join(__dirname, '__fixtures__', 'factory-backend.js');
21
+ const fullIdConstructBackendPath = join(__dirname, '__fixtures__', 'fullid-construct-backend.js');
22
+
23
+ describe('ESM cache-busting (multi-stage)', () => {
24
+ test('BlocksBackend.create() with same backendCDKPath but different IDs produces constructs in each', async () => {
25
+ const app = new cdk.App();
26
+ const stack = new cdk.Stack(app, 'TestStack');
27
+
28
+ const backend1 = await BlocksBackend.create(stack, 'Stage1', {
29
+ backendHandlerPath: handlerPath,
30
+ backendCDKPath: sideEffectBackendPath,
31
+ });
32
+
33
+ const backend2 = await BlocksBackend.create(stack, 'Stage2', {
34
+ backendHandlerPath: handlerPath,
35
+ backendCDKPath: sideEffectBackendPath,
36
+ });
37
+
38
+ const findMarker = (scope: cdk.aws_lambda_nodejs.NodejsFunction | any) =>
39
+ scope.node.tryFindChild('SideEffectMarker');
40
+
41
+ assert.ok(
42
+ findMarker(backend1),
43
+ 'Stage1 backend should have SideEffectMarker construct from module side effect',
44
+ );
45
+ assert.ok(
46
+ findMarker(backend2),
47
+ 'Stage2 backend should have SideEffectMarker construct from re-executed module',
48
+ );
49
+ });
50
+ });
51
+
52
+ describe('synth shape (drop into existing stack)', () => {
53
+ test('BlocksBackend lives inside the parent stack and synthesizes Lambda + API Gateway', async () => {
54
+ const app = new cdk.App();
55
+ const parent = new cdk.Stack(app, 'MyExistingStack');
56
+
57
+ const backend = await BlocksBackend.create(parent, 'Blocks', {
58
+ backendHandlerPath: handlerPath,
59
+ backendCDKPath: sideEffectBackendPath,
60
+ });
61
+
62
+ // Public surface mirrors BlocksStack.
63
+ assert.ok(backend.handler, 'BlocksBackend should expose .handler');
64
+ assert.ok(backend.gateway, 'BlocksBackend should expose .gateway');
65
+ assert.ok(backend.apiUrl, 'BlocksBackend should expose .apiUrl');
66
+
67
+ // Synth produces the expected resources inside the parent stack —
68
+ // no separate stack is created.
69
+ const template = Template.fromStack(parent);
70
+ template.hasResourceProperties('AWS::Lambda::Function', {});
71
+ template.resourceCountIs('AWS::ApiGateway::RestApi', 1);
72
+ });
73
+
74
+ test('multiple BlocksBackends in the same parent stack do not collide', async () => {
75
+ const app = new cdk.App();
76
+ const parent = new cdk.Stack(app, 'MultiBackendStack');
77
+
78
+ await BlocksBackend.create(parent, 'BackendA', {
79
+ backendHandlerPath: handlerPath,
80
+ backendCDKPath: sideEffectBackendPath,
81
+ });
82
+ await BlocksBackend.create(parent, 'BackendB', {
83
+ backendHandlerPath: handlerPath,
84
+ backendCDKPath: sideEffectBackendPath,
85
+ });
86
+
87
+ const template = Template.fromStack(parent);
88
+ template.resourceCountIs('AWS::ApiGateway::RestApi', 2);
89
+ });
90
+ });
91
+
92
+ describe('factory function support', () => {
93
+ test('BlocksBackend.create() calls default export function with the backend instance', async () => {
94
+ const app = new cdk.App();
95
+ const stack = new cdk.Stack(app, 'FactoryTestStack');
96
+
97
+ const backend = await BlocksBackend.create(stack, 'FactoryStage', {
98
+ backendHandlerPath: handlerPath,
99
+ backendCDKPath: factoryBackendPath,
100
+ });
101
+
102
+ const marker = backend.node.tryFindChild('FactoryMarker');
103
+ assert.ok(marker, 'Factory function should have created FactoryMarker on the backend');
104
+ });
105
+ });
106
+
107
+ describe('fullId is token-free (construct IDs / env-var keys)', () => {
108
+ test('top-level stack: fullId is {stackName}-{id} and resolvable', async () => {
109
+ const app = new cdk.App();
110
+ const stack = new cdk.Stack(app, 'TopLevelStack');
111
+
112
+ const backend = await BlocksBackend.create(stack, 'blocks', {
113
+ backendHandlerPath: handlerPath,
114
+ backendCDKPath: sideEffectBackendPath,
115
+ });
116
+
117
+ assert.strictEqual(backend.fullId, 'TopLevelStack-blocks');
118
+ assert.ok(!cdk.Token.isUnresolved(backend.fullId), 'fullId must not contain a token');
119
+ });
120
+
121
+ test('nested stack: fullId stays token-free (regression for #714 / Amplify Gen2)', async () => {
122
+ // Amplify Gen2 wires Blocks into a NestedStack via backend.createStack('blocks').
123
+ // A NestedStack has a tokenized stackName that only resolves at deploy time —
124
+ // embedding it in fullId broke construct IDs with
125
+ // "ID components may not include unresolved tokens".
126
+ const app = new cdk.App();
127
+ const parent = new cdk.Stack(app, 'ParentStack');
128
+ const nested = new cdk.NestedStack(parent, 'blocks');
129
+
130
+ // Sanity: the nested stack's own name really is a token.
131
+ assert.ok(
132
+ cdk.Token.isUnresolved(nested.stackName),
133
+ 'precondition: NestedStack.stackName should be an unresolved token',
134
+ );
135
+
136
+ const backend = await BlocksBackend.create(nested, 'blocks', {
137
+ backendHandlerPath: handlerPath,
138
+ backendCDKPath: sideEffectBackendPath,
139
+ });
140
+
141
+ assert.ok(
142
+ !cdk.Token.isUnresolved(backend.fullId),
143
+ `fullId must be token-free inside a nested stack, got: ${backend.fullId}`,
144
+ );
145
+ // Falls back to the top-level (concrete) stack name, keeping uniqueness.
146
+ assert.strictEqual(backend.fullId, 'ParentStack-blocks');
147
+ });
148
+
149
+ test('child Scope can use fullId as a construct ID inside a nested stack', async () => {
150
+ // The fixture mirrors bb-distributed-data: it builds a construct whose ID is
151
+ // `${this.fullId}Marker`. If fullId carried a token, synth would throw.
152
+ const app = new cdk.App();
153
+ const parent = new cdk.Stack(app, 'Gen2ParentStack');
154
+ const nested = new cdk.NestedStack(parent, 'blocks');
155
+
156
+ const backend = await BlocksBackend.create(nested, 'blocks', {
157
+ backendHandlerPath: handlerPath,
158
+ backendCDKPath: fullIdConstructBackendPath,
159
+ });
160
+
161
+ // The construct ID is `${scope.fullId}Marker` → `ParentStack-blocks-blocks-dbMarker`.
162
+ const expectedId = `${backend.fullId}-dbMarker`;
163
+ assert.ok(
164
+ nested.node.tryFindChild(expectedId),
165
+ `expected a child construct with id "${expectedId}"`,
166
+ );
167
+
168
+ // Full synth must not throw on unresolved-token-in-construct-id.
169
+ assert.doesNotThrow(() => app.synth());
170
+ });
171
+
172
+ test('BLOCKS_STACK_NAME env var equals fullId (CDK-time ↔ runtime invariant)', async () => {
173
+ // Physical resource names (DynamoDB tables, DSQL env-var keys, IAM ARNs) are
174
+ // derived from fullId on BOTH sides: at synth via BlocksBackend.fullId, and at
175
+ // runtime via the root parent `{ id: process.env.BLOCKS_STACK_NAME }`. They MUST
176
+ // be byte-for-byte identical, otherwise the runtime looks up names/grants that
177
+ // were never created. BlocksBackend keeps them in sync by writing fullId into the
178
+ // handler's BLOCKS_STACK_NAME env var — assert that contract holds and is token-free.
179
+ const app = new cdk.App();
180
+ const parent = new cdk.Stack(app, 'InvariantParent');
181
+ const nested = new cdk.NestedStack(parent, 'blocks');
182
+
183
+ const backend = await BlocksBackend.create(nested, 'blocks', {
184
+ backendHandlerPath: handlerPath,
185
+ backendCDKPath: sideEffectBackendPath,
186
+ });
187
+
188
+ const template = Template.fromStack(nested);
189
+ const fns = template.findResources('AWS::Lambda::Function');
190
+ const envValues = Object.values(fns)
191
+ .map((fn: any) => fn.Properties?.Environment?.Variables?.BLOCKS_STACK_NAME)
192
+ .filter((v): v is string => typeof v === 'string');
193
+
194
+ assert.ok(envValues.length > 0, 'expected a Lambda with a BLOCKS_STACK_NAME env var');
195
+ for (const value of envValues) {
196
+ assert.strictEqual(
197
+ value,
198
+ backend.fullId,
199
+ 'BLOCKS_STACK_NAME must equal BlocksBackend.fullId so runtime names match synth',
200
+ );
201
+ assert.ok(
202
+ !cdk.Token.isUnresolved(value),
203
+ `BLOCKS_STACK_NAME must be token-free, got: ${value}`,
204
+ );
205
+ }
206
+ });
207
+ });
@@ -0,0 +1,249 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import * as cdk from 'aws-cdk-lib';
5
+ import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
6
+ import * as apigateway from 'aws-cdk-lib/aws-apigateway';
7
+ import { CfnGroup } from 'aws-cdk-lib/aws-resourcegroups';
8
+ import { Construct } from 'constructs';
9
+ import { DEFAULT_NODE_RUNTIME } from './node-version.js';
10
+ import { addBlocksStackMetadata } from './stack-metadata.js';
11
+ import { finalizeConfigRegistry, registerConfig } from './config-registry.js';
12
+ import { BLOCKS_NAMESPACE, BLOCKS_RPC_PREFIX } from '../constants.js';
13
+ import { registerBuiltinRoutes } from '../builtin-routes.js';
14
+
15
+ /**
16
+ * Validate that the Node.js process was started with `--conditions=cdk`.
17
+ *
18
+ * Without this condition, conditional exports in Building Block packages
19
+ * resolve to their mock/default entry points instead of the CDK entry points.
20
+ * This causes a silent deployment failure: CDK synth "succeeds" but produces
21
+ * no real infrastructure (no tables, no IAM, no Lambda configs).
22
+ */
23
+ export function assertCdkConditionActive(): void {
24
+ const nodeOptions = process.env.NODE_OPTIONS ?? '';
25
+ const execArgv = process.execArgv ?? [];
26
+
27
+ const hasCdkCondition =
28
+ execArgv.some(arg => arg === '--conditions=cdk') ||
29
+ execArgv.some((arg, i) => (arg === '--conditions' || arg === '-C') && execArgv[i + 1] === 'cdk') ||
30
+ nodeOptions.includes('--conditions=cdk') ||
31
+ /(?:--conditions|-C)\s+cdk/.test(nodeOptions);
32
+
33
+ if (!hasCdkCondition) {
34
+ throw new Error(
35
+ 'Missing --conditions=cdk: Building Blocks will silently load mock implementations instead of CDK constructs.\n\n' +
36
+ 'Fix: Set NODE_OPTIONS="--conditions=cdk" before running CDK synth:\n' +
37
+ ' NODE_OPTIONS="--conditions=cdk" npx cdk synth\n\n' +
38
+ 'Or use the Blocks CLI commands (npm run deploy / npm run sandbox) which set this automatically.',
39
+ );
40
+ }
41
+ }
42
+
43
+ export interface BlocksBackendProps {
44
+ backendHandlerPath: string;
45
+ backendCDKPath: string;
46
+ }
47
+
48
+ /** Shared infra setup — creates Lambda + API Gateway on the given scope. */
49
+ export function setupBlocksInfra(scope: Construct, props: BlocksBackendProps, id?: string) {
50
+ const handler = new lambda.NodejsFunction(scope, 'Handler', {
51
+ entry: props.backendHandlerPath,
52
+ runtime: DEFAULT_NODE_RUNTIME,
53
+ handler: 'handler',
54
+ memorySize: 2048,
55
+ timeout: cdk.Duration.seconds(60 * 15),
56
+ environment: {
57
+ NODE_ENV: 'production',
58
+ /**
59
+ * BLOCKS_STACK_NAME is used at runtime to derive physical resource names
60
+ * (DynamoDB table names, env var prefixes). It must match the CDK-time
61
+ * fullId of the BlocksStack/BlocksBackend so resource lookups work correctly.
62
+ *
63
+ * For BlocksStack: this equals the stack name (id).
64
+ * For BlocksBackend: the caller overrides this after construction to include
65
+ * the parent stack name for deployment uniqueness.
66
+ */
67
+ BLOCKS_STACK_NAME: id ?? cdk.Stack.of(scope).stackName,
68
+ },
69
+ bundling: {
70
+ minify: true,
71
+ esbuildArgs: { '--conditions': 'aws-runtime' },
72
+ },
73
+ });
74
+
75
+ // In sandbox mode, allow localhost origins so the local dev frontend can
76
+ // reach the deployed Lambda API via CORS.
77
+ const isSandbox =
78
+ scope.node.tryGetContext('sandboxMode') === 'true' ||
79
+ scope.node.tryGetContext('sandboxMode') === true;
80
+ if (isSandbox) {
81
+ handler.addEnvironment('CORS_ALLOWED_ORIGINS', '^https?://(localhost|127\\.0\\.0\\.1)(:\\d+)?$');
82
+ }
83
+
84
+ const api = new apigateway.RestApi(scope, 'API', {
85
+ restApiName: 'Blocks API',
86
+ deployOptions: { cachingEnabled: false },
87
+ });
88
+
89
+ const integration = new apigateway.LambdaIntegration(handler);
90
+
91
+ // Build the nested resource tree for /aws-blocks/api.
92
+ // Intermediate resource gets a proxy so sub-paths (RawRoutes) still reach Lambda.
93
+ const awsBlocksResource = api.root.addResource(BLOCKS_NAMESPACE.slice(1));
94
+ awsBlocksResource.addProxy({ defaultIntegration: integration, anyMethod: true });
95
+
96
+ const apiResource = awsBlocksResource.addResource('api');
97
+ apiResource.addMethod('POST', integration);
98
+ apiResource.addMethod('OPTIONS', integration);
99
+
100
+ api.root.addProxy({ defaultIntegration: integration, anyMethod: true });
101
+
102
+ // ── Resource Groups ────────────────────────────────────────────────────
103
+ let rootStack = cdk.Stack.of(scope);
104
+ while (rootStack.nestedStackParent) rootStack = rootStack.nestedStackParent;
105
+ const groupPrefix = (id && id !== rootStack.stackName) ? `${rootStack.stackName}-${id}` : rootStack.stackName;
106
+
107
+ new CfnGroup(scope, 'StackResources', {
108
+ name: `${groupPrefix}-resources`,
109
+ resourceQuery: {
110
+ type: 'CLOUDFORMATION_STACK_1_0',
111
+ query: {
112
+ resourceTypeFilters: [
113
+ 'AWS::CloudWatch::Dashboard',
114
+ 'AWS::Cognito::UserPool',
115
+ 'AWS::DynamoDB::Table',
116
+ 'AWS::Logs::LogGroup',
117
+ 'AWS::RDS::DBCluster',
118
+ 'AWS::RDS::DBInstance',
119
+ 'AWS::S3::Bucket',
120
+ 'AWS::SQS::Queue',
121
+ ],
122
+ stackIdentifier: cdk.Stack.of(scope).stackId,
123
+ },
124
+ },
125
+ });
126
+
127
+ new CfnGroup(scope, 'StackSettings', {
128
+ name: `${groupPrefix}-settings`,
129
+ resourceQuery: {
130
+ type: 'TAG_FILTERS_1_0',
131
+ query: {
132
+ resourceTypeFilters: ['AWS::SSM::Parameter'],
133
+ tagFilters: [{ key: 'aws-blocks-stack', values: [rootStack.stackName] }],
134
+ },
135
+ },
136
+ });
137
+
138
+ // ── Console redirect routes ────────────────────────────────────────────
139
+ const region = cdk.Fn.ref('AWS::Region');
140
+ const resourcesUrl = cdk.Fn.join('', [
141
+ 'https://', region, '.console.aws.amazon.com/resource-groups/group/',
142
+ `${groupPrefix}-resources`, '?region=', region,
143
+ ]);
144
+ const settingsUrl = cdk.Fn.join('', [
145
+ 'https://', region, '.console.aws.amazon.com/resource-groups/group/',
146
+ `${groupPrefix}-settings`, '?region=', region,
147
+ ]);
148
+
149
+ registerConfig(scope, 'BB_RESOURCES_GROUP_URL', resourcesUrl);
150
+ registerConfig(scope, 'BB_SETTINGS_GROUP_URL', settingsUrl);
151
+
152
+ registerBuiltinRoutes();
153
+
154
+ return { handler, gateway: api, apiUrl: `${api.url}${BLOCKS_RPC_PREFIX.slice(1)}` };
155
+ }
156
+
157
+ /**
158
+ * Standalone CDK construct that provisions the Blocks backend: a single Lambda
159
+ * function fronted by API Gateway with RPC + catch-all proxy routing.
160
+ *
161
+ * Use this to embed a Blocks backend into any existing CDK stack. Building Blocks
162
+ * instantiated during the `backendCDKPath` import will automatically attach to
163
+ * this construct's Lambda handler.
164
+ *
165
+ * @example Drop into an existing stack
166
+ * ```ts
167
+ * const blocks = await BlocksBackend.create(myStack, 'Blocks', {
168
+ * backendHandlerPath: join(__dirname, 'handler.ts'),
169
+ * backendCDKPath: join(__dirname, 'infra.ts'),
170
+ * });
171
+ * // blocks.apiUrl, blocks.handler, blocks.gateway available
172
+ * ```
173
+ */
174
+ export class BlocksBackend extends Construct {
175
+ public readonly apiUrl: string;
176
+ public readonly gateway: apigateway.RestApi;
177
+ public readonly handler: cdk.aws_lambda_nodejs.NodejsFunction;
178
+ public readonly backendHandlerPath: string;
179
+
180
+ /**
181
+ * The fullId used by child Scopes to compute their env var names,
182
+ * construct IDs, and physical resource names (e.g., DynamoDB table names).
183
+ *
184
+ * Includes the CDK stack name to ensure physical resources are unique
185
+ * per deployment. This matches what the runtime sees via BLOCKS_STACK_NAME.
186
+ *
187
+ * IMPORTANT: this value MUST be token-free. Child Scopes embed `fullId` in
188
+ * CDK construct IDs (e.g. `${fullId}DsqlMigrationFn`), and CDK forbids
189
+ * unresolved tokens in construct IDs ("ID components may not include
190
+ * unresolved tokens"). It is also used to build env-var keys that must match
191
+ * byte-for-byte between synth time and runtime.
192
+ *
193
+ * A nested stack (e.g. Amplify Gen2 `backend.createStack('blocks')`) has a
194
+ * tokenized `stackName` that only resolves at deploy time. We therefore walk
195
+ * up to the top-level stack, whose name is concrete at synth time and still
196
+ * unique per deployment. The `Token.isUnresolved` guard is a defensive
197
+ * fallback to the (token-free) construct id should no resolvable name exist.
198
+ */
199
+ get fullId(): string {
200
+ let stack = cdk.Stack.of(this);
201
+ while (stack.nestedStackParent) {
202
+ stack = stack.nestedStackParent;
203
+ }
204
+ const stackName = stack.stackName;
205
+ if (cdk.Token.isUnresolved(stackName)) {
206
+ return this.node.id;
207
+ }
208
+ return `${stackName}-${this.node.id}`;
209
+ }
210
+
211
+ private constructor(scope: Construct, id: string, props: BlocksBackendProps) {
212
+ super(scope, id);
213
+
214
+ this.backendHandlerPath = props.backendHandlerPath;
215
+
216
+ // Expose self to Building Blocks at CDK time
217
+ (globalThis as any).CURRENT_BLOCKS_STACK = this;
218
+
219
+ const infra = setupBlocksInfra(this, props, id);
220
+ this.handler = infra.handler;
221
+ this.gateway = infra.gateway;
222
+ this.apiUrl = infra.apiUrl;
223
+
224
+ // Override BLOCKS_STACK_NAME to include the parent stack name so runtime
225
+ // resource lookups (DynamoDB table names) match the CDK-time fullId
226
+ // and are unique per deployment.
227
+ this.handler.addEnvironment('BLOCKS_STACK_NAME', this.fullId);
228
+ }
229
+
230
+ static async create(scope: Construct, id: string, props: BlocksBackendProps) {
231
+ assertCdkConditionActive();
232
+ const backend = new BlocksBackend(scope, id, props);
233
+ // ESM caches modules by URL — append a unique query string so each stage re-executes the module body
234
+ const mod = await import(`${props.backendCDKPath}?stack=${id}`);
235
+ if (typeof mod.default === 'function') {
236
+ try {
237
+ await mod.default(backend);
238
+ } catch (error) {
239
+ throw new Error(`Error executing default export function for backend "${id}": ${error instanceof Error ? error.message : error}`, { cause: error });
240
+ }
241
+ }
242
+ addBlocksStackMetadata(cdk.Stack.of(backend));
243
+
244
+ // Finalize BB config → S3 (after all BBs have registered their config)
245
+ finalizeConfigRegistry(backend, backend.handler);
246
+
247
+ return backend;
248
+ }
249
+ }
@@ -0,0 +1,106 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { test, describe, before } from 'node:test';
5
+ import assert from 'node:assert';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { dirname, join } from 'node:path';
8
+ import * as cdk from 'aws-cdk-lib';
9
+ import { BlocksBackend } from './blocks-backend.js';
10
+ import { BlocksStack } from './index.js';
11
+
12
+ // Simulate the CDK condition being active (tests import CDK files directly)
13
+ before(() => {
14
+ process.env.NODE_OPTIONS = (process.env.NODE_OPTIONS ?? '') + ' --conditions=cdk';
15
+ });
16
+
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const handlerPath = join(__dirname, '__fixtures__', 'handler.js');
19
+ const sideEffectBackendPath = join(__dirname, '__fixtures__', 'side-effect-backend.js');
20
+ const factoryBackendPath = join(__dirname, '__fixtures__', 'factory-backend.js');
21
+
22
+ describe('ESM cache-busting (multi-stage)', () => {
23
+ test('BlocksStack.create() with same backendCDKPath but different IDs produces constructs in each', async () => {
24
+ const app = new cdk.App();
25
+
26
+ const stack1 = await BlocksStack.create(app, 'PipelineStage1', {
27
+ backendHandlerPath: handlerPath,
28
+ backendCDKPath: sideEffectBackendPath,
29
+ });
30
+
31
+ const stack2 = await BlocksStack.create(app, 'PipelineStage2', {
32
+ backendHandlerPath: handlerPath,
33
+ backendCDKPath: sideEffectBackendPath,
34
+ });
35
+
36
+ const findMarker = (scope: any) => scope.node.tryFindChild('SideEffectMarker');
37
+
38
+ assert.ok(
39
+ findMarker(stack1),
40
+ 'First stack should have SideEffectMarker from module side effect',
41
+ );
42
+ assert.ok(
43
+ findMarker(stack2),
44
+ 'Second stack should have SideEffectMarker from re-executed module (cache busted)',
45
+ );
46
+ });
47
+ });
48
+
49
+ describe('factory function support', () => {
50
+ test('BlocksStack.create() calls default export function with the stack instance', async () => {
51
+ const app = new cdk.App();
52
+
53
+ const stack = await BlocksStack.create(app, 'FactoryBlocksStack', {
54
+ backendHandlerPath: handlerPath,
55
+ backendCDKPath: factoryBackendPath,
56
+ });
57
+
58
+ const marker = stack.node.tryFindChild('FactoryMarker');
59
+ assert.ok(marker, 'Factory function should have created FactoryMarker on the stack');
60
+ });
61
+ });
62
+
63
+ describe('legacy side-effect mode (no default export)', () => {
64
+ test('module with only side effects still registers constructs via globalThis', async () => {
65
+ const app = new cdk.App();
66
+ const stack = new cdk.Stack(app, 'LegacyTestStack');
67
+
68
+ const backend = await BlocksBackend.create(stack, 'LegacyStage', {
69
+ backendHandlerPath: handlerPath,
70
+ backendCDKPath: sideEffectBackendPath,
71
+ });
72
+
73
+ const marker = backend.node.tryFindChild('SideEffectMarker');
74
+ assert.ok(
75
+ marker,
76
+ 'Side-effect-only module should register construct via globalThis.CURRENT_BLOCKS_STACK',
77
+ );
78
+ });
79
+ });
80
+
81
+ describe('assertCdkConditionActive', () => {
82
+ test('BlocksStack.create() throws when --conditions=cdk is missing', async () => {
83
+ const origNodeOptions = process.env.NODE_OPTIONS;
84
+ const origExecArgv = process.execArgv;
85
+ process.env.NODE_OPTIONS = '';
86
+ process.execArgv = [];
87
+
88
+ try {
89
+ const app = new cdk.App();
90
+
91
+ await assert.rejects(
92
+ BlocksStack.create(app, 'MissingConditionStack', {
93
+ backendHandlerPath: handlerPath,
94
+ backendCDKPath: sideEffectBackendPath,
95
+ }),
96
+ (err: Error) => {
97
+ assert.ok(err.message.includes('Missing --conditions=cdk'), `Expected condition error, got: ${err.message}`);
98
+ return true;
99
+ },
100
+ );
101
+ } finally {
102
+ process.env.NODE_OPTIONS = origNodeOptions;
103
+ process.execArgv = origExecArgv;
104
+ }
105
+ });
106
+ });