@elench/testkit 0.1.65 → 0.1.67

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 (324) hide show
  1. package/README.md +37 -62
  2. package/lib/app/browser-bridge.mjs +66 -0
  3. package/lib/app/configs.mjs +81 -0
  4. package/lib/app/configs.test.mjs +34 -0
  5. package/lib/app/doctor.mjs +139 -0
  6. package/lib/app/typecheck.mjs +203 -0
  7. package/lib/cli/command-helpers.mjs +2 -10
  8. package/lib/cli/commands/browser/serve.mjs +3 -62
  9. package/lib/cli/commands/doctor.mjs +39 -0
  10. package/lib/cli/commands/typecheck.mjs +28 -0
  11. package/lib/cli/db.mjs +3 -68
  12. package/lib/cli/entrypoint.mjs +2 -0
  13. package/lib/config/binaries.mjs +34 -0
  14. package/lib/config/database.mjs +9 -6
  15. package/lib/config/index.mjs +13 -31
  16. package/lib/config/runtime.mjs +35 -96
  17. package/lib/config/runtime.test.mjs +26 -0
  18. package/lib/config/validation.mjs +18 -62
  19. package/lib/coverage/backend-discovery.mjs +68 -85
  20. package/lib/coverage/backend-discovery.test.mjs +55 -46
  21. package/lib/coverage/graph-builder.mjs +5 -5
  22. package/lib/coverage/index.test.mjs +4 -2
  23. package/lib/coverage/next-ir-to-graph.mjs +0 -1
  24. package/lib/coverage/routing.mjs +2 -29
  25. package/lib/coverage/routing.test.mjs +0 -16
  26. package/lib/coverage/shared.mjs +22 -82
  27. package/lib/database/fingerprint.mjs +1 -1
  28. package/lib/discovery/file-metadata.mjs +122 -0
  29. package/lib/discovery/file-metadata.test.mjs +51 -0
  30. package/lib/discovery/index.mjs +10 -2
  31. package/lib/discovery/index.test.mjs +19 -19
  32. package/lib/known-failures/github-cache.mjs +159 -0
  33. package/lib/known-failures/github-transport.mjs +174 -0
  34. package/lib/known-failures/github.mjs +17 -325
  35. package/lib/runner/default-runtime-runner.mjs +4 -10
  36. package/lib/runner/execution-config.mjs +12 -83
  37. package/lib/runner/live-run.mjs +45 -0
  38. package/lib/runner/managed-processes.mjs +29 -0
  39. package/lib/runner/orchestrator.mjs +57 -188
  40. package/lib/runner/planning.mjs +10 -3
  41. package/lib/runner/planning.test.mjs +26 -0
  42. package/lib/runner/playwright-runner.mjs +4 -11
  43. package/lib/runner/run-finalization.mjs +132 -0
  44. package/lib/runner/run-guards.mjs +45 -0
  45. package/lib/runner/runtime-preparation.mjs +1 -1
  46. package/lib/runner/services.mjs +3 -4
  47. package/lib/runner/template-steps.mjs +8 -45
  48. package/lib/runner/template.mjs +7 -28
  49. package/lib/setup/index.d.ts +88 -21
  50. package/lib/setup/index.mjs +177 -50
  51. package/lib/setup/index.test.mjs +194 -64
  52. package/lib/shared/build-config.mjs +144 -0
  53. package/lib/shared/build-config.test.mjs +81 -0
  54. package/lib/shared/configured-steps.mjs +178 -0
  55. package/lib/shared/configured-steps.test.mjs +73 -0
  56. package/lib/shared/execution-schema.mjs +74 -0
  57. package/lib/shared/execution-schema.test.mjs +26 -0
  58. package/node_modules/@elench/next-analysis/dist/api-routes.d.ts +7 -0
  59. package/node_modules/@elench/next-analysis/dist/api-routes.d.ts.map +1 -0
  60. package/node_modules/@elench/next-analysis/dist/api-routes.js +66 -0
  61. package/node_modules/@elench/next-analysis/dist/api-routes.js.map +1 -0
  62. package/node_modules/@elench/next-analysis/dist/app-root.d.ts +2 -0
  63. package/node_modules/@elench/next-analysis/dist/app-root.d.ts.map +1 -0
  64. package/node_modules/@elench/next-analysis/dist/app-root.js +7 -0
  65. package/node_modules/@elench/next-analysis/dist/app-root.js.map +1 -0
  66. package/node_modules/@elench/next-analysis/dist/backend-links.d.ts +8 -0
  67. package/node_modules/@elench/next-analysis/dist/backend-links.d.ts.map +1 -0
  68. package/node_modules/@elench/next-analysis/dist/backend-links.js +30 -0
  69. package/node_modules/@elench/next-analysis/dist/backend-links.js.map +1 -0
  70. package/node_modules/@elench/next-analysis/dist/index.d.ts +11 -0
  71. package/node_modules/@elench/next-analysis/dist/index.d.ts.map +1 -0
  72. package/node_modules/@elench/next-analysis/dist/index.js +10 -0
  73. package/node_modules/@elench/next-analysis/dist/index.js.map +1 -0
  74. package/node_modules/@elench/next-analysis/dist/pages.d.ts +7 -0
  75. package/node_modules/@elench/next-analysis/dist/pages.d.ts.map +1 -0
  76. package/node_modules/@elench/next-analysis/dist/pages.js +47 -0
  77. package/node_modules/@elench/next-analysis/dist/pages.js.map +1 -0
  78. package/node_modules/@elench/next-analysis/dist/project.d.ts +3 -0
  79. package/node_modules/@elench/next-analysis/dist/project.d.ts.map +1 -0
  80. package/node_modules/@elench/next-analysis/dist/project.js +102 -0
  81. package/node_modules/@elench/next-analysis/dist/project.js.map +1 -0
  82. package/node_modules/@elench/next-analysis/dist/route-tree.d.ts +7 -0
  83. package/node_modules/@elench/next-analysis/dist/route-tree.d.ts.map +1 -0
  84. package/node_modules/@elench/next-analysis/dist/route-tree.js +575 -0
  85. package/node_modules/@elench/next-analysis/dist/route-tree.js.map +1 -0
  86. package/node_modules/@elench/next-analysis/dist/routes.d.ts +6 -0
  87. package/node_modules/@elench/next-analysis/dist/routes.d.ts.map +1 -0
  88. package/node_modules/@elench/next-analysis/dist/routes.js +41 -0
  89. package/node_modules/@elench/next-analysis/dist/routes.js.map +1 -0
  90. package/node_modules/@elench/next-analysis/dist/server-actions.d.ts +7 -0
  91. package/node_modules/@elench/next-analysis/dist/server-actions.d.ts.map +1 -0
  92. package/node_modules/@elench/next-analysis/dist/server-actions.js +37 -0
  93. package/node_modules/@elench/next-analysis/dist/server-actions.js.map +1 -0
  94. package/node_modules/@elench/next-analysis/dist/shared.d.ts +57 -0
  95. package/node_modules/@elench/next-analysis/dist/shared.d.ts.map +1 -0
  96. package/node_modules/@elench/next-analysis/dist/shared.js +229 -0
  97. package/node_modules/@elench/next-analysis/dist/shared.js.map +1 -0
  98. package/node_modules/@elench/next-analysis/dist/swc.d.ts +53 -0
  99. package/node_modules/@elench/next-analysis/dist/swc.d.ts.map +1 -0
  100. package/node_modules/@elench/next-analysis/dist/swc.js +387 -0
  101. package/node_modules/@elench/next-analysis/dist/swc.js.map +1 -0
  102. package/node_modules/@elench/next-analysis/dist/types.d.ts +125 -0
  103. package/node_modules/@elench/next-analysis/dist/types.d.ts.map +1 -0
  104. package/node_modules/@elench/next-analysis/dist/types.js +2 -0
  105. package/node_modules/@elench/next-analysis/dist/types.js.map +1 -0
  106. package/node_modules/@elench/next-analysis/package.json +15 -2
  107. package/node_modules/@elench/testkit-bridge/dist/index.d.ts +36 -0
  108. package/node_modules/@elench/testkit-bridge/dist/index.d.ts.map +1 -0
  109. package/node_modules/@elench/testkit-bridge/dist/index.js +538 -0
  110. package/node_modules/@elench/testkit-bridge/dist/index.js.map +1 -0
  111. package/node_modules/@elench/testkit-bridge/package.json +16 -5
  112. package/node_modules/@elench/testkit-protocol/dist/index.d.ts +190 -0
  113. package/node_modules/@elench/testkit-protocol/dist/index.d.ts.map +1 -0
  114. package/node_modules/@elench/testkit-protocol/dist/index.js +296 -0
  115. package/node_modules/@elench/testkit-protocol/dist/index.js.map +1 -0
  116. package/node_modules/@elench/testkit-protocol/package.json +14 -7
  117. package/node_modules/@elench/ts-analysis/dist/callables.d.ts +8 -0
  118. package/node_modules/@elench/ts-analysis/dist/callables.d.ts.map +1 -0
  119. package/node_modules/@elench/ts-analysis/dist/callables.js +126 -0
  120. package/node_modules/@elench/ts-analysis/dist/callables.js.map +1 -0
  121. package/node_modules/@elench/ts-analysis/dist/exports.d.ts +6 -0
  122. package/node_modules/@elench/ts-analysis/dist/exports.d.ts.map +1 -0
  123. package/node_modules/@elench/ts-analysis/dist/exports.js +70 -0
  124. package/node_modules/@elench/ts-analysis/dist/exports.js.map +1 -0
  125. package/node_modules/@elench/ts-analysis/dist/index.d.ts +10 -0
  126. package/node_modules/@elench/ts-analysis/dist/index.d.ts.map +1 -0
  127. package/node_modules/@elench/ts-analysis/{src/index.mjs → dist/index.js} +9 -14
  128. package/node_modules/@elench/ts-analysis/dist/index.js.map +1 -0
  129. package/node_modules/@elench/ts-analysis/dist/jsx.d.ts +9 -0
  130. package/node_modules/@elench/ts-analysis/dist/jsx.d.ts.map +1 -0
  131. package/node_modules/@elench/ts-analysis/dist/jsx.js +68 -0
  132. package/node_modules/@elench/ts-analysis/dist/jsx.js.map +1 -0
  133. package/node_modules/@elench/ts-analysis/dist/project.d.ts +5 -0
  134. package/node_modules/@elench/ts-analysis/dist/project.d.ts.map +1 -0
  135. package/node_modules/@elench/ts-analysis/dist/project.js +90 -0
  136. package/node_modules/@elench/ts-analysis/dist/project.js.map +1 -0
  137. package/node_modules/@elench/ts-analysis/dist/requests.d.ts +6 -0
  138. package/node_modules/@elench/ts-analysis/dist/requests.d.ts.map +1 -0
  139. package/node_modules/@elench/ts-analysis/dist/requests.js +140 -0
  140. package/node_modules/@elench/ts-analysis/dist/requests.js.map +1 -0
  141. package/node_modules/@elench/ts-analysis/dist/resolution.d.ts +4 -0
  142. package/node_modules/@elench/ts-analysis/dist/resolution.d.ts.map +1 -0
  143. package/node_modules/@elench/ts-analysis/dist/resolution.js +53 -0
  144. package/node_modules/@elench/ts-analysis/dist/resolution.js.map +1 -0
  145. package/node_modules/@elench/ts-analysis/dist/shared.d.ts +6 -0
  146. package/node_modules/@elench/ts-analysis/dist/shared.d.ts.map +1 -0
  147. package/node_modules/@elench/ts-analysis/dist/shared.js +31 -0
  148. package/node_modules/@elench/ts-analysis/dist/shared.js.map +1 -0
  149. package/node_modules/@elench/ts-analysis/dist/syntax.d.ts +7 -0
  150. package/node_modules/@elench/ts-analysis/dist/syntax.d.ts.map +1 -0
  151. package/node_modules/@elench/ts-analysis/dist/syntax.js +27 -0
  152. package/node_modules/@elench/ts-analysis/dist/syntax.js.map +1 -0
  153. package/node_modules/@elench/ts-analysis/dist/types.d.ts +58 -0
  154. package/node_modules/@elench/ts-analysis/dist/types.d.ts.map +1 -0
  155. package/node_modules/@elench/ts-analysis/dist/types.js +2 -0
  156. package/node_modules/@elench/ts-analysis/dist/types.js.map +1 -0
  157. package/node_modules/@elench/ts-analysis/package.json +18 -2
  158. package/node_modules/typescript/LICENSE.txt +55 -0
  159. package/node_modules/typescript/README.md +50 -0
  160. package/node_modules/typescript/SECURITY.md +41 -0
  161. package/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
  162. package/node_modules/typescript/bin/tsc +2 -0
  163. package/node_modules/typescript/bin/tsserver +2 -0
  164. package/node_modules/typescript/lib/_tsc.js +133818 -0
  165. package/node_modules/typescript/lib/_tsserver.js +659 -0
  166. package/node_modules/typescript/lib/_typingsInstaller.js +222 -0
  167. package/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +2122 -0
  168. package/node_modules/typescript/lib/de/diagnosticMessages.generated.json +2122 -0
  169. package/node_modules/typescript/lib/es/diagnosticMessages.generated.json +2122 -0
  170. package/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +2122 -0
  171. package/node_modules/typescript/lib/it/diagnosticMessages.generated.json +2122 -0
  172. package/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +2122 -0
  173. package/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +2122 -0
  174. package/node_modules/typescript/lib/lib.d.ts +22 -0
  175. package/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
  176. package/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
  177. package/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
  178. package/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
  179. package/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
  180. package/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
  181. package/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
  182. package/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
  183. package/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
  184. package/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
  185. package/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
  186. package/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
  187. package/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
  188. package/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
  189. package/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
  190. package/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
  191. package/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
  192. package/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
  193. package/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
  194. package/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
  195. package/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
  196. package/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
  197. package/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
  198. package/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
  199. package/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
  200. package/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
  201. package/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
  202. package/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
  203. package/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
  204. package/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
  205. package/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
  206. package/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
  207. package/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
  208. package/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
  209. package/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
  210. package/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
  211. package/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
  212. package/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
  213. package/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
  214. package/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
  215. package/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
  216. package/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
  217. package/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
  218. package/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
  219. package/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
  220. package/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
  221. package/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
  222. package/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
  223. package/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
  224. package/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
  225. package/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
  226. package/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
  227. package/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
  228. package/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
  229. package/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
  230. package/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
  231. package/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
  232. package/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
  233. package/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
  234. package/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
  235. package/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
  236. package/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
  237. package/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
  238. package/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
  239. package/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
  240. package/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
  241. package/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
  242. package/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
  243. package/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
  244. package/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
  245. package/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
  246. package/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
  247. package/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
  248. package/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
  249. package/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
  250. package/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
  251. package/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
  252. package/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
  253. package/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
  254. package/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
  255. package/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
  256. package/node_modules/typescript/lib/lib.es6.d.ts +23 -0
  257. package/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
  258. package/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
  259. package/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
  260. package/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
  261. package/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
  262. package/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
  263. package/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
  264. package/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
  265. package/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
  266. package/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
  267. package/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
  268. package/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
  269. package/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
  270. package/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
  271. package/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
  272. package/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
  273. package/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
  274. package/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +2122 -0
  275. package/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +2122 -0
  276. package/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +2122 -0
  277. package/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +2122 -0
  278. package/node_modules/typescript/lib/tsc.js +8 -0
  279. package/node_modules/typescript/lib/tsserver.js +8 -0
  280. package/node_modules/typescript/lib/tsserverlibrary.d.ts +17 -0
  281. package/node_modules/typescript/lib/tsserverlibrary.js +21 -0
  282. package/node_modules/typescript/lib/typesMap.json +497 -0
  283. package/node_modules/typescript/lib/typescript.d.ts +11437 -0
  284. package/node_modules/typescript/lib/typescript.js +200276 -0
  285. package/node_modules/typescript/lib/typingsInstaller.js +8 -0
  286. package/node_modules/typescript/lib/watchGuard.js +53 -0
  287. package/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +2122 -0
  288. package/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +2122 -0
  289. package/node_modules/typescript/package.json +120 -0
  290. package/package.json +12 -9
  291. package/lib/coverage/fs-walk.mjs +0 -64
  292. package/node_modules/@elench/next-analysis/src/api-routes.mjs +0 -81
  293. package/node_modules/@elench/next-analysis/src/api-routes.test.mjs +0 -22
  294. package/node_modules/@elench/next-analysis/src/app-root.mjs +0 -7
  295. package/node_modules/@elench/next-analysis/src/backend-links.mjs +0 -31
  296. package/node_modules/@elench/next-analysis/src/index.mjs +0 -21
  297. package/node_modules/@elench/next-analysis/src/pages.mjs +0 -68
  298. package/node_modules/@elench/next-analysis/src/project.mjs +0 -94
  299. package/node_modules/@elench/next-analysis/src/project.test.mjs +0 -35
  300. package/node_modules/@elench/next-analysis/src/route-tree.mjs +0 -621
  301. package/node_modules/@elench/next-analysis/src/routes.mjs +0 -41
  302. package/node_modules/@elench/next-analysis/src/routes.test.mjs +0 -25
  303. package/node_modules/@elench/next-analysis/src/server-actions.mjs +0 -53
  304. package/node_modules/@elench/next-analysis/src/server-actions.test.mjs +0 -37
  305. package/node_modules/@elench/next-analysis/src/shared.mjs +0 -209
  306. package/node_modules/@elench/next-analysis/src/swc.mjs +0 -388
  307. package/node_modules/@elench/testkit-bridge/src/index.mjs +0 -583
  308. package/node_modules/@elench/testkit-bridge/src/index.test.mjs +0 -409
  309. package/node_modules/@elench/testkit-protocol/src/index.d.ts +0 -231
  310. package/node_modules/@elench/testkit-protocol/src/index.mjs +0 -265
  311. package/node_modules/@elench/testkit-protocol/src/index.test.mjs +0 -242
  312. package/node_modules/@elench/ts-analysis/src/callables.mjs +0 -135
  313. package/node_modules/@elench/ts-analysis/src/callables.test.mjs +0 -55
  314. package/node_modules/@elench/ts-analysis/src/exports.mjs +0 -69
  315. package/node_modules/@elench/ts-analysis/src/exports.test.mjs +0 -50
  316. package/node_modules/@elench/ts-analysis/src/jsx.mjs +0 -69
  317. package/node_modules/@elench/ts-analysis/src/jsx.test.mjs +0 -43
  318. package/node_modules/@elench/ts-analysis/src/project.mjs +0 -100
  319. package/node_modules/@elench/ts-analysis/src/project.test.mjs +0 -54
  320. package/node_modules/@elench/ts-analysis/src/requests.mjs +0 -141
  321. package/node_modules/@elench/ts-analysis/src/requests.test.mjs +0 -35
  322. package/node_modules/@elench/ts-analysis/src/resolution.mjs +0 -53
  323. package/node_modules/@elench/ts-analysis/src/shared.mjs +0 -32
  324. package/node_modules/@elench/ts-analysis/src/syntax.mjs +0 -27
@@ -1,6 +1,6 @@
1
1
  import path from "path";
2
2
  import { Flags } from "@oclif/core";
3
- import { loadConfigs } from "../config/index.mjs";
3
+ import { loadManagedConfigs } from "../app/configs.mjs";
4
4
  import {
5
5
  parseFileTimeoutOption,
6
6
  parseShardOption,
@@ -73,15 +73,7 @@ export const runFlags = {
73
73
  };
74
74
 
75
75
  export async function resolveConfigsForCommand(flags) {
76
- const allConfigs = await loadConfigs({ dir: flags.dir });
77
- const configs = flags.service
78
- ? allConfigs.filter((config) => config.name === flags.service)
79
- : allConfigs;
80
- if (flags.service && configs.length === 0) {
81
- const available = allConfigs.map((config) => config.name).join(", ");
82
- throw new Error(`Service "${flags.service}" not found. Available: ${available}`);
83
- }
84
- return { allConfigs, configs };
76
+ return loadManagedConfigs({ dir: flags.dir, service: flags.service });
85
77
  }
86
78
 
87
79
  export async function executeRunCommand(command, flags, positionalType = null) {
@@ -1,8 +1,6 @@
1
1
  import { Command, Flags } from "@oclif/core";
2
2
  import { startBrowserBridgeServer } from "@elench/testkit-bridge";
3
- import { loadConfigContext, resolveProductDir } from "../../../config/index.mjs";
4
- import { discoverTests } from "../../../discovery/index.mjs";
5
- import { loadCurrentRunArtifact } from "../../viewer.mjs";
3
+ import { loadBrowserBridgeContext } from "../../../app/browser-bridge.mjs";
6
4
 
7
5
  export default class BrowserServeCommand extends Command {
8
6
  static summary = "Serve the local browser bridge for the current testkit product";
@@ -25,59 +23,10 @@ export default class BrowserServeCommand extends Command {
25
23
 
26
24
  async run() {
27
25
  const { flags } = await this.parse(BrowserServeCommand);
28
- const productDir = resolveProductDir(process.cwd(), flags.dir);
26
+ const { productDir, context } = await loadBrowserBridgeContext({ dir: flags.dir });
29
27
 
30
28
  const adapter = {
31
- loadProductContext: async () => {
32
- const [configContext, discovery] = await Promise.all([
33
- loadConfigContext({
34
- dir: productDir,
35
- discoveryOptions: { strict: false },
36
- }),
37
- discoverTests({
38
- dir: productDir,
39
- diagnostics: "report",
40
- }),
41
- ]);
42
-
43
- return {
44
- product: {
45
- name: discovery.product.name,
46
- directory: discovery.product.directory,
47
- },
48
- services: configContext.configs
49
- .map((config) => {
50
- const baseUrl = config.testkit.local?.baseUrl || null;
51
- const browserOrigins = config.testkit.browser?.origins || [];
52
- if (!baseUrl && browserOrigins.length === 0) return null;
53
- const serviceEntries = [];
54
- if (baseUrl && !baseUrl.includes("{port}")) {
55
- try {
56
- const parsed = new URL(baseUrl);
57
- serviceEntries.push({
58
- name: config.name,
59
- baseUrl,
60
- origin: parsed.origin,
61
- });
62
- } catch {
63
- // Ignore invalid local.baseUrl templates here; explicit browser origins still work.
64
- }
65
- }
66
- for (const origin of browserOrigins) {
67
- serviceEntries.push({
68
- name: config.name,
69
- baseUrl: origin,
70
- origin,
71
- });
72
- }
73
- return serviceEntries;
74
- })
75
- .flat()
76
- .filter(Boolean),
77
- discovery,
78
- runArtifact: loadRunArtifactIfPresent(productDir),
79
- };
80
- },
29
+ loadProductContext: async () => context,
81
30
  };
82
31
 
83
32
  const serverRef = await startBrowserBridgeServer(adapter, {
@@ -102,11 +51,3 @@ export default class BrowserServeCommand extends Command {
102
51
  return payload;
103
52
  }
104
53
  }
105
-
106
- function loadRunArtifactIfPresent(productDir) {
107
- try {
108
- return loadCurrentRunArtifact(productDir);
109
- } catch {
110
- return null;
111
- }
112
- }
@@ -0,0 +1,39 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import { runDoctor } from "../../app/doctor.mjs";
3
+
4
+ export default class DoctorCommand extends Command {
5
+ static summary = "Run built-in setup, discovery, and hygiene checks";
6
+
7
+ static enableJsonFlag = true;
8
+
9
+ static flags = {
10
+ dir: Flags.string({
11
+ description: "Product directory",
12
+ }),
13
+ typecheck: Flags.boolean({
14
+ description: "Include generated TypeScript checks",
15
+ default: true,
16
+ allowNo: true,
17
+ }),
18
+ };
19
+
20
+ async run() {
21
+ const { flags } = await this.parse(DoctorCommand);
22
+ const result = await runDoctor({ dir: flags.dir, typecheck: flags.typecheck });
23
+
24
+ if (!this.jsonEnabled()) {
25
+ this.log(`testkit doctor ${result.ok ? "passed" : "failed"} for ${result.productDir}`);
26
+ for (const check of result.checks) {
27
+ this.log(`${check.level.toUpperCase()} ${check.code} ${check.message}`);
28
+ }
29
+ }
30
+
31
+ if (!result.ok) {
32
+ const error = new Error("testkit doctor failed");
33
+ error.result = result;
34
+ throw error;
35
+ }
36
+
37
+ return result;
38
+ }
39
+ }
@@ -0,0 +1,28 @@
1
+ import { Command, Flags } from "@oclif/core";
2
+ import { runTestkitTypecheck } from "../../app/typecheck.mjs";
3
+
4
+ export default class TypecheckCommand extends Command {
5
+ static summary = "Typecheck testkit setup, helpers, and suites";
6
+
7
+ static enableJsonFlag = true;
8
+
9
+ static flags = {
10
+ dir: Flags.string({
11
+ description: "Product directory",
12
+ }),
13
+ };
14
+
15
+ async run() {
16
+ const { flags } = await this.parse(TypecheckCommand);
17
+ const result = await runTestkitTypecheck({ dir: flags.dir });
18
+
19
+ if (!this.jsonEnabled()) {
20
+ this.log(`Typechecked ${result.results.length} testkit program(s) in ${result.productDir}`);
21
+ for (const entry of result.results) {
22
+ this.log(`PASS ${entry.label} ${entry.tsconfigPath}`);
23
+ }
24
+ }
25
+
26
+ return result;
27
+ }
28
+ }
package/lib/cli/db.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import fs from "fs";
2
2
  import os from "os";
3
3
  import path from "path";
4
- import { loadConfigs, resolveProductDir } from "../config/index.mjs";
4
+ import { loadManagedConfigs, resolveTargetConfig, collectRequiredConfigs, topologicallySortConfigs } from "../app/configs.mjs";
5
+ import { resolveProductDir } from "../config/index.mjs";
5
6
  import { captureDatabaseTemplateSnapshot, prepareDatabaseRuntime } from "../database/index.mjs";
6
7
  import { createRunReporter } from "./presentation/run-reporter.mjs";
7
8
  import { createRunLogRegistry } from "../runner/logs.mjs";
@@ -10,7 +11,7 @@ import { resolveRuntimeInstanceConfigs } from "../runner/template.mjs";
10
11
 
11
12
  export async function runDatabaseSnapshotCaptureCommand(options = {}) {
12
13
  const productDir = resolveProductDir(process.cwd(), options.dir);
13
- const configs = await loadConfigs({ dir: productDir });
14
+ const { configs } = await loadManagedConfigs({ dir: productDir });
14
15
  const target = resolveTargetConfig(configs, options.service);
15
16
  const outputPath = normalizeOptionalString(options.output);
16
17
  if (!outputPath) {
@@ -57,74 +58,8 @@ export async function runDatabaseSnapshotCaptureCommand(options = {}) {
57
58
  }
58
59
  }
59
60
 
60
- function resolveTargetConfig(configs, serviceName) {
61
- if (serviceName) {
62
- const match = configs.find((config) => config.name === serviceName);
63
- if (!match) {
64
- const available = configs.map((config) => config.name).join(", ");
65
- throw new Error(`Service "${serviceName}" not found. Available: ${available}`);
66
- }
67
- return match;
68
- }
69
-
70
- if (configs.length === 1) return configs[0];
71
- const withLocalDb = configs.filter((config) => config.testkit.database?.provider === "local");
72
- if (withLocalDb.length === 1) return withLocalDb[0];
73
-
74
- const available = configs.map((config) => config.name).join(", ");
75
- throw new Error(`Multiple services available. Pass --service. Available: ${available}`);
76
- }
77
-
78
61
  function normalizeOptionalString(value) {
79
62
  if (typeof value !== "string") return null;
80
63
  const normalized = value.trim();
81
64
  return normalized.length > 0 ? normalized : null;
82
65
  }
83
-
84
- function collectRequiredConfigs(configs, targetName) {
85
- const byName = new Map(configs.map((config) => [config.name, config]));
86
- const required = new Set();
87
-
88
- const visit = (name) => {
89
- if (required.has(name)) return;
90
- const config = byName.get(name);
91
- if (!config) {
92
- throw new Error(`Missing config for dependency "${name}"`);
93
- }
94
- required.add(name);
95
- for (const depName of config.testkit.dependsOn || []) {
96
- visit(depName);
97
- }
98
- };
99
-
100
- visit(targetName);
101
- return configs.filter((config) => required.has(config.name));
102
- }
103
-
104
- function topologicallySortConfigs(configs) {
105
- const byName = new Map(configs.map((config) => [config.name, config]));
106
- const visited = new Set();
107
- const visiting = new Set();
108
- const ordered = [];
109
-
110
- const visit = (config) => {
111
- if (visited.has(config.name)) return;
112
- if (visiting.has(config.name)) {
113
- throw new Error(`Dependency cycle while resolving snapshot capture for "${config.name}"`);
114
- }
115
- visiting.add(config.name);
116
- for (const depName of config.testkit.dependsOn || []) {
117
- const dependency = byName.get(depName);
118
- if (dependency) visit(dependency);
119
- }
120
- visiting.delete(config.name);
121
- visited.add(config.name);
122
- ordered.push(config);
123
- };
124
-
125
- for (const config of configs) {
126
- visit(config);
127
- }
128
-
129
- return ordered;
130
- }
@@ -9,6 +9,8 @@ export function normalizeCliArgs(argv) {
9
9
  "artifacts",
10
10
  "watch",
11
11
  "discover",
12
+ "typecheck",
13
+ "doctor",
12
14
  "browser",
13
15
  "known-failures",
14
16
  "db",
@@ -0,0 +1,34 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+
5
+ const TESTKIT_K6_BIN = "TESTKIT_K6_BIN";
6
+
7
+ export function resolveK6Binary() {
8
+ const override = process.env[TESTKIT_K6_BIN]?.trim();
9
+ if (override) {
10
+ const isPathLike =
11
+ path.isAbsolute(override) ||
12
+ override.includes(path.sep) ||
13
+ override.includes(path.posix.sep) ||
14
+ override.includes(path.win32.sep);
15
+ const overridePath = isPathLike ? path.resolve(process.cwd(), override) : override;
16
+
17
+ if (isPathLike && !fs.existsSync(overridePath)) {
18
+ throw new Error(`${TESTKIT_K6_BIN} points to a missing file: ${overridePath}`);
19
+ }
20
+
21
+ return overridePath;
22
+ }
23
+
24
+ const thisFile = fileURLToPath(import.meta.url);
25
+ const abs = path.resolve(path.dirname(thisFile), "..", "..", "vendor", "k6");
26
+ if (!fs.existsSync(abs)) {
27
+ throw new Error(`Bundled k6 binary not found: ${abs}`);
28
+ }
29
+ return abs;
30
+ }
31
+
32
+ export function resolveDalBinary() {
33
+ return resolveK6Binary();
34
+ }
@@ -1,5 +1,8 @@
1
- import { normalizeDatabaseBinding } from "../runner/execution-config.mjs";
2
- import { normalizeOptionalString, normalizeTemplateInputs, normalizeTemplateLifecycleSteps } from "./runtime.mjs";
1
+ import { normalizeDatabaseBinding } from "../shared/execution-schema.mjs";
2
+ import {
3
+ normalizeConfiguredInputs,
4
+ normalizeConfiguredSteps,
5
+ } from "../shared/configured-steps.mjs";
3
6
 
4
7
  const DEFAULT_LOCAL_IMAGE = "pgvector/pgvector:pg16";
5
8
  const DEFAULT_LOCAL_USER = "testkit";
@@ -45,9 +48,9 @@ export function normalizeDatabaseTemplateConfig(value, serviceName) {
45
48
  }
46
49
 
47
50
  return {
48
- inputs: normalizeTemplateInputs(value.inputs, `Service "${serviceName}" database.template`),
49
- migrate: normalizeTemplateLifecycleSteps(value.migrate, `Service "${serviceName}" database.template.migrate`),
50
- seed: normalizeTemplateLifecycleSteps(value.seed, `Service "${serviceName}" database.template.seed`),
51
- verify: normalizeTemplateLifecycleSteps(value.verify, `Service "${serviceName}" database.template.verify`),
51
+ inputs: normalizeConfiguredInputs(value.inputs, `Service "${serviceName}" database.template`),
52
+ migrate: normalizeConfiguredSteps(value.migrate, `Service "${serviceName}" database.template.migrate`),
53
+ seed: normalizeConfiguredSteps(value.seed, `Service "${serviceName}" database.template.seed`),
54
+ verify: normalizeConfiguredSteps(value.verify, `Service "${serviceName}" database.template.verify`),
52
55
  };
53
56
  }
@@ -1,13 +1,14 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { fileURLToPath } from "url";
4
3
  import { discoverProject } from "./discovery.mjs";
5
4
  import { loadTestkitSetup } from "./setup-loader.mjs";
6
5
  import { normalizeToolchainRegistry } from "../toolchains/index.mjs";
6
+ import { loadTestFileMetadataMap } from "../discovery/file-metadata.mjs";
7
7
  import { mergeDiscoveryConfigs } from "../discovery/path-policy.mjs";
8
8
  import { normalizeDatabaseConfig } from "./database.mjs";
9
9
  import { normalizeRepoDiscoveryConfig, normalizeServiceDiscoveryConfig } from "./discovery-config.mjs";
10
10
  import { inferEnvFiles, loadServiceEnv, parseDotenv } from "./env.mjs";
11
+ import { resolveDalBinary, resolveK6Binary } from "./binaries.mjs";
11
12
  import { ensureExistingPath, resolveProductDir, resolveServiceCwd } from "./paths.mjs";
12
13
  import {
13
14
  detectNextApp,
@@ -22,8 +23,6 @@ import { normalizeServiceRequirements, normalizeSkipConfig } from "./skip-config
22
23
  import { normalizeTelemetryConfig } from "./telemetry.mjs";
23
24
  import { validateConfigCoverage, validateServiceConfig } from "./validation.mjs";
24
25
 
25
- const TESTKIT_K6_BIN = "TESTKIT_K6_BIN";
26
-
27
26
  export { parseDotenv, resolveProductDir, resolveServiceCwd };
28
27
 
29
28
  export async function loadConfigContext(opts = {}) {
@@ -39,6 +38,7 @@ export async function loadConfigContext(opts = {}) {
39
38
  ...(opts.discoveryOptions || {}),
40
39
  discovery: discoveryConfig,
41
40
  });
41
+ const fileMetadataByPath = loadTestFileMetadataMap(productDir, discovery.suitesByService);
42
42
  const serviceNames = new Set([
43
43
  ...Object.keys(explicitServices),
44
44
  ...Object.keys(discovery.suitesByService),
@@ -59,6 +59,7 @@ export async function loadConfigContext(opts = {}) {
59
59
  explicitService: explicitServices[name] || {},
60
60
  discoveredService: discovery.services[name] || null,
61
61
  suites: discovery.suitesByService[name] || {},
62
+ fileMetadataByPath,
62
63
  })
63
64
  );
64
65
 
@@ -92,34 +93,7 @@ export async function loadConfigs(opts = {}) {
92
93
  return filtered;
93
94
  }
94
95
 
95
- export function resolveK6Binary() {
96
- const override = process.env[TESTKIT_K6_BIN]?.trim();
97
- if (override) {
98
- const isPathLike =
99
- path.isAbsolute(override) ||
100
- override.includes(path.sep) ||
101
- override.includes(path.posix.sep) ||
102
- override.includes(path.win32.sep);
103
- const overridePath = isPathLike ? path.resolve(process.cwd(), override) : override;
104
-
105
- if (isPathLike && !fs.existsSync(overridePath)) {
106
- throw new Error(`${TESTKIT_K6_BIN} points to a missing file: ${overridePath}`);
107
- }
108
-
109
- return overridePath;
110
- }
111
-
112
- const thisFile = fileURLToPath(import.meta.url);
113
- const abs = path.resolve(path.dirname(thisFile), "..", "..", "vendor", "k6");
114
- if (!fs.existsSync(abs)) {
115
- throw new Error(`Bundled k6 binary not found: ${abs}`);
116
- }
117
- return abs;
118
- }
119
-
120
- export function resolveDalBinary() {
121
- return resolveK6Binary();
122
- }
96
+ export { resolveDalBinary, resolveK6Binary } from "./binaries.mjs";
123
97
 
124
98
  function normalizeServiceConfig({
125
99
  name,
@@ -133,6 +107,7 @@ function normalizeServiceConfig({
133
107
  explicitService,
134
108
  discoveredService,
135
109
  suites,
110
+ fileMetadataByPath,
136
111
  }) {
137
112
  const local = normalizeLocalConfig(name, explicitService, discoveredService, productDir);
138
113
  const envFiles = inferEnvFiles(productDir, explicitService, local);
@@ -154,6 +129,12 @@ function normalizeServiceConfig({
154
129
  const runtime = normalizeRuntimeConfig(explicitService.runtime, name, toolchains);
155
130
  const skip = normalizeSkipConfig(explicitService.skip, { name, suites });
156
131
  const requirements = normalizeServiceRequirements(explicitService.requirements, { name, suites });
132
+ const serviceFilePaths = new Set(
133
+ Object.values(suites || {}).flatMap((suiteList) => suiteList.flatMap((suite) => suite.files || []))
134
+ );
135
+ const serviceFileMetadata = new Map(
136
+ [...fileMetadataByPath.entries()].filter(([filePath]) => serviceFilePaths.has(filePath))
137
+ );
157
138
 
158
139
  validateServiceConfig({
159
140
  name,
@@ -186,6 +167,7 @@ function normalizeServiceConfig({
186
167
  skip,
187
168
  runtime,
188
169
  browser,
170
+ fileMetadataByPath: serviceFileMetadata,
189
171
  local,
190
172
  },
191
173
  };
@@ -1,16 +1,24 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { DEFAULT_FILE_TIMEOUT_SECONDS, normalizeExecutionConfig, normalizeRuntimeMaxConcurrentTasks, normalizeRuntimeInstances } from "../runner/execution-config.mjs";
3
+ import {
4
+ DEFAULT_FILE_TIMEOUT_SECONDS,
5
+ normalizeExecutionConfig,
6
+ normalizeRuntimeMaxConcurrentTasks,
7
+ normalizeRuntimeInstances,
8
+ } from "../shared/execution-schema.mjs";
9
+ import {
10
+ normalizeConfiguredInputs,
11
+ normalizeConfiguredStep,
12
+ normalizeConfiguredStepInputs,
13
+ normalizeConfiguredSteps,
14
+ normalizeOptionalString,
15
+ parseModuleSpecifier,
16
+ } from "../shared/configured-steps.mjs";
17
+ import { buildConfigToPrepare, normalizeBuildConfig } from "../shared/build-config.mjs";
4
18
  import { normalizeKnownFailureIssueValidationConfig } from "../known-failures/github.mjs";
5
19
  import { normalizeRuntimeToolchain } from "../toolchains/index.mjs";
6
20
  import { resolveServiceCwd } from "./paths.mjs";
7
21
 
8
- export function normalizeOptionalString(value) {
9
- if (typeof value !== "string") return null;
10
- const normalized = value.trim();
11
- return normalized.length > 0 ? normalized : null;
12
- }
13
-
14
22
  export function normalizeReportingConfig(value) {
15
23
  if (!value) return null;
16
24
 
@@ -70,6 +78,7 @@ export function inferLocalRuntime(productDir, cwd) {
70
78
  export function normalizeRuntimeConfig(value, serviceName, toolchains) {
71
79
  if (!value) {
72
80
  return {
81
+ build: null,
73
82
  instances: 1,
74
83
  maxConcurrentTasks: Number.POSITIVE_INFINITY,
75
84
  prepare: {
@@ -80,13 +89,21 @@ export function normalizeRuntimeConfig(value, serviceName, toolchains) {
80
89
  };
81
90
  }
82
91
 
92
+ const build = normalizeBuildConfig(value.build, `Service "${serviceName}" runtime.build`);
93
+ const prepare = normalizeRuntimePrepareConfig(value.prepare, serviceName);
94
+ const buildPrepare = buildConfigToPrepare(build);
95
+
83
96
  return {
97
+ build,
84
98
  instances: normalizeRuntimeInstances(value.instances ?? 1, `Service "${serviceName}" runtime.instances`),
85
99
  maxConcurrentTasks: normalizeRuntimeMaxConcurrentTasks(
86
100
  value.maxConcurrentTasks,
87
101
  `Service "${serviceName}" runtime.maxConcurrentTasks`
88
102
  ),
89
- prepare: normalizeRuntimePrepareConfig(value.prepare, serviceName),
103
+ prepare: {
104
+ inputs: [...new Set([...(buildPrepare.inputs || []), ...(prepare.inputs || [])])],
105
+ steps: [...(buildPrepare.steps || []), ...(prepare.steps || [])],
106
+ },
90
107
  toolchain: normalizeRuntimeToolchain(
91
108
  value.toolchain,
92
109
  `Service "${serviceName}" runtime.toolchain`,
@@ -107,90 +124,11 @@ export function normalizeRuntimePrepareConfig(value, serviceName) {
107
124
  }
108
125
 
109
126
  return {
110
- inputs: normalizeTemplateInputs(value.inputs, `Service "${serviceName}" runtime.prepare`),
111
- steps: normalizeTemplateLifecycleSteps(value.steps, `Service "${serviceName}" runtime.prepare.steps`),
127
+ inputs: normalizeConfiguredInputs(value.inputs, `Service "${serviceName}" runtime.prepare`),
128
+ steps: normalizeConfiguredSteps(value.steps, `Service "${serviceName}" runtime.prepare.steps`),
112
129
  };
113
130
  }
114
131
 
115
- export function normalizeTemplateInputs(value, label) {
116
- if (value == null) return [];
117
- if (!Array.isArray(value)) {
118
- throw new Error(`${label}.inputs must be an array`);
119
- }
120
-
121
- return value.map((entry, index) => {
122
- const normalized = normalizeOptionalString(entry);
123
- if (!normalized) {
124
- throw new Error(`${label}.inputs[${index}] must be a non-empty string`);
125
- }
126
- return normalized;
127
- });
128
- }
129
-
130
- export function normalizeTemplateLifecycleSteps(value, label) {
131
- if (value == null) return [];
132
- if (!Array.isArray(value)) {
133
- throw new Error(`${label} must be an array`);
134
- }
135
-
136
- return value.map((step, index) => normalizeTemplateLifecycleStep(step, `${label}[${index}]`));
137
- }
138
-
139
- export function normalizeTemplateLifecycleStep(step, label) {
140
- if (!step || typeof step !== "object") {
141
- throw new Error(`${label} must be an object`);
142
- }
143
-
144
- const kind = normalizeOptionalString(step.kind);
145
- if (kind === "command") {
146
- const cmd = normalizeOptionalString(step.cmd);
147
- if (!cmd) throw new Error(`${label}.cmd must be a non-empty string`);
148
- return {
149
- kind,
150
- cmd,
151
- cwd: normalizeOptionalString(step.cwd),
152
- inputs: normalizeTemplateStepInputs(step.inputs, label),
153
- };
154
- }
155
- if (kind === "sql-file") {
156
- const filePath = normalizeOptionalString(step.path);
157
- if (!filePath) throw new Error(`${label}.path must be a non-empty string`);
158
- return {
159
- kind,
160
- path: filePath,
161
- cwd: normalizeOptionalString(step.cwd),
162
- inputs: normalizeTemplateStepInputs(step.inputs, label),
163
- };
164
- }
165
- if (kind === "module") {
166
- const specifier = normalizeOptionalString(step.specifier);
167
- if (!specifier) throw new Error(`${label}.specifier must be a non-empty string`);
168
- return {
169
- kind,
170
- specifier,
171
- cwd: normalizeOptionalString(step.cwd),
172
- inputs: normalizeTemplateStepInputs(step.inputs, label),
173
- };
174
- }
175
-
176
- throw new Error(`${label}.kind must be one of: command, sql-file, module`);
177
- }
178
-
179
- export function normalizeTemplateStepInputs(value, label) {
180
- if (value == null) return [];
181
- if (!Array.isArray(value)) {
182
- throw new Error(`${label}.inputs must be an array`);
183
- }
184
-
185
- return value.map((entry, index) => {
186
- const normalized = normalizeOptionalString(entry);
187
- if (!normalized) {
188
- throw new Error(`${label}.inputs[${index}] must be a non-empty string`);
189
- }
190
- return normalized;
191
- });
192
- }
193
-
194
132
  export function normalizeBrowserServiceConfig(value, serviceName) {
195
133
  if (!value) return undefined;
196
134
  if (typeof value !== "object" || Array.isArray(value)) {
@@ -232,10 +170,11 @@ export function detectNextApp(cwd) {
232
170
  );
233
171
  }
234
172
 
235
- export function parseModuleSpecifier(specifier) {
236
- const [modulePath, exportName] = String(specifier).split("#", 2);
237
- return {
238
- modulePath,
239
- exportName: exportName || "default",
240
- };
241
- }
173
+ export {
174
+ normalizeConfiguredInputs as normalizeTemplateInputs,
175
+ normalizeConfiguredStep as normalizeTemplateLifecycleStep,
176
+ normalizeConfiguredStepInputs as normalizeTemplateStepInputs,
177
+ normalizeConfiguredSteps as normalizeTemplateLifecycleSteps,
178
+ normalizeOptionalString,
179
+ parseModuleSpecifier,
180
+ } from "../shared/configured-steps.mjs";
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import {
3
3
  normalizeBrowserServiceConfig,
4
+ normalizeRuntimeConfig,
4
5
  normalizeRuntimePrepareConfig,
5
6
  normalizeTemplateLifecycleStep,
6
7
  normalizeTemplateStepInputs,
@@ -45,6 +46,31 @@ describe("config runtime helpers", () => {
45
46
  });
46
47
  });
47
48
 
49
+ it("folds declarative runtime.build into runtime.prepare", () => {
50
+ expect(
51
+ normalizeRuntimeConfig(
52
+ {
53
+ build: {
54
+ kind: "tsc",
55
+ entry: "src/server.ts",
56
+ },
57
+ },
58
+ "api",
59
+ {}
60
+ )
61
+ ).toMatchObject({
62
+ build: {
63
+ kind: "tsc",
64
+ entry: "src/server.ts",
65
+ tsconfig: "tsconfig.json",
66
+ outDir: "dist",
67
+ },
68
+ prepare: {
69
+ inputs: ["tsconfig.json", "package.json", "src"],
70
+ },
71
+ });
72
+ });
73
+
48
74
  it("rejects malformed lifecycle steps and empty step inputs", () => {
49
75
  expect(() => normalizeTemplateLifecycleStep({ kind: "module" }, "runtime.prepare.steps[0]")).toThrow(
50
76
  /specifier must be a non-empty string/