@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,323 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { AsyncLocalStorage } from 'node:async_hooks';
5
+
6
+ import { ApiError } from '../errors.js';
7
+
8
+ declare global {
9
+ var __BLOCKS_REQUEST_COOKIES_STORE__: AsyncLocalStorage<string> | undefined;
10
+ }
11
+
12
+ function getSsrCookies(): string | undefined {
13
+ const store = globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
14
+ if (!store || typeof store.getStore !== 'function') return undefined;
15
+ return store.getStore();
16
+ }
17
+
18
+ /**
19
+ * Get or lazily create the request cookie AsyncLocalStorage.
20
+ *
21
+ * In the API Lambda, `lambda-handler.ts` creates the store and registers it
22
+ * on `globalThis.__BLOCKS_REQUEST_COOKIES_STORE__`. In the SSR Lambda (a separate
23
+ * process), the store may not exist yet — this function creates it on demand.
24
+ *
25
+ * This module is server-only (never bundled for the browser), so direct
26
+ * `node:async_hooks` import is safe — no `webpackIgnore` needed.
27
+ */
28
+ function getRequestCookieStore(): AsyncLocalStorage<string> {
29
+ const existing = globalThis.__BLOCKS_REQUEST_COOKIES_STORE__;
30
+ if (existing) return existing;
31
+
32
+ const store = new AsyncLocalStorage<string>();
33
+ globalThis.__BLOCKS_REQUEST_COOKIES_STORE__ = store;
34
+ return store;
35
+ }
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Cookie Provider Registry
39
+ // ---------------------------------------------------------------------------
40
+
41
+ /**
42
+ * A function that attempts to detect cookies from a specific framework's
43
+ * request context. Returns the cookie string if available, or `undefined`
44
+ * if the framework is not active or no cookies are present.
45
+ */
46
+ export type CookieProvider = () => Promise<string | undefined>;
47
+
48
+ const providers: Array<{ name: string; detect: CookieProvider }> = [];
49
+
50
+ /**
51
+ * Register a framework-specific cookie provider for `withAuth()`.
52
+ *
53
+ * Providers are tried in registration order when `withAuth()` is called
54
+ * without explicit cookies. The first provider that returns a non-undefined
55
+ * value wins.
56
+ *
57
+ * Two providers are registered by default:
58
+ *
59
+ * - **Next.js** — reads cookies from `next/headers`. Works out of the box.
60
+ * - **Nuxt/Nitro** — reads cookies from the active Nitro request event
61
+ * (via the `unctx` `'nitro-app'` async context). Requires
62
+ * `nitro.experimental.asyncContext: true` in `nuxt.config.ts` so Nitro
63
+ * wraps each request in an `AsyncLocalStorage` context. Without that
64
+ * flag the provider returns `undefined` and a warning is emitted on
65
+ * first miss to point at the missing config (see `withAuth` for the
66
+ * no-cookies error path).
67
+ *
68
+ * Use this to add support for additional frameworks (SvelteKit, Astro, etc.)
69
+ * or custom cookie sources.
70
+ *
71
+ * @param name - Human-readable provider name (for debugging).
72
+ * @param detect - Async function that returns a cookie string or `undefined`.
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * import { registerCookieProvider } from '@aws-blocks/blocks/server';
77
+ *
78
+ * // SvelteKit provider
79
+ * registerCookieProvider('sveltekit', async () => {
80
+ * try {
81
+ * const { getRequestEvent } = await import('$app/server');
82
+ * const event = getRequestEvent();
83
+ * return event?.request.headers.get('cookie') ?? undefined;
84
+ * } catch {
85
+ * return undefined;
86
+ * }
87
+ * });
88
+ * ```
89
+ */
90
+ export function registerCookieProvider(name: string, detect: CookieProvider): void {
91
+ const existingIdx = providers.findIndex(p => p.name === name);
92
+ if (existingIdx >= 0) {
93
+ providers[existingIdx] = { name, detect };
94
+ } else {
95
+ providers.push({ name, detect });
96
+ }
97
+ }
98
+
99
+ // Built-in Next.js provider — registered by default
100
+ registerCookieProvider('nextjs', async () => {
101
+ try {
102
+ const mod = await import('next/headers');
103
+ const store = await mod.cookies();
104
+ const all = store.getAll();
105
+ if (all.length === 0) return undefined;
106
+ return all.map((c: { name: string; value: string }) => `${c.name}=${c.value}`).join('; ');
107
+ } catch {
108
+ return undefined;
109
+ }
110
+ });
111
+
112
+ // Built-in Nuxt/Nitro provider — requires `nitro.experimental.asyncContext: true`
113
+ //
114
+ // Reads the active request event from Nitro's async context, keyed
115
+ // `'nitro-app'` in `unctx`. Nitro's *documented* entry point for this is
116
+ // `useEvent()` from `nitropack/runtime` — but we deliberately do NOT use
117
+ // it here, and reach into `unctx.getContext('nitro-app')` directly instead.
118
+ //
119
+ // WHY (do not "fix" this back to `nitropack/runtime`): `@aws-blocks/core`
120
+ // is framework-agnostic. `withAuth` is re-exported through
121
+ // `@aws-blocks/blocks/server` and gets transitively imported by Next.js
122
+ // apps (and any other framework). `nitropack/runtime`'s entrypoint pulls
123
+ // in `#nitro-internal-virtual/*` subpath imports that ONLY resolve inside
124
+ // a Nitro build — webpack/Next.js can't resolve them and the consumer's
125
+ // `next build` fails with "Module not found: Can't resolve
126
+ // '#nitro-internal-virtual/error-handler'". `unctx` is a standalone leaf
127
+ // utility with no virtual imports, so it bundles cleanly from any
128
+ // framework. The documented-vs-internal-key trade-off loses to the
129
+ // bundler-safety requirement for a cross-framework package.
130
+ //
131
+ // Both approaches ride the same experimental async-context machinery and
132
+ // both require `experimental.asyncContext: true`. `nitroApp.use()` throws
133
+ // when no context instance is bound (the flag-off signature), which we
134
+ // distinguish from "not a Nitro app at all" below.
135
+ /** Minimal shape of the h3 `H3Event` we read from (Nitro v2 / Nuxt 4). */
136
+ type NitroH3Event = { node?: { req?: { headers?: { cookie?: string } } } };
137
+
138
+ let nuxtAsyncContextWarned = false;
139
+ registerCookieProvider('nuxt', async () => {
140
+ let getContext: typeof import('unctx').getContext;
141
+ try {
142
+ ({ getContext } = await import('unctx'));
143
+ } catch {
144
+ return undefined; // unctx not installed → not a Nuxt/Nitro app
145
+ }
146
+
147
+ // `getContext('nitro-app')` itself never throws — it lazily creates the
148
+ // context registry. `.use()` is what throws when no instance is bound.
149
+ const nitroAsyncContext = getContext('nitro-app');
150
+ let bound: { event?: NitroH3Event; request?: Request } | undefined;
151
+ try {
152
+ // `.use()` returns the bound NitroApp or throws.
153
+ //
154
+ // TODO(nitro-v3 / nuxt-5): Nitro v3 swaps h3 for srvx, so the bound
155
+ // context shape changes from `{ event }` (h3 `H3Event`, read below via
156
+ // `event.node.req.headers.cookie`) to `{ request }` (a standard Web
157
+ // `Request`, read via `request.headers.get('cookie')`). We read both
158
+ // shapes below so the provider keeps working across the cutover; revisit
159
+ // and drop the h3 branch once Nuxt 5 / Nitro v3 is the floor.
160
+ bound = nitroAsyncContext.use() as typeof bound;
161
+ } catch {
162
+ // In a Nitro runtime but no context bound for this call — almost
163
+ // always `experimental.asyncContext: true` missing from the config.
164
+ // Surface a hint exactly once per process so the developer sees the
165
+ // root cause, not a downstream generic "no cookies" 401. Suppressible
166
+ // via env var for tests / intentional setups.
167
+ if (
168
+ !nuxtAsyncContextWarned &&
169
+ process.env.BLOCKS_SUPPRESS_NUXT_ASYNC_CONTEXT_WARN !== '1'
170
+ ) {
171
+ nuxtAsyncContextWarned = true;
172
+ // eslint-disable-next-line no-console
173
+ console.warn(
174
+ '[@aws-blocks/core] withAuth: Nuxt/Nitro detected but the request context is not available. ' +
175
+ "Add `nitro: { experimental: { asyncContext: true } }` to nuxt.config.ts so withAuth() can read cookies from the active request. " +
176
+ 'See https://nuxt.com/docs/guide/going-further/experimental-features#asynccontext',
177
+ );
178
+ }
179
+ return undefined;
180
+ }
181
+
182
+ // h3 (Nitro v2): cookie lives on the Node request headers.
183
+ // srvx (Nitro v3): cookie lives on the Web `Request` headers. See the
184
+ // TODO above — the `request` branch future-proofs this for Nuxt 5.
185
+ const cookie =
186
+ bound?.event?.node?.req?.headers?.cookie ??
187
+ bound?.request?.headers?.get('cookie') ??
188
+ undefined;
189
+ return typeof cookie === 'string' && cookie.length > 0 ? cookie : undefined;
190
+ });
191
+
192
+ /**
193
+ * Try each registered provider in order; return the first non-undefined result.
194
+ */
195
+ async function detectFrameworkCookies(): Promise<string | undefined> {
196
+ for (const provider of providers) {
197
+ const result = await provider.detect();
198
+ if (result) return result;
199
+ }
200
+ return undefined;
201
+ }
202
+
203
+ /**
204
+ * Clear all registered cookie providers, including the built-in Next.js one.
205
+ *
206
+ * Primarily useful for testing. After calling this, you must re-register any
207
+ * providers you need (including Next.js if desired).
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * import { clearCookieProviders, registerCookieProvider } from '@aws-blocks/blocks/server';
212
+ *
213
+ * // In test setup
214
+ * clearCookieProviders();
215
+ * registerCookieProvider('test', async () => 'session=test');
216
+ * ```
217
+ */
218
+ export function clearCookieProviders(): void {
219
+ providers.length = 0;
220
+ }
221
+
222
+ /** @internal Read-only view of registered providers (for testing). */
223
+ export function _getProviders(): ReadonlyArray<{ name: string; detect: CookieProvider }> {
224
+ return providers;
225
+ }
226
+
227
+ /**
228
+ * Wraps an async function with authenticated cookie forwarding for SSR.
229
+ *
230
+ * In SSR server components, browser cookies aren't automatically forwarded
231
+ * to API calls. This wrapper reads cookies and makes them available to
232
+ * all Blocks API calls within the callback via `AsyncLocalStorage`.
233
+ *
234
+ * **Resolution order:**
235
+ * 1. Explicit `cookies` parameter (framework-agnostic)
236
+ * 2. Existing request context (Lambda handler already set it up)
237
+ * 3. Registered cookie providers — Next.js and Nuxt are built-in, plus any
238
+ * you've added via `registerCookieProvider`
239
+ * 4. Throws if no cookies found
240
+ *
241
+ * **Built-in providers:**
242
+ *
243
+ * | Framework | Source | Notes |
244
+ * |-----------|--------|-------|
245
+ * | Next.js | `next/headers` | Works out of the box. |
246
+ * | Nuxt/Nitro | Nitro async context (via `unctx`) | Requires `nitro: { experimental: { asyncContext: true } }` in `nuxt.config.ts`. With the flag off the provider returns `undefined` and emits a one-time warning naming the missing config. |
247
+ *
248
+ * @param fn - Async function containing Blocks API calls that need auth.
249
+ * @param cookies - Optional explicit cookie string. If omitted, auto-detects
250
+ * from the request context or registered providers. Pass this for frameworks
251
+ * without a registered provider (or use `registerCookieProvider` to add one).
252
+ * @returns The return value of `fn`.
253
+ *
254
+ * @example
255
+ * ```typescript
256
+ * // Next.js — auto-detects cookies from next/headers (built-in provider)
257
+ * import { withAuth } from '@aws-blocks/blocks/server';
258
+ *
259
+ * const posts = await withAuth(() => api.listMyPosts());
260
+ *
261
+ * // Multiple calls in one scope
262
+ * const data = await withAuth(async () => {
263
+ * const posts = await api.listMyPosts();
264
+ * const profile = await api.getProfile();
265
+ * return { posts, profile };
266
+ * });
267
+ *
268
+ * // Explicit cookies for any framework
269
+ * const posts = await withAuth(
270
+ * () => api.listMyPosts(),
271
+ * request.headers.get('cookie'),
272
+ * );
273
+ * ```
274
+ *
275
+ * @example
276
+ * ```typescript
277
+ * // Nuxt — auto-detects cookies via the active Nitro request event
278
+ * // (built-in provider). Requires the experimental.asyncContext flag.
279
+ * //
280
+ * // nuxt.config.ts
281
+ * // export default defineNuxtConfig({
282
+ * // nitro: { experimental: { asyncContext: true } },
283
+ * // });
284
+ * //
285
+ * // server/api/posts.get.ts
286
+ * import { withAuth } from '@aws-blocks/blocks/server';
287
+ *
288
+ * export default defineEventHandler(async () => {
289
+ * return withAuth(() => api.listMyPosts());
290
+ * });
291
+ * ```
292
+ *
293
+ * @throws {Error} If no cookies are found and no provider detected them.
294
+ */
295
+ export async function withAuth<T>(
296
+ fn: () => Promise<T>,
297
+ cookies?: string | null,
298
+ ): Promise<T> {
299
+ if (cookies != null && cookies.trim()) {
300
+ const store = getRequestCookieStore();
301
+ return store.run(cookies, fn);
302
+ }
303
+
304
+ const existing = getSsrCookies();
305
+ if (existing) {
306
+ return fn();
307
+ }
308
+
309
+ const detected = await detectFrameworkCookies();
310
+ if (detected) {
311
+ const store = getRequestCookieStore();
312
+ return store.run(detected, fn);
313
+ }
314
+
315
+ const providerNames = providers.map(p => p.name).join(', ');
316
+ throw new ApiError(
317
+ `withAuth: No authentication cookies found. ` +
318
+ `Tried providers: [${providerNames || 'none registered'}]. ` +
319
+ `Ensure the user is logged in and cookies are being forwarded, ` +
320
+ `or pass cookies explicitly as the second argument.`,
321
+ 401,
322
+ );
323
+ }
@@ -0,0 +1,226 @@
1
+ import { request as httpsRequest } from 'node:https';
2
+ import { request as httpRequest } from 'node:http';
3
+ import { existsSync, readFileSync, mkdirSync, openSync, writeSync, closeSync, writeFileSync, constants } from 'node:fs';
4
+ import path from 'node:path';
5
+ import { debuglog } from 'node:util';
6
+ import { CORE_VERSION } from '../version.js';
7
+ import { Scope } from '../common/index.js';
8
+ import { isTelemetryEnabled } from './consent.js';
9
+ import { collectEnvironment } from './environment.js';
10
+ import { getInstallationId, getProjectId, generateEventId } from './identifiers.js';
11
+ import type { BlocksTelemetryEvent, BuildAndSendEventOptions } from './types.js';
12
+
13
+ // Debug log: writes to stderr via NODE_DEBUG=blocks-telemetry (developer-facing, for troubleshooting)
14
+ const debug = debuglog('blocks-telemetry');
15
+
16
+ const DEFAULT_ENDPOINT = 'https://blocks-telemetry.us-east-1.api.aws/metrics';
17
+ const TIMEOUT_MS = 500;
18
+ const TELEMETRY_VERSION = '1.0.0';
19
+
20
+ function getEndpoint(): string {
21
+ return process.env.BLOCKS_TELEMETRY_ENDPOINT || DEFAULT_ENDPOINT;
22
+ }
23
+
24
+ /**
25
+ * Parse `--telemetry-file=/path/to/file.json` from process.argv.
26
+ *
27
+ * Supports both `--telemetry-file=path` and `--telemetry-file path` forms.
28
+ *
29
+ * @returns The file path if the flag is present, undefined otherwise.
30
+ *
31
+ * @example
32
+ * // Capture telemetry to file (also sends HTTP when enabled):
33
+ * // npx tsx aws-blocks/scripts/server.ts --telemetry-file=/tmp/events.json
34
+ *
35
+ * // Capture WITHOUT sending (disable HTTP, file still writes):
36
+ * // AWS_BLOCKS_DISABLE_TELEMETRY=1 npx tsx aws-blocks/scripts/server.ts --telemetry-file=/tmp/events.json
37
+ */
38
+ export function getTelemetryFilePath(): string | undefined {
39
+ const arg = process.argv.find(a => a.startsWith('--telemetry-file='));
40
+ if (arg) {
41
+ const p = arg.slice('--telemetry-file='.length);
42
+ return p.trim() === '' ? undefined : p;
43
+ }
44
+ const idx = process.argv.indexOf('--telemetry-file');
45
+ if (idx !== -1 && process.argv[idx + 1] && !process.argv[idx + 1].startsWith('-')) {
46
+ return process.argv[idx + 1];
47
+ }
48
+ return undefined;
49
+ }
50
+
51
+ // File sink: writes to --telemetry-file path (user-facing, for debugging/testing)
52
+ function writeToTelemetryFile(event: BlocksTelemetryEvent): void {
53
+ const filePath = getTelemetryFilePath();
54
+ if (!filePath) return; // getTelemetryFilePath already rejects empty/whitespace
55
+
56
+ try {
57
+ const dir = path.dirname(filePath);
58
+ if (!existsSync(dir)) {
59
+ mkdirSync(dir, { recursive: true });
60
+ }
61
+
62
+ // O_CREAT | O_EXCL: atomic create — fails with EEXIST if file already exists
63
+ const fd = openSync(filePath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 0o644);
64
+ const content = JSON.stringify([event], null, 2);
65
+ writeSync(fd, content);
66
+ closeSync(fd);
67
+ } catch (err: any) {
68
+ // EEXIST = file already existed → skip (protects user data)
69
+ // All other errors silently ignored — telemetry must never affect commands
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Constructs a telemetry event without sending it.
75
+ * Useful for testing event structure without I/O side effects.
76
+ * @internal
77
+ */
78
+ export function buildEvent(opts: BuildAndSendEventOptions): BlocksTelemetryEvent {
79
+ const { blocks, totalCount, customBlocksCount } = Scope.getRegisteredBlocks();
80
+
81
+ let templateName: string | undefined = opts.product?.template;
82
+ let templateVersion: string | undefined = opts.product?.templateVersion;
83
+ try {
84
+ const pkgPath = path.resolve(process.cwd(), 'package.json');
85
+ if (existsSync(pkgPath)) {
86
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
87
+ if (pkg.blocksTemplate) templateName = templateName || pkg.blocksTemplate;
88
+ if (pkg.blocksTemplateVersion) templateVersion = templateVersion || pkg.blocksTemplateVersion;
89
+ }
90
+ } catch {
91
+ // template info is best-effort
92
+ }
93
+
94
+ const buildingBlocks = blocks;
95
+
96
+ return {
97
+ telemetryVersion: TELEMETRY_VERSION,
98
+ identifiers: {
99
+ installationId: getInstallationId(),
100
+ projectId: getProjectId(),
101
+ eventId: generateEventId(),
102
+ timestamp: new Date().toISOString(),
103
+ },
104
+ event: {
105
+ command: opts.command,
106
+ state: opts.state,
107
+ duration: opts.duration,
108
+ ...(opts.error && { error: opts.error }),
109
+ },
110
+ environment: collectEnvironment(),
111
+ product: {
112
+ blocksVersion: CORE_VERSION,
113
+ ...(opts.product?.cdkVersion && { cdkVersion: opts.product.cdkVersion }),
114
+ ...(opts.product?.framework && { framework: opts.product.framework }),
115
+ ...(templateName && {
116
+ template: {
117
+ name: templateName,
118
+ ...(templateVersion && { version: templateVersion }),
119
+ },
120
+ }),
121
+ ...(buildingBlocks.length > 0 && { buildingBlocks }),
122
+ },
123
+ ...(opts.counters || totalCount > 0 || customBlocksCount > 0
124
+ ? {
125
+ counters: {
126
+ blocksCount: opts.counters?.blocksCount ?? totalCount,
127
+ ...(opts.counters?.customBuildingBlocks !== undefined
128
+ ? { customBuildingBlocks: opts.counters.customBuildingBlocks }
129
+ : customBlocksCount > 0 ? { customBuildingBlocks: customBlocksCount } : undefined),
130
+ },
131
+ }
132
+ : undefined),
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Build a complete telemetry event and send it to the collection endpoint.
138
+ *
139
+ * This is the single entry point for all telemetry emission. It handles:
140
+ * 1. Early exit — if telemetry is disabled AND no `--telemetry-file` is set,
141
+ * returns immediately with no side effects (no IDs persisted, no notice)
142
+ * 2. Full payload construction (identifiers, environment, product info)
143
+ * 3. File sink — writes to the file specified by `--telemetry-file` (if set),
144
+ * regardless of opt-out status (inspired by CDK CLI's --telemetry-file)
145
+ * 4. Privacy filtering — custom BB names are NEVER sent, only counted
146
+ * 5. HTTP sink — fire-and-forget POST (only when telemetry is enabled)
147
+ *
148
+ * The file sink fires unconditionally when `--telemetry-file` is set.
149
+ * The HTTP sink only fires when telemetry is enabled. Callers never need to
150
+ * import consent, identifier, or environment utilities directly.
151
+ *
152
+ * @param opts - Event metadata (command, state, duration, optional error/product/counters)
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * buildAndSendEvent({
157
+ * command: 'deploy',
158
+ * state: 'SUCCESS',
159
+ * duration: 4500,
160
+ * product: { cdkVersion: '2.150.0' },
161
+ * });
162
+ * ```
163
+ */
164
+ export function buildAndSendEvent(opts: BuildAndSendEventOptions): void {
165
+ try {
166
+ const filePath = getTelemetryFilePath();
167
+ const enabled = isTelemetryEnabled();
168
+ if (!filePath && !enabled) return;
169
+
170
+ const event = buildEvent(opts);
171
+
172
+ if (filePath) writeToTelemetryFile(event);
173
+ if (enabled) sendEvent(event);
174
+ } catch {
175
+ // Telemetry must never throw or affect the user's command
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Send a pre-built telemetry event to the collection endpoint.
181
+ *
182
+ * Fire-and-forget: no retry, 500ms timeout, all errors silently swallowed.
183
+ * Debug output available via `NODE_DEBUG=blocks-telemetry`.
184
+ */
185
+ export function sendEvent(event: BlocksTelemetryEvent): void {
186
+ try {
187
+ const endpoint = getEndpoint();
188
+ const payload = JSON.stringify(event);
189
+
190
+ // E2E test sink: writes to BLOCKS_TELEMETRY_FILE env path (test-facing, for assertions)
191
+ if (process.env.BLOCKS_TELEMETRY_FILE) {
192
+ try { writeFileSync(process.env.BLOCKS_TELEMETRY_FILE, payload); } catch {}
193
+ }
194
+
195
+ debug('sending event to %s (%d bytes)', endpoint, Buffer.byteLength(payload));
196
+
197
+ const url = new URL(endpoint);
198
+ const isHttps = url.protocol === 'https:';
199
+ const requestFn = isHttps ? httpsRequest : httpRequest;
200
+
201
+ const req = requestFn(
202
+ {
203
+ hostname: url.hostname,
204
+ port: url.port || (isHttps ? '443' : '80'),
205
+ path: url.pathname + url.search,
206
+ method: 'POST',
207
+ headers: {
208
+ 'Content-Type': 'application/json',
209
+ 'Content-Length': Buffer.byteLength(payload),
210
+ },
211
+ timeout: TIMEOUT_MS,
212
+ },
213
+ (res) => {
214
+ debug('event sent (status=%d)', res.statusCode);
215
+ res.resume();
216
+ },
217
+ );
218
+
219
+ req.on('error', (err) => { debug('send failed: %s', err.message); });
220
+ req.on('timeout', () => { debug('send timed out'); req.destroy(); });
221
+ req.write(payload);
222
+ req.end();
223
+ } catch {
224
+ // Telemetry must never throw or affect the user's command
225
+ }
226
+ }
@@ -0,0 +1,52 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
5
+ import { dirname } from 'node:path';
6
+
7
+ interface TelemetryConfig {
8
+ enabled?: boolean;
9
+ projectId?: string;
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ interface BlocksConfig {
14
+ telemetry?: TelemetryConfig;
15
+ [key: string]: unknown;
16
+ }
17
+
18
+ /**
19
+ * Read an existing config file, merge the telemetry.enabled setting, and write it back.
20
+ * Creates the file and parent directories if they don't exist.
21
+ * Preserves all other keys in the config file and in the telemetry object
22
+ * (e.g., projectId).
23
+ *
24
+ * Config format:
25
+ * ```json
26
+ * { "telemetry": { "enabled": true, "projectId": "..." } }
27
+ * ```
28
+ *
29
+ * @param configPath - Absolute path to the config file
30
+ * @param telemetryEnabled - Whether telemetry should be enabled
31
+ */
32
+ export function writeConfigTelemetry(configPath: string, telemetryEnabled: boolean): void {
33
+ let existing: BlocksConfig = {};
34
+
35
+ try {
36
+ const content = readFileSync(configPath, 'utf-8');
37
+ existing = JSON.parse(content) as BlocksConfig;
38
+ } catch {
39
+ // File doesn't exist or is invalid — start fresh
40
+ }
41
+
42
+ const telemetry: TelemetryConfig = (existing.telemetry && typeof existing.telemetry === 'object')
43
+ ? { ...existing.telemetry }
44
+ : {};
45
+
46
+ telemetry.enabled = telemetryEnabled;
47
+ existing.telemetry = telemetry;
48
+
49
+ const dir = dirname(configPath);
50
+ mkdirSync(dir, { recursive: true });
51
+ writeFileSync(configPath, JSON.stringify(existing, null, 2) + '\n', 'utf-8');
52
+ }