@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,706 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // This will be bundled with the customer's backend code
5
+ import { AsyncLocalStorage } from 'node:async_hooks';
6
+ import { ApiError } from './errors.js';
7
+ import { BLOCKS_RPC_PREFIX } from './constants.js';
8
+ import { matchRoute, lockRouteRegistry } from './raw-route.js';
9
+ import { registerBuiltinRoutes } from './builtin-routes.js';
10
+ import { loadConfigToProcessEnv } from './common/config.js';
11
+ import {
12
+ parseRpcRequest,
13
+ successResponse,
14
+ errorResponse,
15
+ errorResponseFromCatch,
16
+ methodNotFoundResponse,
17
+ } from './rpc.js';
18
+ import { getCorsPatterns, isOriginAllowed, corsRejection } from './cors.js';
19
+
20
+ export { parseCorsPatterns, _resetCorsPatterns } from './cors.js';
21
+
22
+ /**
23
+ * AsyncLocalStorage that carries the inbound HTTP request cookies through
24
+ * the call stack. SSR frameworks (Next.js Server Components) can read this
25
+ * via `requestCookies.getStore()` to forward auth cookies when calling the
26
+ * Blocks API server-side.
27
+ *
28
+ * Also registered on `globalThis.__BLOCKS_REQUEST_COOKIES_STORE__` so the
29
+ * client bundle can access it without importing node:async_hooks.
30
+ */
31
+ export const requestCookies = new AsyncLocalStorage<string>();
32
+ (globalThis as any).__BLOCKS_REQUEST_COOKIES_STORE__ = requestCookies;
33
+
34
+ /**
35
+ * Event source mapping identifiers used by AWS when pushing records to Lambda.
36
+ * Building Blocks use these constants with `Scope.registerLambdaEventHandler()`.
37
+ */
38
+ export const EventSourceMapping = {
39
+ SQS: 'aws:sqs',
40
+ } as const;
41
+
42
+ // ── CORS helpers (private to handler) ───────────────────────────────────────
43
+
44
+ function buildCorsHeaders(origin: string): Record<string, string> {
45
+ const headers: Record<string, string> = {};
46
+ if (isOriginAllowed(origin)) {
47
+ headers['Access-Control-Allow-Origin'] = origin;
48
+ headers['Access-Control-Allow-Credentials'] = 'true';
49
+ } else if (origin) {
50
+ console.warn(
51
+ `[CORS] Origin "${origin}" is not allowed. Set the CORS_ALLOWED_ORIGINS environment variable to allow this origin. Example: CORS_ALLOWED_ORIGINS=https://myapp\\.com,^https?://(localhost|127\\.0\\.0\\.1)(:\\d+)?$`
52
+ );
53
+ }
54
+ return headers;
55
+ }
56
+
57
+ // ── Helpers ─────────────────────────────────────────────────────────────────
58
+
59
+ /**
60
+ * Decode the Lambda event body and return both the raw string and a ReadableStream.
61
+ *
62
+ * Handles base64-encoded bodies (binary payloads forwarded by API Gateway)
63
+ * and plain-text bodies.
64
+ */
65
+ function decodeEventBody(event: any): { bodyText: string; bodyStream: ReadableStream<Uint8Array> | null } {
66
+ if (!event.body) {
67
+ return { bodyText: '', bodyStream: null };
68
+ }
69
+
70
+ const bodyText = event.isBase64Encoded
71
+ ? Buffer.from(event.body, 'base64').toString('utf-8')
72
+ : event.body;
73
+
74
+ const bodyStream = new ReadableStream<Uint8Array>({
75
+ start(controller) {
76
+ controller.enqueue(new TextEncoder().encode(bodyText));
77
+ controller.close();
78
+ },
79
+ });
80
+
81
+ return { bodyText, bodyStream };
82
+ }
83
+
84
+ /**
85
+ * Hostnames that count as loopback for the trusted-forwarded-host gate.
86
+ *
87
+ * `URL.hostname` keeps the brackets on IPv6 literals (`http://[::1]:3000` →
88
+ * `[::1]`), so the set is keyed on the bracketed form.
89
+ */
90
+ const LOOPBACK_HOSTNAMES = new Set(['localhost', '127.0.0.1', '[::1]']);
91
+
92
+ /**
93
+ * Whether an `X-Forwarded-Host` value points at the local loopback interface.
94
+ *
95
+ * The gate matters because the deployed Lambda sits directly behind API Gateway
96
+ * with no trusted proxy to strip this attacker-controllable header — in sandbox
97
+ * *and* production. Honoring it unconditionally would let any client spoof the
98
+ * host the backend builds absolute URLs from (e.g. an OIDC `redirect_uri`). Only
99
+ * loopback is trusted: it's the one case the sandbox dev-server needs, and a
100
+ * forged non-loopback value is ignored.
101
+ *
102
+ * @internal Exported for testing only.
103
+ */
104
+ export function isLoopbackForwardedHost(forwardedHost: string | undefined): boolean {
105
+ if (!forwardedHost) return false;
106
+ // Parse via URL so a `host:port` (or bracketed IPv6) value yields a clean
107
+ // hostname with the port stripped. A bare hostname parses fine too.
108
+ let hostname: string;
109
+ try {
110
+ hostname = new URL(`http://${forwardedHost}`).hostname.toLowerCase();
111
+ } catch {
112
+ return false;
113
+ }
114
+ return LOOPBACK_HOSTNAMES.has(hostname);
115
+ }
116
+
117
+ /**
118
+ * Reconstruct the absolute request URL from an API Gateway Lambda event.
119
+ *
120
+ * - Path comes from `event.path` (API Gateway v1) or `event.requestContext.http.path` (v2).
121
+ * - Query string from `event.multiValueQueryStringParameters` when present (preserves duplicates),
122
+ * falling back to `event.queryStringParameters`, then `event.rawQueryString` (v2).
123
+ * - When a trusted loopback `X-Forwarded-Host` is present (the sandbox dev-server
124
+ * front door), the URL is rebuilt as the browser-visible origin: that host,
125
+ * plain `http`, and **no** API Gateway stage prefix. Otherwise host comes from
126
+ * `Host`/`host`, protocol from `x-forwarded-proto` (default `https`), and the
127
+ * stage prefix is prepended. See {@link isLoopbackForwardedHost} for the gate.
128
+ *
129
+ * @internal Exported for testing only.
130
+ */
131
+ export function buildEventUrl(event: any): URL {
132
+ const path: string = event.path || event.requestContext?.http?.path || '/';
133
+ const forwardedHost: string | undefined =
134
+ event.headers?.['x-forwarded-host'] || event.headers?.['X-Forwarded-Host'];
135
+
136
+ let origin: string;
137
+ let fullPath: string;
138
+ if (isLoopbackForwardedHost(forwardedHost)) {
139
+ // Trusted sandbox dev-server front door. The browser reached the backend at
140
+ // `http://localhost:<port><path>` and the proxy forwarded it to execute-api.
141
+ // The browser-visible URL — which is what absolute URLs like the OIDC
142
+ // `redirect_uri` must match — is that localhost origin: plain HTTP and no
143
+ // stage. Rebuilding proto/stage from the execute-api request context would
144
+ // produce e.g. `https://localhost:3000/prod/auth/callback`, which the IdP
145
+ // rejects and the browser can't reach.
146
+ //
147
+ // `http` is hardcoded on purpose: the shipped dev server is HTTP-only, and
148
+ // `x-forwarded-proto` is unusable here — the dev server connects to API
149
+ // Gateway over HTTPS, so API Gateway stamps `x-forwarded-proto: https` on the
150
+ // Lambda integration request, clobbering whatever the dev server forwarded.
151
+ // A user-supplied TLS front door (`https://localhost`) is a known, unsupported
152
+ // limitation; the proper fix is a config-derived front-door origin rather than
153
+ // header inference.
154
+ origin = `http://${forwardedHost}`;
155
+ fullPath = path;
156
+ } else {
157
+ const host = event.headers?.Host || event.headers?.host || 'localhost';
158
+ const proto = event.headers?.['x-forwarded-proto'] || event.headers?.['X-Forwarded-Proto'] || 'https';
159
+ origin = `${proto}://${host}`;
160
+ // API Gateway REST APIs have a stage prefix (e.g. /prod) that's part of the
161
+ // external URL but NOT included in event.path. Include it so ctx.request.url
162
+ // reflects the full external-facing URL — needed for callback URLs, stub IdP
163
+ // issuer URLs, etc.
164
+ const stage = event.requestContext?.stage;
165
+ fullPath = stage ? `/${stage}${path}` : path;
166
+ }
167
+
168
+ const url = new URL(fullPath, origin);
169
+
170
+ if (event.rawQueryString) {
171
+ url.search = `?${event.rawQueryString}`;
172
+ } else if (event.multiValueQueryStringParameters) {
173
+ const params = new URLSearchParams();
174
+ for (const [k, values] of Object.entries(event.multiValueQueryStringParameters)) {
175
+ for (const v of values as string[]) params.append(k, v);
176
+ }
177
+ url.search = params.toString();
178
+ } else if (event.queryStringParameters) {
179
+ const params = new URLSearchParams();
180
+ for (const [k, v] of Object.entries(event.queryStringParameters)) {
181
+ if (v !== null && v !== undefined) params.append(k, String(v));
182
+ }
183
+ url.search = params.toString();
184
+ }
185
+
186
+ return url;
187
+ }
188
+
189
+ /**
190
+ * Default timeout for API Gateway HTTP requests (28s).
191
+ *
192
+ * API Gateway has a 29-second hard timeout for HTTP integrations.
193
+ * We self-terminate at 28s (1s safety margin) to return a proper 504
194
+ * before APIGW cuts the connection and returns its own opaque 504.
195
+ */
196
+ const APIGW_TIMEOUT_MS = 28_000;
197
+
198
+ /**
199
+ * Safety buffer subtracted from `context.getRemainingTimeInMillis()` to
200
+ * ensure the timeout response is sent before Lambda is killed.
201
+ */
202
+ const REMAINING_TIME_BUFFER_MS = 1_000;
203
+
204
+ /**
205
+ * Classified event source type for Lambda invocations.
206
+ *
207
+ * - `'http'`: API Gateway REST (v1) or HTTP (v2) request
208
+ * - `'websocket'`: API Gateway WebSocket (CONNECT/DISCONNECT/MESSAGE)
209
+ * - `'records'`: Event source mapping (SQS, Kinesis, DDB Streams)
210
+ * - `'direct'`: Direct invoke with Blocks-controlled payload (EventBridge Scheduler)
211
+ */
212
+ export type EventClass = 'http' | 'websocket' | 'records' | 'direct';
213
+
214
+ /**
215
+ * Classify a Lambda event into its source type.
216
+ *
217
+ * Used by both the timeout guard (to decide whether to apply the HTTP deadline)
218
+ * and the dispatcher (to route to the correct handler). Single source of truth
219
+ * prevents drift when new async event types are added.
220
+ *
221
+ * Returns `'http'` only when positive HTTP indicators are present (`httpMethod`
222
+ * or `requestContext.http.method`). Events that don't match any classification
223
+ * also fall to `'http'` via the dispatcher, but `isApiGatewayHttpEvent` gates
224
+ * the timeout guard to only fire when `classifyEvent` returns `'http'`.
225
+ *
226
+ * @internal Exported for testing only.
227
+ */
228
+ export function classifyEvent(event: any): EventClass {
229
+ if (event.Records?.[0]?.eventSource) return 'records';
230
+ if (event.source?.startsWith('blocks.')) return 'direct';
231
+ if (
232
+ event.requestContext?.eventType &&
233
+ ['CONNECT', 'DISCONNECT', 'MESSAGE'].includes(event.requestContext.eventType)
234
+ ) {
235
+ return 'websocket';
236
+ }
237
+ if (event.httpMethod || event.requestContext?.http?.method) return 'http';
238
+ return 'http';
239
+ }
240
+
241
+ /**
242
+ * Detect whether a Lambda event originates from API Gateway (HTTP).
243
+ *
244
+ * API Gateway v1 (REST): has `httpMethod` at top level.
245
+ * API Gateway v2 (HTTP): has `requestContext.http.method`.
246
+ *
247
+ * Events that are NOT API Gateway HTTP:
248
+ * - SQS/Kinesis/DDB Streams → `event.Records[0].eventSource`
249
+ * - EventBridge Scheduler → `event.source` starts with 'blocks.'
250
+ * - WebSocket → `event.requestContext.eventType` in CONNECT/DISCONNECT/MESSAGE
251
+ *
252
+ * @internal Exported for testing only.
253
+ */
254
+ export function isApiGatewayHttpEvent(event: any): boolean {
255
+ return classifyEvent(event) === 'http' && !!(event.httpMethod || event.requestContext?.http?.method);
256
+ }
257
+
258
+ /**
259
+ * Compute the HTTP deadline in milliseconds.
260
+ *
261
+ * Uses the minimum of:
262
+ * - `APIGW_TIMEOUT_MS` (28s fixed guard)
263
+ * - `context.getRemainingTimeInMillis() - REMAINING_TIME_BUFFER_MS` (actual remaining Lambda time)
264
+ *
265
+ * This handles the edge case where a warm Lambda has less than 29s remaining.
266
+ *
267
+ * @internal Exported for testing only.
268
+ */
269
+ export function computeHttpDeadlineMs(context?: LambdaContext): number {
270
+ if (!context?.getRemainingTimeInMillis) return APIGW_TIMEOUT_MS;
271
+ const remaining = context.getRemainingTimeInMillis() - REMAINING_TIME_BUFFER_MS;
272
+ return Math.min(APIGW_TIMEOUT_MS, Math.max(remaining, 0));
273
+ }
274
+
275
+ /**
276
+ * Minimal Lambda context interface for the fields we use.
277
+ * @internal Exported for testing only.
278
+ */
279
+ export interface LambdaContext {
280
+ getRemainingTimeInMillis(): number;
281
+ }
282
+
283
+ /**
284
+ * Create a Lambda handler for the Blocks backend.
285
+ *
286
+ * Uses the lazy factory pattern with a dynamic import:
287
+ * ```ts
288
+ * export const handler = createLambdaHandler(() => import('./index.js'));
289
+ * ```
290
+ *
291
+ * Why: Building Blocks read config from process.env at import time.
292
+ * The factory pattern loads S3 config into process.env BEFORE your
293
+ * backend module is imported.
294
+ *
295
+ * Cold start: First invocation fetches config from S3 (~50-200ms),
296
+ * then imports the backend. Subsequent invocations use cached config.
297
+ *
298
+ * Local dev: No S3 access — config comes from process.env directly.
299
+ *
300
+ * For API Gateway (HTTP) events, a self-termination guard races the handler
301
+ * against a 28s deadline. If the handler wedges, the Lambda returns a 504
302
+ * instead of billing for the full 15-minute timeout while the client already
303
+ * received a 504 from API Gateway. Async event sources (SQS, EventBridge,
304
+ * WebSocket) are not subject to this guard.
305
+ *
306
+ * @param backendFactory - Async function returning the backend module (typically `() => import('./index.js')`)
307
+ */
308
+ export function createLambdaHandler(backendFactory: () => Promise<any>) {
309
+ let handler: ((event: any, signal?: AbortSignal) => Promise<any>) | null = null;
310
+ let initPromise: Promise<void> | null = null;
311
+
312
+ async function initialize() {
313
+ await loadConfigToProcessEnv();
314
+
315
+ // Merge hosting-provided CORS origins into the main env var so the lazy
316
+ // getCorsPatterns() sees a combined value on first access.
317
+ // loadConfigToProcessEnv() won't override CORS_ALLOWED_ORIGINS if it's
318
+ // already set (sandbox env var), but CORS_HOSTING_ORIGINS always loads
319
+ // from S3 since it's never set as a direct env var.
320
+ const hostingOrigins = process.env.CORS_HOSTING_ORIGINS;
321
+ if (hostingOrigins) {
322
+ const existing = process.env.CORS_ALLOWED_ORIGINS;
323
+ process.env.CORS_ALLOWED_ORIGINS = existing
324
+ ? `${existing},${hostingOrigins}`
325
+ : hostingOrigins;
326
+ }
327
+
328
+ const mod = await backendFactory();
329
+ handler = createHandler(mod);
330
+ registerBuiltinRoutes();
331
+ lockRouteRegistry();
332
+ }
333
+
334
+ return async (event: any, context?: LambdaContext) => {
335
+ if (!handler) {
336
+ if (!initPromise) initPromise = initialize();
337
+ await initPromise;
338
+ }
339
+
340
+ // Only apply the HTTP timeout guard to API Gateway requests; async event
341
+ // sources (SQS, EventBridge, WebSocket) have their own retry semantics.
342
+ if (!isApiGatewayHttpEvent(event)) {
343
+ return handler!(event);
344
+ }
345
+
346
+ // Race the handler against a timeout so we can return a proper 504 before
347
+ // API Gateway's own 29s hard cutoff fires and returns an opaque 504.
348
+ const deadlineMs = computeHttpDeadlineMs(context);
349
+ const abortController = new AbortController();
350
+
351
+ const handlerPromise = handler!(event, abortController.signal);
352
+ // After a timeout we abort in-flight fetches/SDK calls via the signal.
353
+ // Those will reject with AbortError, but we've already returned the 504
354
+ // response — attach a no-op catch to prevent unhandled-rejection crashes.
355
+ handlerPromise.catch(() => {});
356
+
357
+ let timer: ReturnType<typeof setTimeout>;
358
+ const timeoutPromise = new Promise<never>((_, reject) => {
359
+ timer = setTimeout(() => {
360
+ // Signal the handler to stop any in-flight work (fetch, SDK calls).
361
+ abortController.abort();
362
+ reject(new HandlerTimeoutError());
363
+ }, deadlineMs);
364
+ // unref() ensures this timer alone won't keep the Lambda runtime alive
365
+ // if the handler finishes just before the timeout fires.
366
+ if (typeof timer === 'object' && 'unref' in timer) timer.unref();
367
+ });
368
+
369
+ try {
370
+ // Whichever settles first wins: handler success or timeout rejection.
371
+ const result = await Promise.race([handlerPromise, timeoutPromise]);
372
+ clearTimeout(timer!);
373
+ return result;
374
+ } catch (err) {
375
+ clearTimeout(timer!);
376
+ if (err instanceof HandlerTimeoutError) {
377
+ // Timeout won the race — build a 504 response. Format depends on
378
+ // whether the request targeted an RPC endpoint (structured JSON-RPC
379
+ // error envelope) or a plain HTTP path (simple error JSON).
380
+ const origin = event.headers?.origin || event.headers?.Origin || '*';
381
+ const requestPath = getRequestPath(event);
382
+ const isRpcPath = requestPath === BLOCKS_RPC_PREFIX || requestPath.startsWith(BLOCKS_RPC_PREFIX + '/');
383
+ const body = isRpcPath
384
+ ? errorResponse(504, 'Request timed out', null, { name: 'HandlerTimeoutError' })
385
+ : JSON.stringify({ error: 'Request timed out', code: 'HANDLER_TIMEOUT' });
386
+ return {
387
+ statusCode: 504,
388
+ headers: {
389
+ 'Content-Type': 'application/json',
390
+ 'Access-Control-Allow-Origin': origin,
391
+ 'Access-Control-Allow-Credentials': 'true',
392
+ },
393
+ body,
394
+ };
395
+ }
396
+ // Non-timeout errors (handler threw before deadline) propagate normally.
397
+ throw err;
398
+ }
399
+ };
400
+ }
401
+
402
+ class HandlerTimeoutError extends Error {
403
+ constructor() {
404
+ super('Handler timeout');
405
+ this.name = 'HandlerTimeoutError';
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Extract the request path from a Lambda event, normalizing between
411
+ * API Gateway v1 (REST) and v2 (HTTP API) event shapes.
412
+ *
413
+ * - v1 REST API: path is at `event.path`
414
+ * - v2 HTTP API: path is at `event.requestContext.http.path`
415
+ * - Fallback: `'/'`
416
+ */
417
+ function getRequestPath(event: any): string {
418
+ return event.path || event.requestContext?.http?.path || '/';
419
+ }
420
+
421
+ function createHandler(backend: any) {
422
+ return async (event: any, signal?: AbortSignal) => {
423
+ const eventClass = classifyEvent(event);
424
+
425
+ // ── WebSocket events (API Gateway WebSocket API) ──
426
+ if (eventClass === 'websocket') {
427
+ const handlers: Map<string, (record: any) => Promise<void>> =
428
+ (globalThis as any).__BLOCKS_LAMBDA_EVENT_HANDLERS__ ?? new Map();
429
+ for (const [key, handler] of handlers) {
430
+ if (key.startsWith('blocks.websocket:')) {
431
+ return handler(event);
432
+ }
433
+ }
434
+ console.error('WebSocket event received but no blocks.websocket handler registered');
435
+ return { statusCode: 500 };
436
+ }
437
+
438
+ // ── Batch/Stream events (SQS, Kinesis, DDB Streams) ──
439
+ if (eventClass === 'records') {
440
+ return handleEventSourceRecords(event, backend);
441
+ }
442
+
443
+ // ── Direct invoke with Blocks-controlled payload ──
444
+ if (eventClass === 'direct') {
445
+ const handlers: Map<string, (record: any) => Promise<void>> =
446
+ (globalThis as any).__BLOCKS_LAMBDA_EVENT_HANDLERS__ ?? new Map();
447
+ const identifier = event.jobName ?? event.id ?? event.source;
448
+ const key = `${event.source}:${identifier}`;
449
+ const handler = handlers.get(key);
450
+ if (!handler) {
451
+ console.error(`No handler registered for "${key}"`);
452
+ throw new Error(`No handler registered for "${key}"`);
453
+ }
454
+ return handler(event);
455
+ }
456
+
457
+ const origin = event.headers?.origin || event.headers?.Origin || '';
458
+ const httpMethod = event.httpMethod || event.requestContext?.http?.method;
459
+ const corsHeaders = buildCorsHeaders(origin);
460
+
461
+ // Reject cross-origin requests from disallowed origins
462
+ const patterns = getCorsPatterns();
463
+ if (origin && patterns && !isOriginAllowed(origin)) {
464
+ return corsRejection();
465
+ }
466
+
467
+ // Handle OPTIONS preflight
468
+ if (httpMethod === 'OPTIONS') {
469
+ return {
470
+ statusCode: 200,
471
+ headers: {
472
+ ...corsHeaders,
473
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS',
474
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
475
+ 'Access-Control-Max-Age': '86400',
476
+ },
477
+ body: '',
478
+ };
479
+ }
480
+
481
+ // Extract cookies from the inbound request and store them in
482
+ // AsyncLocalStorage so downstream code (e.g. the Blocks client making
483
+ // server-side API calls during SSR) can forward them automatically.
484
+ // Wraps both RawRoute and RPC handling so any handler that calls Blocks
485
+ // APIs server-side gets forwarded cookies.
486
+ const inboundCookies = event.headers?.cookie || event.headers?.Cookie || '';
487
+
488
+ return requestCookies.run(inboundCookies, async () => {
489
+ // RawRoute dispatch — check path-based routes before falling through to RPC
490
+ const requestPath = getRequestPath(event);
491
+ if (requestPath !== BLOCKS_RPC_PREFIX) {
492
+ const matched = matchRoute(httpMethod, requestPath);
493
+ if (matched) {
494
+ return handleRawRoute(event, matched.route, matched.params, corsHeaders, signal);
495
+ }
496
+ // No RawRoute matched and path is not the RPC endpoint — return 404
497
+ if (!requestPath.startsWith(BLOCKS_RPC_PREFIX)) {
498
+ return {
499
+ statusCode: 404,
500
+ headers: {
501
+ 'Content-Type': 'application/json',
502
+ ...corsHeaders,
503
+ },
504
+ body: JSON.stringify({ error: 'Not Found' }),
505
+ };
506
+ }
507
+ }
508
+
509
+ const rpcHeaders = {
510
+ 'Content-Type': 'application/json',
511
+ ...corsHeaders,
512
+ 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
513
+ 'Pragma': 'no-cache',
514
+ 'Expires': '0',
515
+ };
516
+
517
+ const { bodyText, bodyStream } = decodeEventBody(event);
518
+ const parsed = parseRpcRequest(bodyText);
519
+
520
+ if (!parsed.ok) {
521
+ return { statusCode: 200, headers: rpcHeaders, body: parsed.response };
522
+ }
523
+
524
+ const { apiNamespace, method, args, id: rpcId } = parsed.request;
525
+
526
+ try {
527
+ const headers = new Headers(event.headers || {});
528
+
529
+ let responseStatus = 200;
530
+ const responseHeaders = new Headers(rpcHeaders);
531
+ let responseBody: any;
532
+
533
+ const context = {
534
+ request: {
535
+ headers,
536
+ body: bodyStream,
537
+ json: async () => JSON.parse(bodyText),
538
+ text: async () => bodyText,
539
+ url: buildEventUrl(event),
540
+ params: {},
541
+ signal,
542
+ },
543
+ response: {
544
+ headers: responseHeaders,
545
+ get status() { return responseStatus; },
546
+ set status(code: number) { responseStatus = code; },
547
+ send: (body: any) => { responseBody = body; },
548
+ },
549
+ };
550
+
551
+ // Get the API by export name
552
+ const apiHandler = backend[apiNamespace];
553
+ if (!apiHandler) {
554
+ return { statusCode: 200, headers: rpcHeaders, body: methodNotFoundResponse(`API '${apiNamespace}' not found`, rpcId) };
555
+ }
556
+
557
+ // Call the handler to get methods
558
+ const apiMethods = typeof apiHandler === 'function'
559
+ ? apiHandler(context)
560
+ : apiHandler;
561
+
562
+ if (!apiMethods[method]) {
563
+ return { statusCode: 200, headers: rpcHeaders, body: methodNotFoundResponse(`'${method}' on API '${apiNamespace}'`, rpcId) };
564
+ }
565
+
566
+ const result = await apiMethods[method](...args);
567
+
568
+ return {
569
+ statusCode: responseStatus,
570
+ headers: Object.fromEntries(responseHeaders.entries()),
571
+ body: successResponse(responseBody ?? result, rpcId),
572
+ };
573
+ } catch (error: any) {
574
+ console.error('Lambda Error:', error);
575
+ return {
576
+ statusCode: 200,
577
+ headers: rpcHeaders,
578
+ body: errorResponseFromCatch(error, rpcId),
579
+ };
580
+ }
581
+ });
582
+ };
583
+ }
584
+
585
+ async function handleRawRoute(
586
+ event: any,
587
+ route: import('./raw-route.js').RegisteredRoute,
588
+ params: Record<string, string>,
589
+ corsHeaders: Record<string, string>,
590
+ signal?: AbortSignal,
591
+ ) {
592
+ const headers = new Headers(event.headers || {});
593
+ const { bodyText, bodyStream } = decodeEventBody(event);
594
+
595
+ let responseStatus = 200;
596
+ const responseHeaders = new Headers({
597
+ 'Content-Type': 'application/json',
598
+ ...corsHeaders,
599
+ 'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
600
+ 'Pragma': 'no-cache',
601
+ 'Expires': '0',
602
+ });
603
+ let responseBody: any;
604
+
605
+ const context = {
606
+ request: {
607
+ headers,
608
+ body: bodyStream,
609
+ json: async () => JSON.parse(bodyText),
610
+ text: async () => bodyText,
611
+ url: buildEventUrl(event),
612
+ params,
613
+ signal,
614
+ },
615
+ response: {
616
+ headers: responseHeaders,
617
+ get status() { return responseStatus; },
618
+ set status(code: number) { responseStatus = code; },
619
+ send: (body: any) => { responseBody = body; },
620
+ },
621
+ };
622
+
623
+ try {
624
+ await route.handler(context);
625
+
626
+ return {
627
+ statusCode: responseStatus,
628
+ headers: Object.fromEntries(
629
+ [...responseHeaders.entries()].filter(([k]) => k.toLowerCase() !== 'set-cookie')
630
+ ),
631
+ multiValueHeaders: {
632
+ 'Set-Cookie': responseHeaders.getSetCookie?.() ?? [],
633
+ },
634
+ body: responseBody !== undefined ? (typeof responseBody === 'string' ? responseBody : JSON.stringify(responseBody)) : '',
635
+ };
636
+ } catch (error: any) {
637
+ console.error('RawRoute Error:', error);
638
+ const status = error instanceof ApiError ? error.status : 500;
639
+ const body: Record<string, any> = { error: error.message };
640
+ if (error.name && error.name !== 'Error') body.name = error.name;
641
+ return {
642
+ statusCode: status,
643
+ headers: Object.fromEntries(
644
+ [...responseHeaders.entries()].filter(([k]) => k.toLowerCase() !== 'set-cookie')
645
+ ),
646
+ multiValueHeaders: {
647
+ 'Set-Cookie': responseHeaders.getSetCookie?.() ?? [],
648
+ },
649
+ body: JSON.stringify(body),
650
+ };
651
+ }
652
+ }
653
+
654
+ async function handleEventSourceRecords(event: any, _backend: any) {
655
+ const handlers: Map<string, (record: any) => Promise<void>> =
656
+ (globalThis as any).__BLOCKS_LAMBDA_EVENT_HANDLERS__ ?? new Map();
657
+
658
+ // Process all records in parallel for better throughput
659
+ const results = await Promise.allSettled(
660
+ event.Records.map(async (record: any) => {
661
+ const eventSource: string = record.eventSource;
662
+ const resourceId = record.eventSourceARN?.split(':').pop();
663
+ const key = `${eventSource}:${resourceId}`;
664
+ const handler = handlers.get(key);
665
+
666
+ if (!handler) {
667
+ console.error(`No event handler registered for ${key} (ARN: ${record.eventSourceARN})`);
668
+ throw new Error(`No event handler registered for ${key}`);
669
+ }
670
+
671
+ await handler(record);
672
+ return { record, success: true };
673
+ })
674
+ );
675
+
676
+ // Collect failures for SQS partial batch response
677
+ const batchItemFailures: Array<{ itemIdentifier: string }> = [];
678
+ let nonSqsFailure: Error | null = null;
679
+
680
+ results.forEach((result, index) => {
681
+ if (result.status === 'rejected') {
682
+ const record = event.Records[index];
683
+ const eventSource: string = record.eventSource;
684
+
685
+ if (eventSource === EventSourceMapping.SQS && record.messageId) {
686
+ console.error(`Handler failed for record ${record.messageId}:`, result.reason);
687
+ batchItemFailures.push({ itemIdentifier: record.messageId });
688
+ } else {
689
+ // For non-SQS event sources, we need to throw
690
+ nonSqsFailure = result.reason;
691
+ }
692
+ }
693
+ });
694
+
695
+ // For non-SQS event sources (Kinesis, DynamoDB Streams), throw on any failure
696
+ if (nonSqsFailure) {
697
+ throw nonSqsFailure;
698
+ }
699
+
700
+ // Return partial batch failure response for SQS
701
+ if (batchItemFailures.length > 0) {
702
+ return { batchItemFailures };
703
+ }
704
+
705
+ return {};
706
+ }