@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,664 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Extract TypeScript type information from ApiNamespace method signatures.
5
+ *
6
+ * Uses `ts.createProgram` with a full type checker to extract both explicit
7
+ * and inferred types — including return types that have no annotation.
8
+ * Converts TS types to JSON Schema for the OpenRPC spec.
9
+ *
10
+ * Zod-validated methods still take priority in generate-spec.ts — this
11
+ * module provides the fallback for plain TS methods so they emit real
12
+ * types instead of { type: "unknown" }.
13
+ */
14
+ import * as ts from 'typescript';
15
+ import { dirname, resolve } from 'path';
16
+ import { existsSync } from 'fs';
17
+ /**
18
+ * Public so `generate-spec.ts` and any future emitter can share the same
19
+ * vocabulary. Spelt as a single token to avoid hyphenation surprises in
20
+ * JSDoc parsers.
21
+ */
22
+ export const BLOCKS_SKIP_CODEGEN_TAG = 'blocksSkipCodegen';
23
+ function hasKitSkipCodegenTag(node) {
24
+ for (const tag of ts.getJSDocTags(node)) {
25
+ if (tag.tagName.text === BLOCKS_SKIP_CODEGEN_TAG)
26
+ return true;
27
+ }
28
+ return false;
29
+ }
30
+ /**
31
+ * Pure-AST scan for method names tagged with `@blocksSkipCodegen` inside the
32
+ * `ApiNamespace(...)` calls of a TS source file. Returns a Set of method
33
+ * names (the OpenRPC emitter qualifies them by namespace later).
34
+ *
35
+ * Distinct from {@link extractMethodTypes} because that function builds a
36
+ * full `ts.Program` + type checker, and any failure inside type
37
+ * resolution (an imported module that doesn't typecheck, a third-party
38
+ * `.d.ts` mismatch) silently empties the returned Map. The skip set must
39
+ * survive those crashes, so this function uses only the parser.
40
+ */
41
+ export function extractSkipCodegenMethods(sourcePath) {
42
+ const result = new Set();
43
+ const absPath = resolve(sourcePath);
44
+ const fileText = ts.sys.readFile(absPath);
45
+ if (!fileText)
46
+ return result;
47
+ const sourceFile = ts.createSourceFile(absPath, fileText, ts.ScriptTarget.ESNext,
48
+ /*setParentNodes*/ true, ts.ScriptKind.TS);
49
+ function visitObjectLiteral(obj) {
50
+ for (const prop of obj.properties) {
51
+ if (ts.isMethodDeclaration(prop) &&
52
+ prop.name &&
53
+ ts.isIdentifier(prop.name) &&
54
+ hasKitSkipCodegenTag(prop)) {
55
+ result.add(prop.name.text);
56
+ }
57
+ }
58
+ }
59
+ function visit(node) {
60
+ if (ts.isNewExpression(node)) {
61
+ const callee = node.expression;
62
+ if (ts.isIdentifier(callee) && callee.text === 'ApiNamespace' && node.arguments && node.arguments.length >= 2) {
63
+ const handler = node.arguments[node.arguments.length - 1];
64
+ if (ts.isArrowFunction(handler) || ts.isFunctionExpression(handler)) {
65
+ const body = handler.body;
66
+ if (ts.isParenthesizedExpression(body) && ts.isObjectLiteralExpression(body.expression)) {
67
+ visitObjectLiteral(body.expression);
68
+ }
69
+ else if (ts.isObjectLiteralExpression(body)) {
70
+ visitObjectLiteral(body);
71
+ }
72
+ else if (ts.isBlock(body)) {
73
+ for (const stmt of body.statements) {
74
+ if (ts.isReturnStatement(stmt) && stmt.expression) {
75
+ if (ts.isObjectLiteralExpression(stmt.expression)) {
76
+ visitObjectLiteral(stmt.expression);
77
+ }
78
+ else if (ts.isParenthesizedExpression(stmt.expression) &&
79
+ ts.isObjectLiteralExpression(stmt.expression.expression)) {
80
+ visitObjectLiteral(stmt.expression.expression);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ }
88
+ ts.forEachChild(node, visit);
89
+ }
90
+ visit(sourceFile);
91
+ return result;
92
+ }
93
+ // ── Main entry point ────────────────────────────────────────────────────────
94
+ /**
95
+ * Parse a TypeScript source file with full type checking and extract type
96
+ * info for all methods inside `ApiNamespace(...)` calls.
97
+ *
98
+ * Uses `ts.createProgram` to resolve imports and infer return types.
99
+ * Falls back to AST-only parsing if program creation fails.
100
+ */
101
+ export function extractMethodTypes(sourcePath) {
102
+ const result = new Map();
103
+ const absPath = resolve(sourcePath);
104
+ // Find tsconfig.json by walking up from the source file
105
+ const configPath = findTsConfig(dirname(absPath));
106
+ let program;
107
+ let checker;
108
+ let sourceFile;
109
+ if (configPath) {
110
+ const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
111
+ const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, dirname(configPath));
112
+ // Only include our target file — the compiler resolves imports on demand.
113
+ // This is much faster than passing the full fileNames list from tsconfig.
114
+ const options = { ...parsed.options, skipLibCheck: true, skipDefaultLibCheck: true };
115
+ program = ts.createProgram([absPath], options);
116
+ }
117
+ else {
118
+ // No tsconfig — create a minimal program
119
+ program = ts.createProgram([absPath], {
120
+ target: ts.ScriptTarget.ESNext,
121
+ module: ts.ModuleKind.ESNext,
122
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
123
+ strict: true,
124
+ esModuleInterop: true,
125
+ skipLibCheck: true,
126
+ });
127
+ }
128
+ checker = program.getTypeChecker();
129
+ sourceFile = program.getSourceFile(absPath);
130
+ if (!sourceFile)
131
+ return result;
132
+ // Find new ApiNamespace(scope, name, handler) and extract methods using the type checker
133
+ ts.forEachChild(sourceFile, function visit(node) {
134
+ if (ts.isNewExpression(node)) {
135
+ const fnName = node.expression;
136
+ if (ts.isIdentifier(fnName) && fnName.text === 'ApiNamespace' && node.arguments && node.arguments.length >= 2) {
137
+ const handlerArg = node.arguments[node.arguments.length - 1];
138
+ extractMethodsFromHandler(handlerArg, checker, sourceFile, result);
139
+ }
140
+ }
141
+ ts.forEachChild(node, visit);
142
+ });
143
+ // Second pass: resolve types for indirect ApiNamespace exports (e.g., auth.createApi()).
144
+ // The AST walk above only finds `new ApiNamespace(...)` in this file.
145
+ // For methods created by Building Block helpers in other files, use the type
146
+ // checker to resolve the call's return type and extract method signatures.
147
+ ts.forEachChild(sourceFile, (node) => {
148
+ if (!ts.isVariableStatement(node))
149
+ return;
150
+ for (const decl of node.declarationList.declarations) {
151
+ if (!decl.initializer || !ts.isIdentifier(decl.name))
152
+ continue;
153
+ // Skip if we already extracted methods for this via the AST walk
154
+ if (ts.isNewExpression(decl.initializer)) {
155
+ const callee = decl.initializer.expression;
156
+ if (ts.isIdentifier(callee) && callee.text === 'ApiNamespace')
157
+ continue;
158
+ }
159
+ // Use the type checker to get the type of the initializer expression.
160
+ // For `auth.createApi()`, this resolves through the method's return type
161
+ // to the `AsyncAPI<T>` type that ApiNamespace returns.
162
+ const initType = checker.getTypeAtLocation(decl.initializer);
163
+ extractMethodsFromResolvedType(initType, checker, result);
164
+ }
165
+ });
166
+ return result;
167
+ }
168
+ // ── tsconfig discovery ──────────────────────────────────────────────────────
169
+ function findTsConfig(dir) {
170
+ let current = dir;
171
+ for (let i = 0; i < 10; i++) {
172
+ const candidate = resolve(current, 'tsconfig.json');
173
+ if (existsSync(candidate))
174
+ return candidate;
175
+ const parent = dirname(current);
176
+ if (parent === current)
177
+ break;
178
+ current = parent;
179
+ }
180
+ return undefined;
181
+ }
182
+ // ── Handler extraction ──────────────────────────────────────────────────────
183
+ function extractMethodsFromHandler(handlerNode, checker, sourceFile, result) {
184
+ let objectLiteral;
185
+ if (ts.isArrowFunction(handlerNode) || ts.isFunctionExpression(handlerNode)) {
186
+ const body = handlerNode.body;
187
+ if (ts.isParenthesizedExpression(body)) {
188
+ if (ts.isObjectLiteralExpression(body.expression)) {
189
+ objectLiteral = body.expression;
190
+ }
191
+ }
192
+ else if (ts.isObjectLiteralExpression(body)) {
193
+ objectLiteral = body;
194
+ }
195
+ else if (ts.isBlock(body)) {
196
+ for (const stmt of body.statements) {
197
+ if (ts.isReturnStatement(stmt) && stmt.expression) {
198
+ if (ts.isObjectLiteralExpression(stmt.expression)) {
199
+ objectLiteral = stmt.expression;
200
+ }
201
+ else if (ts.isParenthesizedExpression(stmt.expression) &&
202
+ ts.isObjectLiteralExpression(stmt.expression.expression)) {
203
+ objectLiteral = stmt.expression.expression;
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ if (!objectLiteral)
210
+ return;
211
+ for (const prop of objectLiteral.properties) {
212
+ if (ts.isMethodDeclaration(prop) && prop.name && ts.isIdentifier(prop.name)) {
213
+ const methodName = prop.name.text;
214
+ const info = extractMethodTypeInfo(prop, checker, sourceFile);
215
+ if (info)
216
+ result.set(methodName, info);
217
+ }
218
+ }
219
+ }
220
+ function extractMethodTypeInfo(method, checker, sourceFile) {
221
+ const params = [];
222
+ for (const param of method.parameters) {
223
+ const name = ts.isIdentifier(param.name) ? param.name.text
224
+ : param.name.getText(sourceFile);
225
+ const required = !param.questionToken && !param.initializer;
226
+ // Use the type checker to get the resolved type (handles imported types, aliases, etc.)
227
+ const symbol = checker.getSymbolAtLocation(param.name);
228
+ let schema = { type: 'unknown' };
229
+ if (symbol) {
230
+ const paramType = checker.getTypeOfSymbolAtLocation(symbol, param);
231
+ schema = tsTypeToJsonSchema(paramType, checker);
232
+ }
233
+ else if (param.type) {
234
+ // Fallback to AST-based extraction
235
+ schema = typeNodeToJsonSchema(param.type, sourceFile);
236
+ }
237
+ params.push({ name, required, schema });
238
+ }
239
+ // Return type: use the type checker to get the inferred return type
240
+ let returnType = { type: 'unknown' };
241
+ let transferable;
242
+ const signature = checker.getSignatureFromDeclaration(method);
243
+ if (signature) {
244
+ let retType = checker.getReturnTypeOfSignature(signature);
245
+ // Unwrap Promise<T>
246
+ retType = unwrapPromise(retType, checker);
247
+ // Check if the return type is a transferable before converting to schema.
248
+ // Pass the syntactic return-type node so we can distinguish between
249
+ // `RealtimeChannel` (default `T = unknown` filled in) and
250
+ // `RealtimeChannel<unknown>` (explicit) — the resolved `ts.Type` looks
251
+ // identical for both, but only the latter should emit `typeArgs: [{}]`.
252
+ const retTypeNode = unwrapPromiseTypeNode(method.type);
253
+ transferable = detectTransferable(retType, checker, retTypeNode);
254
+ returnType = tsTypeToJsonSchema(retType, checker);
255
+ }
256
+ const skipCodegen = hasKitSkipCodegenTag(method) || undefined;
257
+ return { params, returnType, transferable, skipCodegen };
258
+ }
259
+ /**
260
+ * Walk a return-type AST node, unwrapping a single layer of `Promise<T>`,
261
+ * and return the inner `TypeReferenceNode` if any. Used to recover the
262
+ * syntactic type-arguments the customer wrote — `Promise<RealtimeChannel>`
263
+ * has no inner `<...>`, while `Promise<RealtimeChannel<X>>` does.
264
+ */
265
+ function unwrapPromiseTypeNode(node) {
266
+ if (!node || !ts.isTypeReferenceNode(node))
267
+ return undefined;
268
+ const name = ts.isIdentifier(node.typeName) ? node.typeName.text : node.typeName.getText();
269
+ if (name === 'Promise' && node.typeArguments && node.typeArguments.length === 1) {
270
+ const inner = node.typeArguments[0];
271
+ return ts.isTypeReferenceNode(inner) ? inner : undefined;
272
+ }
273
+ return node;
274
+ }
275
+ // ── Type-checker-based extraction for indirect ApiNamespace calls ────────────
276
+ /**
277
+ * Extract method type info from a resolved `ts.Type` (e.g., the return type
278
+ * of `auth.createApi()`). This handles the case where `ApiNamespace(...)` is
279
+ * called inside another module — the AST walk can't see it, but the type
280
+ * checker resolves the full return type including method signatures.
281
+ *
282
+ * The type is the `AsyncAPI<T>` wrapper returned by `ApiNamespace`, which is
283
+ * a mapped type where each property is `(...args: Args) => Promise<R>`.
284
+ * We also handle the case where the type is callable (the raw handler function
285
+ * before `AsyncAPI` wrapping) — we call-resolve it and inspect the result.
286
+ */
287
+ function extractMethodsFromResolvedType(type, checker, result) {
288
+ // The runtime value of an ApiNamespace export is the handler function itself
289
+ // (with the marker symbol attached). Its TS type is `AsyncAPI<T>`, which is
290
+ // an object type with method-like properties. But it could also be typed as
291
+ // the handler function `(context: BlocksContext) => T`. Try both:
292
+ // 1. If the type has call signatures, resolve the return type (handler fn case)
293
+ // 2. Otherwise, treat it as the AsyncAPI<T> object directly
294
+ let methodsType = type;
295
+ // If the type is callable (handler function), resolve its return type
296
+ const callSigs = type.getCallSignatures();
297
+ if (callSigs.length > 0) {
298
+ const retType = checker.getReturnTypeOfSignature(callSigs[0]);
299
+ // The return type should be the object with method properties
300
+ if (retType.getProperties().length > 0) {
301
+ methodsType = retType;
302
+ }
303
+ }
304
+ const props = methodsType.getProperties();
305
+ if (props.length === 0)
306
+ return;
307
+ for (const prop of props) {
308
+ const propName = prop.getName();
309
+ // Skip internal symbols and the marker
310
+ if (propName.startsWith('_') || propName === 'Symbol(blocks:ApiNamespace)')
311
+ continue;
312
+ // Don't overwrite methods already found by the AST walk
313
+ if (result.has(propName))
314
+ continue;
315
+ const propType = checker.getTypeOfSymbol(prop);
316
+ const methodSigs = propType.getCallSignatures();
317
+ if (methodSigs.length === 0)
318
+ continue;
319
+ const sig = methodSigs[0];
320
+ // Extract params
321
+ const params = [];
322
+ for (const paramSymbol of sig.getParameters()) {
323
+ const paramType = checker.getTypeOfSymbol(paramSymbol);
324
+ const schema = tsTypeToJsonSchema(paramType, checker);
325
+ const paramDecl = paramSymbol.valueDeclaration;
326
+ const isOptional = paramDecl && ts.isParameter(paramDecl)
327
+ ? !!(paramDecl.questionToken || paramDecl.initializer)
328
+ : (paramSymbol.flags & ts.SymbolFlags.Optional) !== 0;
329
+ params.push({
330
+ name: paramSymbol.getName(),
331
+ required: !isOptional,
332
+ schema,
333
+ });
334
+ }
335
+ // Extract return type (unwrap Promise<T>)
336
+ let retType = checker.getReturnTypeOfSignature(sig);
337
+ retType = unwrapPromise(retType, checker);
338
+ // Check if the return type is a transferable before converting to schema
339
+ const transferable = detectTransferable(retType, checker);
340
+ const returnType = tsTypeToJsonSchema(retType, checker);
341
+ // JSDoc lives on the original method declaration, which we can reach
342
+ // via the symbol's `valueDeclaration` (the `MethodDeclaration` node in
343
+ // the BB-helper file that minted the AsyncAPI<T> shape).
344
+ let skipCodegen;
345
+ const declaration = prop.valueDeclaration;
346
+ if (declaration && hasKitSkipCodegenTag(declaration)) {
347
+ skipCodegen = true;
348
+ }
349
+ result.set(propName, { params, returnType, transferable, skipCodegen });
350
+ }
351
+ }
352
+ // ── Transferable detection ───────────────────────────────────────────────────
353
+ /**
354
+ * Inspect a resolved ts.Type for the transferable protocol:
355
+ * - Has a method named `toJSON`
356
+ * - toJSON's return type has a property `__blocks` with a string LITERAL type
357
+ *
358
+ * If detected, extracts the blocks tag and resolves generic type arguments.
359
+ * Returns undefined if the type is not transferable.
360
+ *
361
+ * `syntacticNode` is the AST `TypeReferenceNode` the customer wrote (e.g.
362
+ * `RealtimeChannel<CursorPosition>`). It's passed in alongside the resolved
363
+ * `ts.Type` so we can tell the difference between an unwritten default
364
+ * (`RealtimeChannel`, where `T = unknown` is filled in by the checker) and
365
+ * an explicit `RealtimeChannel<unknown>`. The two look identical in the
366
+ * resolved `ts.Type`, but only the explicit form should emit a `[{}]` slot.
367
+ */
368
+ function detectTransferable(type, checker, syntacticNode) {
369
+ // Step 1-2: Get properties of the type and find `toJSON`
370
+ const props = checker.getPropertiesOfType(type);
371
+ const toJsonSymbol = props.find(p => p.getName() === 'toJSON');
372
+ if (!toJsonSymbol)
373
+ return undefined;
374
+ // Step 3: Get the type of `toJSON`
375
+ const toJsonType = checker.getTypeOfSymbol(toJsonSymbol);
376
+ // Step 4: Get call signatures of the `toJSON` type
377
+ const callSignatures = toJsonType.getCallSignatures();
378
+ if (callSignatures.length === 0)
379
+ return undefined;
380
+ // Step 5: Get the return type of the first call signature
381
+ const returnType = checker.getReturnTypeOfSignature(callSignatures[0]);
382
+ // Step 6: Get properties of the return type, find `__blocks`
383
+ const returnProps = checker.getPropertiesOfType(returnType);
384
+ const blocksSymbol = returnProps.find(p => p.getName() === '__blocks');
385
+ if (!blocksSymbol)
386
+ return undefined;
387
+ // Step 7: Get the type of `__blocks`
388
+ const blocksType = checker.getTypeOfSymbol(blocksSymbol);
389
+ // Step 8: Check if it's a string literal type
390
+ if (!(blocksType.getFlags() & ts.TypeFlags.StringLiteral))
391
+ return undefined;
392
+ // Step 9: Extract the literal value as `blocksTag`
393
+ const blocksTag = blocksType.value;
394
+ // Step 10-11: For generic type arguments — only emit them when the
395
+ // customer actually wrote `<...>` in the source. If `syntacticNode` has
396
+ // no `typeArguments`, treat the type as non-generic (defaults filled in
397
+ // by the checker shouldn't appear in the spec).
398
+ const typeArgs = [];
399
+ const wroteTypeArgs = syntacticNode?.typeArguments && syntacticNode.typeArguments.length > 0;
400
+ if (wroteTypeArgs) {
401
+ const typeRef = type;
402
+ const resolvedArgs = typeRef.typeArguments ?? [];
403
+ for (const arg of resolvedArgs) {
404
+ // Explicit `unknown` / `any` → empty schema (matches Req 4.3).
405
+ const argFlags = arg.getFlags();
406
+ if (argFlags & ts.TypeFlags.Unknown || argFlags & ts.TypeFlags.Any) {
407
+ typeArgs.push({});
408
+ }
409
+ else {
410
+ typeArgs.push(tsTypeToJsonSchema(arg, checker));
411
+ }
412
+ }
413
+ }
414
+ return { blocksTag, typeArgs };
415
+ }
416
+ // ── ts.Type → JSON Schema conversion ────────────────────────────────────────
417
+ /** Recursion guard to prevent infinite loops on recursive types. */
418
+ const MAX_DEPTH = 6;
419
+ /**
420
+ * Convert a resolved `ts.Type` to JSON Schema.
421
+ * This handles inferred types, imported types, type aliases, etc.
422
+ */
423
+ function tsTypeToJsonSchema(type, checker, depth = 0) {
424
+ if (depth > MAX_DEPTH)
425
+ return { type: 'object' };
426
+ const flags = type.getFlags();
427
+ // Primitives
428
+ if (flags & ts.TypeFlags.String)
429
+ return { type: 'string' };
430
+ if (flags & ts.TypeFlags.Number)
431
+ return { type: 'number' };
432
+ if (flags & ts.TypeFlags.Boolean)
433
+ return { type: 'boolean' };
434
+ if (flags & ts.TypeFlags.Null)
435
+ return { type: 'null' };
436
+ if (flags & ts.TypeFlags.Undefined)
437
+ return { type: 'null' };
438
+ if (flags & ts.TypeFlags.Void)
439
+ return { type: 'null' };
440
+ if (flags & ts.TypeFlags.Any)
441
+ return {};
442
+ if (flags & ts.TypeFlags.Unknown)
443
+ return { type: 'unknown' };
444
+ if (flags & ts.TypeFlags.Never)
445
+ return { type: 'unknown' };
446
+ // String/number/boolean literal
447
+ if (flags & ts.TypeFlags.StringLiteral) {
448
+ return { type: 'string', enum: [type.value] };
449
+ }
450
+ if (flags & ts.TypeFlags.NumberLiteral) {
451
+ return { type: 'number', enum: [type.value] };
452
+ }
453
+ if (flags & ts.TypeFlags.BooleanLiteral) {
454
+ // ts.TypeFlags doesn't expose the value directly; use the intrinsicName
455
+ const intrinsic = type.intrinsicName;
456
+ if (intrinsic === 'true')
457
+ return { type: 'boolean', enum: [true] };
458
+ if (intrinsic === 'false')
459
+ return { type: 'boolean', enum: [false] };
460
+ return { type: 'boolean' };
461
+ }
462
+ // Union type
463
+ if (type.isUnion()) {
464
+ return unionTypeToJsonSchema(type, checker, depth);
465
+ }
466
+ // Intersection type. Merge fixed properties from each arm and also
467
+ // preserve `additionalProperties` if any arm contributes an index
468
+ // signature (e.g. `{ username; password } & Record<string, string>`).
469
+ // This is how Cognito sign-up declares an open shape — without merging
470
+ // the index signature, native client codegen drops every key the
471
+ // type system can't statically enumerate (email, custom:*, etc.) and
472
+ // the wire format ends up missing them.
473
+ if (type.isIntersection()) {
474
+ const allProps = {};
475
+ const allRequired = [];
476
+ let additionalProps;
477
+ for (const member of type.types) {
478
+ const schema = tsTypeToJsonSchema(member, checker, depth + 1);
479
+ if (schema.properties) {
480
+ Object.assign(allProps, schema.properties);
481
+ if (schema.required)
482
+ allRequired.push(...schema.required);
483
+ }
484
+ if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
485
+ additionalProps = schema.additionalProperties;
486
+ }
487
+ }
488
+ if (Object.keys(allProps).length > 0) {
489
+ const schema = { type: 'object', properties: allProps };
490
+ if (allRequired.length > 0)
491
+ schema.required = allRequired;
492
+ if (additionalProps)
493
+ schema.additionalProperties = additionalProps;
494
+ return schema;
495
+ }
496
+ if (additionalProps) {
497
+ return { type: 'object', additionalProperties: additionalProps };
498
+ }
499
+ return { type: 'object' };
500
+ }
501
+ // Array type
502
+ if (checker.isArrayType(type)) {
503
+ const typeArgs = type.typeArguments;
504
+ if (typeArgs && typeArgs.length === 1) {
505
+ return { type: 'array', items: tsTypeToJsonSchema(typeArgs[0], checker, depth + 1) };
506
+ }
507
+ return { type: 'array' };
508
+ }
509
+ // Object type (interfaces, type literals, classes)
510
+ if (flags & ts.TypeFlags.Object) {
511
+ // Special-case built-in types that serialize to JSON primitives.
512
+ // Without this, Date emits as an object with getTime/toISOString/etc. properties.
513
+ const symbol = type.getSymbol();
514
+ const typeName = symbol?.getName();
515
+ if (typeName === 'Date')
516
+ return { type: 'string', format: 'date-time' };
517
+ if (typeName === 'RegExp')
518
+ return { type: 'string', format: 'regex' };
519
+ if (typeName === 'URL')
520
+ return { type: 'string', format: 'uri' };
521
+ if (typeName === 'Buffer' || typeName === 'ArrayBuffer' || typeName === 'Uint8Array')
522
+ return { type: 'string', format: 'binary' };
523
+ return objectTypeToJsonSchema(type, checker, depth);
524
+ }
525
+ return { type: 'unknown' };
526
+ }
527
+ function objectTypeToJsonSchema(type, checker, depth) {
528
+ const properties = {};
529
+ const required = [];
530
+ const props = checker.getPropertiesOfType(type);
531
+ // Index signatures (`Record<string, V>` or `{ [key: string]: V }`) carry
532
+ // the value type for any unnamed key. Capture once up front so we can
533
+ // emit `additionalProperties` on both the pure-map case (no fixed
534
+ // properties) and the mixed case (fixed properties + index sig).
535
+ const stringIndexType = checker.getIndexTypeOfType(type, ts.IndexKind.String);
536
+ const additionalProps = stringIndexType
537
+ ? tsTypeToJsonSchema(stringIndexType, checker, depth + 1)
538
+ : undefined;
539
+ if (props.length === 0 && additionalProps) {
540
+ return { type: 'object', additionalProperties: additionalProps };
541
+ }
542
+ if (props.length === 0)
543
+ return { type: 'object' };
544
+ for (const prop of props) {
545
+ // Skip internal/private properties
546
+ if (prop.name.startsWith('_'))
547
+ continue;
548
+ // Mapped-type properties (e.g. from `Partial<Record<K, V>>` and the
549
+ // per-variant intersections produced when unioning over an action
550
+ // payload map) are synthetic and have no `valueDeclaration`. Casting
551
+ // the `Symbol` to a `ts.Node` to satisfy `getTypeOfSymbolAtLocation`
552
+ // crashes inside the compiler's `isDeclaration` walk. `getTypeOfSymbol`
553
+ // resolves the property type without a location and works for both
554
+ // real and synthetic properties.
555
+ const propType = checker.getTypeOfSymbol(prop);
556
+ const propSchema = tsTypeToJsonSchema(propType, checker, depth + 1);
557
+ properties[prop.name] = propSchema;
558
+ const isOptional = (prop.flags & ts.SymbolFlags.Optional) !== 0;
559
+ if (!isOptional) {
560
+ required.push(prop.name);
561
+ }
562
+ }
563
+ const schema = { type: 'object', properties };
564
+ if (required.length > 0)
565
+ schema.required = required;
566
+ if (additionalProps)
567
+ schema.additionalProperties = additionalProps;
568
+ // Preserve the original type name for named types (interfaces, type aliases).
569
+ // This enables $ref extraction in generate-spec.ts and Phase 4 hydration detection.
570
+ const symbol = type.getSymbol() || type.aliasSymbol;
571
+ if (symbol) {
572
+ const name = symbol.getName();
573
+ // Skip anonymous/synthetic names
574
+ if (name && name !== '__type' && name !== '__object' && !name.startsWith('__')) {
575
+ schema.title = name;
576
+ }
577
+ }
578
+ return schema;
579
+ }
580
+ function unionTypeToJsonSchema(type, checker, depth) {
581
+ const members = type.types.map(t => tsTypeToJsonSchema(t, checker, depth + 1));
582
+ const nullish = members.filter(m => m.type === 'null');
583
+ const nonNullish = members.filter(m => m.type !== 'null');
584
+ // boolean is represented as true | false union in TS
585
+ if (nonNullish.length === 2 &&
586
+ nonNullish.every(m => m.type === 'boolean' && m.enum)) {
587
+ if (nullish.length > 0) {
588
+ return { oneOf: [{ type: 'boolean' }, { type: 'null' }] };
589
+ }
590
+ return { type: 'boolean' };
591
+ }
592
+ // T | null → oneOf [T, null]
593
+ if (nonNullish.length === 1 && nullish.length > 0) {
594
+ return { oneOf: [nonNullish[0], { type: 'null' }] };
595
+ }
596
+ // All same base type with enum values
597
+ const allEnums = nonNullish.every(m => m.enum);
598
+ if (allEnums && nonNullish.length > 0) {
599
+ const baseType = nonNullish[0].type;
600
+ if (nonNullish.every(m => m.type === baseType)) {
601
+ const enumValues = nonNullish.flatMap(m => m.enum || []);
602
+ const schema = { type: baseType, enum: enumValues };
603
+ if (nullish.length > 0) {
604
+ return { oneOf: [schema, { type: 'null' }] };
605
+ }
606
+ return schema;
607
+ }
608
+ }
609
+ // General union → oneOf
610
+ if (nonNullish.length > 1) {
611
+ const allMembers = nullish.length > 0 ? [...nonNullish, { type: 'null' }] : nonNullish;
612
+ return { oneOf: allMembers };
613
+ }
614
+ return members[0] || { type: 'unknown' };
615
+ }
616
+ // ── Helpers ─────────────────────────────────────────────────────────────────
617
+ /**
618
+ * Unwrap Promise<T> → T. If the type is not a Promise, returns it unchanged.
619
+ */
620
+ function unwrapPromise(type, checker) {
621
+ // Check if it's a Promise by looking at the symbol name
622
+ const symbol = type.getSymbol();
623
+ if (symbol && symbol.getName() === 'Promise') {
624
+ const typeArgs = type.typeArguments;
625
+ if (typeArgs && typeArgs.length === 1) {
626
+ return typeArgs[0];
627
+ }
628
+ }
629
+ return type;
630
+ }
631
+ // ── AST-only fallback (for explicit type annotations without checker) ───────
632
+ function typeNodeToJsonSchema(typeNode, sourceFile) {
633
+ if (ts.isToken(typeNode)) {
634
+ switch (typeNode.kind) {
635
+ case ts.SyntaxKind.StringKeyword: return { type: 'string' };
636
+ case ts.SyntaxKind.NumberKeyword: return { type: 'number' };
637
+ case ts.SyntaxKind.BooleanKeyword: return { type: 'boolean' };
638
+ case ts.SyntaxKind.NullKeyword: return { type: 'null' };
639
+ case ts.SyntaxKind.VoidKeyword: return { type: 'null' };
640
+ case ts.SyntaxKind.AnyKeyword: return {};
641
+ default: return { type: 'unknown' };
642
+ }
643
+ }
644
+ if (ts.isTypeLiteralNode(typeNode)) {
645
+ const properties = {};
646
+ const required = [];
647
+ for (const member of typeNode.members) {
648
+ if (ts.isPropertySignature(member) && member.name) {
649
+ const propName = member.name.getText(sourceFile);
650
+ properties[propName] = member.type ? typeNodeToJsonSchema(member.type, sourceFile) : { type: 'unknown' };
651
+ if (!member.questionToken)
652
+ required.push(propName);
653
+ }
654
+ }
655
+ const schema = { type: 'object', properties };
656
+ if (required.length > 0)
657
+ schema.required = required;
658
+ return schema;
659
+ }
660
+ if (ts.isArrayTypeNode(typeNode)) {
661
+ return { type: 'array', items: typeNodeToJsonSchema(typeNode.elementType, sourceFile) };
662
+ }
663
+ return { type: 'unknown' };
664
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=extract-ts-types.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-ts-types.test.d.ts","sourceRoot":"","sources":["../../src/scripts/extract-ts-types.test.ts"],"names":[],"mappings":""}