@gfdelarue/testkit 0.4.5 → 0.6.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 (787) hide show
  1. package/README.md +724 -495
  2. package/bin/testkit-windows-owner-arm64.exe +0 -0
  3. package/bin/testkit-windows-owner-x64.exe +0 -0
  4. package/dist/app/bugs/ci-report.js +2 -2
  5. package/dist/app/bugs/ci-summary.js +3 -3
  6. package/dist/app/bugs/draft.js +3 -3
  7. package/dist/app/bugs/file.js +1 -1
  8. package/dist/app/bugs/gate.js +1 -1
  9. package/dist/app/bugs/guide.js +3 -3
  10. package/dist/app/bugs/issue.js +4 -4
  11. package/dist/app/bugs/known-failures.js +1 -1
  12. package/dist/app/bugs/record.js +1 -1
  13. package/dist/app/bugs/run-reading.js +1 -1
  14. package/dist/app/bugs/supplied-reproduce.js +1 -0
  15. package/dist/app/campaigns/campaign.js +1 -1
  16. package/dist/app/campaigns/index.js +2 -2
  17. package/dist/app/cleanup/index.js +1 -1
  18. package/dist/app/db-schema/prepare.js +1 -1
  19. package/dist/app/destroy/index.js +1 -1
  20. package/dist/app/discover/index.js +2 -2
  21. package/dist/app/doctor/index.js +1 -1
  22. package/dist/app/environments/config-driven.js +1 -1
  23. package/dist/app/environments/environment-file.js +1 -0
  24. package/dist/app/environments/file-setup.js +1 -0
  25. package/dist/app/environments/routing.js +1 -1
  26. package/dist/app/environments/static-values.js +1 -0
  27. package/dist/app/environments/supplied-input.js +1 -0
  28. package/dist/app/environments/supplied.js +1 -1
  29. package/dist/app/environments/task-databases.js +2 -0
  30. package/dist/app/inspect/artifacts.js +1 -1
  31. package/dist/app/inspect/index.js +1 -1
  32. package/dist/app/lint/index.js +1 -1
  33. package/dist/app/lint/native.js +1 -1
  34. package/dist/app/lint/options.js +1 -1
  35. package/dist/app/lint/rules/engine-imports.js +1 -1
  36. package/dist/app/lint/rules/syntax.js +1 -1
  37. package/dist/app/lint/rules/unit.js +1 -1
  38. package/dist/app/reports/prepare.js +1 -1
  39. package/dist/app/run/caller-redaction.js +1 -0
  40. package/dist/app/run/engine-execution-failures.js +1 -1
  41. package/dist/app/run/engine-execution-reporting.js +1 -1
  42. package/dist/app/run/engine-execution.js +1 -1
  43. package/dist/app/run/engine-orchestration.js +1 -1
  44. package/dist/app/run/environment.js +1 -1
  45. package/dist/app/run/failure-details.js +1 -1
  46. package/dist/app/run/live-run.js +1 -1
  47. package/dist/app/run/orchestrator.js +1 -1
  48. package/dist/app/run/planning.js +1 -1
  49. package/dist/app/run/request.js +1 -1
  50. package/dist/app/run/results.js +1 -1
  51. package/dist/app/run/run-events.js +1 -1
  52. package/dist/app/run/run-finalization.js +1 -1
  53. package/dist/app/run/scheduler/estimates.js +1 -1
  54. package/dist/app/run/scheduler/identity.js +1 -1
  55. package/dist/app/run/scheduler/index.js +1 -1
  56. package/dist/app/run/setup/runtime-node-setup-protocol.js +1 -1
  57. package/dist/app/run/setup/runtime-node-setup-worker.js +1 -1
  58. package/dist/app/run/setup/runtime-node-setup.js +2 -2
  59. package/dist/app/run/task-batches.js +1 -1
  60. package/dist/app/run/worker-loop.js +1 -1
  61. package/dist/app/status/model.js +1 -1
  62. package/dist/app/status/runs.js +1 -1
  63. package/dist/app/typecheck/index.js +4 -4
  64. package/dist/cli/command-catalog.js +1 -1
  65. package/dist/cli/command-flags.js +1 -1
  66. package/dist/cli/commands/artifacts.js +2 -2
  67. package/dist/cli/commands/bug/file.js +2 -2
  68. package/dist/cli/commands/bug/record.js +2 -2
  69. package/dist/cli/commands/discover.js +1 -1
  70. package/dist/cli/commands/guard/unsafe-entrypoint.js +1 -1
  71. package/dist/cli/commands/run.js +2 -2
  72. package/dist/cli/commands/typecheck.js +1 -1
  73. package/dist/cli/commands/workspace.js +1 -1
  74. package/dist/cli/framework/errors.js +1 -1
  75. package/dist/cli/framework/execute.js +7 -6
  76. package/dist/cli/framework/parser.js +1 -1
  77. package/dist/cli/operations/run/operation.js +2 -2
  78. package/dist/cli/renderers/bug/text.js +1 -1
  79. package/dist/cli/renderers/discover/report.js +1 -1
  80. package/dist/cli/renderers/run/events.js +2 -2
  81. package/dist/cli/renderers/run/formatting.js +1 -1
  82. package/dist/cli/renderers/run/status.js +1 -1
  83. package/dist/cli/renderers/run/text-reporter.js +24 -22
  84. package/dist/cli/terminal/colors.js +1 -1
  85. package/dist/cli/terminal/layout.js +2 -2
  86. package/dist/config/authoring/database-fixture-discovery.js +1 -0
  87. package/dist/config/authoring/http-methods.js +1 -1
  88. package/dist/config/authoring/index.js +1 -1
  89. package/dist/config/loader/config-loader.js +1 -1
  90. package/dist/config/loader/decode-discovery.js +1 -1
  91. package/dist/config/loader/decode-execution.js +1 -1
  92. package/dist/config/loader/dependencies.js +1 -1
  93. package/dist/config/loader/discover-tests.js +1 -1
  94. package/dist/config/loader/discovery-summary.js +1 -1
  95. package/dist/config/loader/discovery.js +2 -2
  96. package/dist/config/loader/env.js +1 -1
  97. package/dist/config/loader/file-metadata.js +1 -1
  98. package/dist/config/loader/groups.js +2 -1
  99. package/dist/config/loader/index.js +1 -1
  100. package/dist/config/loader/load.js +1 -1
  101. package/dist/config/loader/managed-configs.js +1 -1
  102. package/dist/config/loader/owned-discovery.js +1 -0
  103. package/dist/config/loader/path-policy.js +1 -1
  104. package/dist/config/loader/runtime-isolation.js +1 -1
  105. package/dist/config/loader/runtime.js +1 -1
  106. package/dist/config/loader/skip-config.js +1 -1
  107. package/dist/config/loader/task-policy.js +1 -0
  108. package/dist/config/loader/test-selection.js +1 -1
  109. package/dist/config/loader/validation.js +1 -1
  110. package/dist/database/admin.js +2 -2
  111. package/dist/database/bindings.js +1 -0
  112. package/dist/database/cleanup.js +1 -1
  113. package/dist/database/configured-steps.js +1 -1
  114. package/dist/database/docker-metadata.js +3 -3
  115. package/dist/database/docker.js +3 -3
  116. package/dist/database/index.js +1 -1
  117. package/dist/database/local-postgres.js +1 -1
  118. package/dist/database/naming.js +1 -1
  119. package/dist/database/postgres/connection-check.js +1 -0
  120. package/dist/database/postgres/protocol.js +2 -0
  121. package/dist/database/schema-operations.js +1 -1
  122. package/dist/database/schema-source.js +3 -3
  123. package/dist/database/source-schema-env.js +1 -0
  124. package/dist/database/state-files.js +1 -1
  125. package/dist/database/state.js +1 -1
  126. package/dist/database/steps.js +3 -3
  127. package/dist/domain/file-timeout.js +1 -1
  128. package/dist/domain/identifiers.js +1 -1
  129. package/dist/domain/retired-test-types.js +1 -0
  130. package/dist/domain/runtime-isolation-contract.js +1 -1
  131. package/dist/domain/suite-selection.js +1 -1
  132. package/dist/domain/test-types.js +1 -1
  133. package/dist/engines/adapters/evidence-files.js +1 -1
  134. package/dist/engines/adapters/execution.js +1 -1
  135. package/dist/engines/adapters/json-bounds.js +2 -0
  136. package/dist/engines/adapters/native-report.js +1 -1
  137. package/dist/engines/api/execution.js +1 -1
  138. package/dist/engines/api/index.js +1 -1
  139. package/dist/engines/api/runtime-artifact.js +1 -1
  140. package/dist/engines/catalog.js +1 -1
  141. package/dist/engines/contracts/environment-values.js +1 -0
  142. package/dist/engines/definitions.js +1 -1
  143. package/dist/engines/environment/handles.js +1 -0
  144. package/dist/engines/environment/index.js +1 -0
  145. package/dist/engines/factory.js +1 -1
  146. package/dist/engines/installations/node-vitest.js +1 -1
  147. package/dist/engines/installations/package-resolution.js +1 -1
  148. package/dist/engines/installations/playwright.js +1 -1
  149. package/dist/engines/managed-module-resolution.js +8 -4
  150. package/dist/engines/manager.js +1 -1
  151. package/dist/engines/node-vitest/adapter/adapter.js +1 -1
  152. package/dist/engines/node-vitest/adapter/driver.js +2 -0
  153. package/dist/engines/node-vitest/adapter/evidence.js +2 -2
  154. package/dist/engines/node-vitest/adapter/failure-details.js +4 -2
  155. package/dist/engines/node-vitest/adapter/reporter.js +1 -1
  156. package/dist/engines/node-vitest/adapter/workspace.js +17 -195
  157. package/dist/engines/node-vitest/inventory/index.js +2 -0
  158. package/dist/engines/node-vitest/inventory/list-files.js +3 -0
  159. package/dist/engines/node-vitest/runtime/data/index.js +1 -1
  160. package/dist/engines/node-vitest/runtime/data/report.js +5 -6
  161. package/dist/engines/node-vitest/runtime/data/scenario.js +2 -2
  162. package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
  163. package/dist/engines/node-vitest/selection.js +1 -0
  164. package/dist/engines/playwright/adapter/adapter.js +1 -1
  165. package/dist/engines/playwright/adapter/config.js +3 -3
  166. package/dist/engines/playwright/adapter/evidence-validation.js +1 -1
  167. package/dist/engines/playwright/adapter/evidence.js +1 -1
  168. package/dist/engines/playwright/adapter/reporter.js +1 -1
  169. package/dist/engines/playwright/runtime/config-file.js +1 -1
  170. package/dist/engines/playwright/runtime/config.js +1 -1
  171. package/dist/engines/playwright/runtime/managed-test.js +1 -0
  172. package/dist/engines/playwright/runtime/runtime-input.js +29 -10
  173. package/dist/engines/runtime-input-file.js +1 -1
  174. package/dist/environment/lifecycle-controller.js +1 -1
  175. package/dist/environment/lifecycle.js +1 -1
  176. package/dist/environment/ready-environment.js +1 -1
  177. package/dist/environment/run-environment.js +1 -1
  178. package/dist/environment/run-stopping.js +1 -1
  179. package/dist/environment/runtime-contexts.js +1 -1
  180. package/dist/environment/runtime-manager.js +1 -1
  181. package/dist/environment/runtime-planning.js +1 -1
  182. package/dist/environment/runtime-preparation.js +1 -1
  183. package/dist/environment/services.js +3 -3
  184. package/dist/environment/template.js +1 -1
  185. package/dist/evidence/artifact-config.js +1 -1
  186. package/dist/evidence/artifacts.js +2 -2
  187. package/dist/evidence/bundles.js +1 -1
  188. package/dist/evidence/environment-record.js +1 -1
  189. package/dist/evidence/index.js +1 -1
  190. package/dist/evidence/maintenance.js +1 -0
  191. package/dist/evidence/read-run.js +1 -1
  192. package/dist/evidence/reading.js +1 -1
  193. package/dist/evidence/redaction.js +4 -0
  194. package/dist/evidence/reporting.js +1 -1
  195. package/dist/evidence/run-model.js +1 -0
  196. package/dist/evidence/storage.js +2 -2
  197. package/dist/evidence/timing.js +1 -1
  198. package/dist/kernel/error-serialization.js +1 -1
  199. package/dist/kernel/known-keys.js +1 -0
  200. package/dist/kernel/redaction-targets.js +1 -0
  201. package/dist/kernel/redaction.js +4 -1
  202. package/dist/kernel/unknown-values.js +1 -1
  203. package/dist/process/environment.js +1 -1
  204. package/dist/process/execa-bundle.json +3 -3
  205. package/dist/process/files/json-file.js +1 -1
  206. package/dist/process/host/platform.js +1 -1
  207. package/dist/process/host-process.js +1 -1
  208. package/dist/process/index.js +1 -1
  209. package/dist/process/locks.js +4 -4
  210. package/dist/process/port-listener.js +2 -0
  211. package/dist/process/process-group.js +1 -1
  212. package/dist/process/process.js +32 -32
  213. package/dist/process/readiness.js +1 -1
  214. package/dist/process/ready-deadline.js +1 -0
  215. package/dist/process/runs/ownership.js +1 -1
  216. package/dist/process/runs/stop.js +1 -1
  217. package/dist/process/service-processes.js +1 -1
  218. package/dist/process/windows-cli-owner.js +3 -3
  219. package/dist/process/windows-native.js +1 -1
  220. package/dist/repo/fingerprint-policy.js +1 -1
  221. package/dist/repo/managed-git.js +1 -1
  222. package/dist/repo/physical-tree.js +1 -1
  223. package/dist/repo/state.js +4 -4
  224. package/dist/steps/build-config.js +1 -1
  225. package/dist/steps/configured-step-testkit-modules.js +1 -1
  226. package/dist/steps/configured-steps.js +1 -1
  227. package/dist/steps/environment.js +1 -1
  228. package/dist/steps/index.js +1 -1
  229. package/dist/toolchains/index.js +3 -3
  230. package/dist/toolchains/semver.js +1 -1
  231. package/dist/toolchains/vitest/index.js +1 -1
  232. package/dist/tracker/redaction.js +1 -2
  233. package/dist/{config/runtime/build-assets.d.ts → types/config-build-assets.d.ts} +5 -3
  234. package/dist/{database/steps.d.ts → types/config-database-steps.d.ts} +7 -7
  235. package/dist/{config/runtime/next-runtime-tsconfig.d.ts → types/config-next-runtime-tsconfig.d.ts} +5 -3
  236. package/dist/types/config.d.ts +422 -0
  237. package/dist/types/drizzle.d.ts +13 -0
  238. package/dist/{config/runtime/env/index.d.ts → types/env.d.ts} +22 -20
  239. package/dist/types/environment.d.ts +46 -0
  240. package/dist/types/index.d.ts +21 -0
  241. package/dist/types/node-vitest-data.d.ts +191 -0
  242. package/dist/types/playwright.d.ts +130 -0
  243. package/dist/types/tooling-vitest.d.ts +13 -0
  244. package/dist/types/workspace.d.ts +633 -0
  245. package/docs/bug-records.md +35 -40
  246. package/docs/engines.md +259 -0
  247. package/docs/release-notes.md +2116 -0
  248. package/docs/test-types.md +37 -85
  249. package/package.json +22 -32
  250. package/testkit-config-schema.md +391 -260
  251. package/dist/app/bugs/areas.d.ts +0 -38
  252. package/dist/app/bugs/assessment.d.ts +0 -9
  253. package/dist/app/bugs/categories.d.ts +0 -41
  254. package/dist/app/bugs/ci-report.d.ts +0 -21
  255. package/dist/app/bugs/ci-summary.d.ts +0 -13
  256. package/dist/app/bugs/draft.d.ts +0 -70
  257. package/dist/app/bugs/facts.d.ts +0 -49
  258. package/dist/app/bugs/file.d.ts +0 -45
  259. package/dist/app/bugs/gate.d.ts +0 -22
  260. package/dist/app/bugs/guide.d.ts +0 -20
  261. package/dist/app/bugs/issue.d.ts +0 -18
  262. package/dist/app/bugs/known-failures.d.ts +0 -49
  263. package/dist/app/bugs/record.d.ts +0 -14
  264. package/dist/app/bugs/run-reading.d.ts +0 -51
  265. package/dist/app/bugs/store.d.ts +0 -34
  266. package/dist/app/campaigns/brief.d.ts +0 -7
  267. package/dist/app/campaigns/campaign.d.ts +0 -14
  268. package/dist/app/campaigns/index.d.ts +0 -38
  269. package/dist/app/campaigns/store.d.ts +0 -5
  270. package/dist/app/campaigns/summary.d.ts +0 -13
  271. package/dist/app/cleanup/index.d.ts +0 -52
  272. package/dist/app/db-schema/prepare.d.ts +0 -11
  273. package/dist/app/db-schema/refresh.d.ts +0 -17
  274. package/dist/app/db-schema/verify.d.ts +0 -11
  275. package/dist/app/destroy/index.d.ts +0 -16
  276. package/dist/app/discover/index.d.ts +0 -8
  277. package/dist/app/doctor/index.d.ts +0 -17
  278. package/dist/app/environments/config-driven.d.ts +0 -5
  279. package/dist/app/environments/routing.d.ts +0 -6
  280. package/dist/app/environments/supplied.d.ts +0 -3
  281. package/dist/app/file-selection.d.ts +0 -1
  282. package/dist/app/inspect/artifacts.d.ts +0 -30
  283. package/dist/app/inspect/index.d.ts +0 -112
  284. package/dist/app/lint/index.d.ts +0 -28
  285. package/dist/app/lint/native.d.ts +0 -10
  286. package/dist/app/lint/options.d.ts +0 -66
  287. package/dist/app/lint/policy.d.ts +0 -21
  288. package/dist/app/lint/rules/data.d.ts +0 -3
  289. package/dist/app/lint/rules/data.js +0 -1
  290. package/dist/app/lint/rules/engine-imports.d.ts +0 -3
  291. package/dist/app/lint/rules/syntax.d.ts +0 -4
  292. package/dist/app/lint/rules/unit.d.ts +0 -3
  293. package/dist/app/lint/shared.d.ts +0 -34
  294. package/dist/app/package-inspection.d.ts +0 -20
  295. package/dist/app/reports/files.d.ts +0 -13
  296. package/dist/app/reports/prepare.d.ts +0 -20
  297. package/dist/app/reports/publish.d.ts +0 -21
  298. package/dist/app/run/endpoint-readiness.d.ts +0 -43
  299. package/dist/app/run/endpoint-readiness.js +0 -1
  300. package/dist/app/run/engine-evidence-persistence.d.ts +0 -39
  301. package/dist/app/run/engine-execution-cleanup.d.ts +0 -8
  302. package/dist/app/run/engine-execution-cleanup.js +0 -1
  303. package/dist/app/run/engine-execution-failures.d.ts +0 -41
  304. package/dist/app/run/engine-execution-observer.d.ts +0 -21
  305. package/dist/app/run/engine-execution-reporting.d.ts +0 -17
  306. package/dist/app/run/engine-execution.d.ts +0 -65
  307. package/dist/app/run/engine-failure-stack.d.ts +0 -1
  308. package/dist/app/run/engine-orchestration.d.ts +0 -30
  309. package/dist/app/run/environment.d.ts +0 -33
  310. package/dist/app/run/failure-details.d.ts +0 -37
  311. package/dist/app/run/live-run.d.ts +0 -29
  312. package/dist/app/run/operation-progress.d.ts +0 -13
  313. package/dist/app/run/orchestrator.d.ts +0 -75
  314. package/dist/app/run/planning-types.d.ts +0 -68
  315. package/dist/app/run/planning.d.ts +0 -14
  316. package/dist/app/run/request.d.ts +0 -30
  317. package/dist/app/run/results.d.ts +0 -161
  318. package/dist/app/run/run-events.d.ts +0 -144
  319. package/dist/app/run/run-finalization.d.ts +0 -56
  320. package/dist/app/run/run-guards.d.ts +0 -3
  321. package/dist/app/run/runtime-failures.d.ts +0 -18
  322. package/dist/app/run/runtime-fixtures.d.ts +0 -2
  323. package/dist/app/run/runtime-task-types.d.ts +0 -20
  324. package/dist/app/run/scheduler/estimates.d.ts +0 -32
  325. package/dist/app/run/scheduler/identity.d.ts +0 -9
  326. package/dist/app/run/scheduler/index.d.ts +0 -124
  327. package/dist/app/run/scheduler/locks.d.ts +0 -6
  328. package/dist/app/run/scheduler/observations.d.ts +0 -20
  329. package/dist/app/run/selection.d.ts +0 -9
  330. package/dist/app/run/setup/runtime-node-setup-errors.d.ts +0 -13
  331. package/dist/app/run/setup/runtime-node-setup-protocol.d.ts +0 -85
  332. package/dist/app/run/setup/runtime-node-setup-worker.d.ts +0 -1
  333. package/dist/app/run/setup/runtime-node-setup.d.ts +0 -48
  334. package/dist/app/run/task-batches.d.ts +0 -23
  335. package/dist/app/run/task-leases.d.ts +0 -15
  336. package/dist/app/run/worker-loop.d.ts +0 -66
  337. package/dist/app/setup/playwright.d.ts +0 -22
  338. package/dist/app/status/index.d.ts +0 -9
  339. package/dist/app/status/model.d.ts +0 -29
  340. package/dist/app/status/runs.d.ts +0 -99
  341. package/dist/app/stop/index.d.ts +0 -14
  342. package/dist/app/tracker/index.d.ts +0 -13
  343. package/dist/app/tracker/remote.d.ts +0 -13
  344. package/dist/app/tracker/token.d.ts +0 -7
  345. package/dist/app/typecheck/index.d.ts +0 -63
  346. package/dist/cli/command-catalog.d.ts +0 -156
  347. package/dist/cli/command-flags.d.ts +0 -19
  348. package/dist/cli/command-registry.d.ts +0 -3
  349. package/dist/cli/commands/artifacts.d.ts +0 -48
  350. package/dist/cli/commands/bug/file.d.ts +0 -16
  351. package/dist/cli/commands/bug/guide.d.ts +0 -5
  352. package/dist/cli/commands/bug/record.d.ts +0 -9
  353. package/dist/cli/commands/campaign/finish.d.ts +0 -10
  354. package/dist/cli/commands/campaign/start.d.ts +0 -7
  355. package/dist/cli/commands/campaign/status.d.ts +0 -13
  356. package/dist/cli/commands/ci/report.d.ts +0 -15
  357. package/dist/cli/commands/cleanup.d.ts +0 -13
  358. package/dist/cli/commands/db/schema/refresh.d.ts +0 -2
  359. package/dist/cli/commands/db/schema/verify.d.ts +0 -2
  360. package/dist/cli/commands/destroy.d.ts +0 -9
  361. package/dist/cli/commands/discover.d.ts +0 -2
  362. package/dist/cli/commands/doctor.d.ts +0 -2
  363. package/dist/cli/commands/guard/unsafe-entrypoint.d.ts +0 -2
  364. package/dist/cli/commands/lint.d.ts +0 -2
  365. package/dist/cli/commands/report/prepare.d.ts +0 -12
  366. package/dist/cli/commands/report/publish.d.ts +0 -13
  367. package/dist/cli/commands/run/status.d.ts +0 -5
  368. package/dist/cli/commands/run/stop.d.ts +0 -7
  369. package/dist/cli/commands/run.d.ts +0 -9
  370. package/dist/cli/commands/setup/playwright.d.ts +0 -2
  371. package/dist/cli/commands/status.d.ts +0 -5
  372. package/dist/cli/commands/stop.d.ts +0 -12
  373. package/dist/cli/commands/typecheck.d.ts +0 -2
  374. package/dist/cli/commands/workspace.d.ts +0 -2
  375. package/dist/cli/entrypoint.d.ts +0 -1
  376. package/dist/cli/framework/command.d.ts +0 -21
  377. package/dist/cli/framework/definitions.d.ts +0 -100
  378. package/dist/cli/framework/errors.d.ts +0 -6
  379. package/dist/cli/framework/execute.d.ts +0 -14
  380. package/dist/cli/framework/help.d.ts +0 -11
  381. package/dist/cli/framework/index.d.ts +0 -3
  382. package/dist/cli/framework/parser.d.ts +0 -6
  383. package/dist/cli/index.d.ts +0 -4
  384. package/dist/cli/json-errors.d.ts +0 -3
  385. package/dist/cli/operations/db/schema/refresh/operation.d.ts +0 -7
  386. package/dist/cli/operations/db/schema/verify/operation.d.ts +0 -7
  387. package/dist/cli/operations/run/operation.d.ts +0 -26
  388. package/dist/cli/process-signal.d.ts +0 -1
  389. package/dist/cli/renderers/bug/text.d.ts +0 -8
  390. package/dist/cli/renderers/campaign/text.d.ts +0 -2
  391. package/dist/cli/renderers/ci/text.d.ts +0 -2
  392. package/dist/cli/renderers/cleanup/format.d.ts +0 -14
  393. package/dist/cli/renderers/db-schema/text.d.ts +0 -4
  394. package/dist/cli/renderers/destroy/text.d.ts +0 -4
  395. package/dist/cli/renderers/discover/report.d.ts +0 -7
  396. package/dist/cli/renderers/discover/text.d.ts +0 -3
  397. package/dist/cli/renderers/doctor/text.d.ts +0 -2
  398. package/dist/cli/renderers/lint/text.d.ts +0 -2
  399. package/dist/cli/renderers/run/events.d.ts +0 -8
  400. package/dist/cli/renderers/run/failure.d.ts +0 -8
  401. package/dist/cli/renderers/run/formatting.d.ts +0 -79
  402. package/dist/cli/renderers/run/status.d.ts +0 -6
  403. package/dist/cli/renderers/run/text-reporter.d.ts +0 -19
  404. package/dist/cli/renderers/status/text.d.ts +0 -2
  405. package/dist/cli/renderers/stop/text.d.ts +0 -7
  406. package/dist/cli/renderers/typecheck/text.d.ts +0 -2
  407. package/dist/cli/terminal/colors.d.ts +0 -10
  408. package/dist/cli/terminal/layout.d.ts +0 -11
  409. package/dist/cli/version-drift.d.ts +0 -25
  410. package/dist/config/authoring/build-config-contract.d.ts +0 -27
  411. package/dist/config/authoring/configured-step-contract.d.ts +0 -18
  412. package/dist/config/authoring/http-execution-contract.d.ts +0 -70
  413. package/dist/config/authoring/http-methods.d.ts +0 -18
  414. package/dist/config/authoring/index.d.ts +0 -372
  415. package/dist/config/authoring/preset-env.d.ts +0 -19
  416. package/dist/config/authoring/runtime.d.ts +0 -64
  417. package/dist/config/authoring/runtime.js +0 -1
  418. package/dist/config/loader/bugs.d.ts +0 -15
  419. package/dist/config/loader/config-loader.d.ts +0 -9
  420. package/dist/config/loader/database-materialization.d.ts +0 -19
  421. package/dist/config/loader/database-roles.d.ts +0 -2
  422. package/dist/config/loader/database.d.ts +0 -55
  423. package/dist/config/loader/decode-discovery.d.ts +0 -5
  424. package/dist/config/loader/decode-execution.d.ts +0 -7
  425. package/dist/config/loader/dependencies.d.ts +0 -7
  426. package/dist/config/loader/discover-tests.d.ts +0 -111
  427. package/dist/config/loader/discovery-summary.d.ts +0 -29
  428. package/dist/config/loader/discovery.d.ts +0 -53
  429. package/dist/config/loader/env.d.ts +0 -4
  430. package/dist/config/loader/execution-model.d.ts +0 -15
  431. package/dist/config/loader/file-metadata.d.ts +0 -19
  432. package/dist/config/loader/groups.d.ts +0 -33
  433. package/dist/config/loader/index.d.ts +0 -10
  434. package/dist/config/loader/load.d.ts +0 -89
  435. package/dist/config/loader/managed-configs.d.ts +0 -23
  436. package/dist/config/loader/path-policy.d.ts +0 -9
  437. package/dist/config/loader/paths.d.ts +0 -5
  438. package/dist/config/loader/runtime-isolation.d.ts +0 -44
  439. package/dist/config/loader/runtime.d.ts +0 -16
  440. package/dist/config/loader/skip-config.d.ts +0 -44
  441. package/dist/config/loader/test-selection.d.ts +0 -15
  442. package/dist/config/loader/validation.d.ts +0 -15
  443. package/dist/config/loader/values.d.ts +0 -3
  444. package/dist/config/loader/values.js +0 -1
  445. package/dist/database/activity-gate.d.ts +0 -22
  446. package/dist/database/admin.d.ts +0 -31
  447. package/dist/database/cleanup.d.ts +0 -36
  448. package/dist/database/configured-steps.d.ts +0 -27
  449. package/dist/database/constants.d.ts +0 -11
  450. package/dist/database/docker-metadata.d.ts +0 -3
  451. package/dist/database/docker.d.ts +0 -65
  452. package/dist/database/drizzle/index.d.ts +0 -13
  453. package/dist/database/fingerprint.d.ts +0 -12
  454. package/dist/database/index.d.ts +0 -39
  455. package/dist/database/lifecycle-cleanup.d.ts +0 -8
  456. package/dist/database/local-postgres.d.ts +0 -71
  457. package/dist/database/naming.d.ts +0 -17
  458. package/dist/database/postgres/index.d.ts +0 -71
  459. package/dist/database/progress.d.ts +0 -6
  460. package/dist/database/roles.d.ts +0 -19
  461. package/dist/database/runtime-config.d.ts +0 -16
  462. package/dist/database/runtime-reservations.d.ts +0 -19
  463. package/dist/database/schema-operations.d.ts +0 -18
  464. package/dist/database/schema-source.d.ts +0 -96
  465. package/dist/database/source-refresh-lock.d.ts +0 -8
  466. package/dist/database/source-url.d.ts +0 -21
  467. package/dist/database/state-files.d.ts +0 -13
  468. package/dist/database/state.d.ts +0 -26
  469. package/dist/database/template-steps.d.ts +0 -39
  470. package/dist/domain/file-timeout.d.ts +0 -25
  471. package/dist/domain/identifiers.d.ts +0 -9
  472. package/dist/domain/operation-display.d.ts +0 -10
  473. package/dist/domain/operation-reason.d.ts +0 -5
  474. package/dist/domain/postgres-route.d.ts +0 -4
  475. package/dist/domain/runtime-identity.d.ts +0 -1
  476. package/dist/domain/runtime-isolation-contract.d.ts +0 -5
  477. package/dist/domain/service-name.d.ts +0 -2
  478. package/dist/domain/suite-selection.d.ts +0 -20
  479. package/dist/domain/test-outcomes.d.ts +0 -2
  480. package/dist/domain/test-types.d.ts +0 -16
  481. package/dist/engines/adapters/evidence-files.d.ts +0 -32
  482. package/dist/engines/adapters/evidence-identity.d.ts +0 -12
  483. package/dist/engines/adapters/execution.d.ts +0 -41
  484. package/dist/engines/adapters/native-report.d.ts +0 -25
  485. package/dist/engines/adapters/node-startup-cache.d.ts +0 -8
  486. package/dist/engines/adapters/workspace.d.ts +0 -4
  487. package/dist/engines/api/capabilities.d.ts +0 -21
  488. package/dist/engines/api/capabilities.js +0 -1
  489. package/dist/engines/api/evidence.d.ts +0 -38
  490. package/dist/engines/api/execution-observer.d.ts +0 -8
  491. package/dist/engines/api/execution-scope.d.ts +0 -17
  492. package/dist/engines/api/execution.d.ts +0 -101
  493. package/dist/engines/api/index.d.ts +0 -5
  494. package/dist/engines/api/k6-runtime-input.d.ts +0 -26
  495. package/dist/engines/api/k6-runtime-input.js +0 -1
  496. package/dist/engines/api/runtime-artifact.d.ts +0 -19
  497. package/dist/engines/bundle-cache.d.ts +0 -32
  498. package/dist/engines/catalog.d.ts +0 -27
  499. package/dist/engines/contracts/fixture-manifest.d.ts +0 -34
  500. package/dist/engines/contracts/json-bounds.d.ts +0 -36
  501. package/dist/engines/contracts/json-bounds.js +0 -2
  502. package/dist/engines/contracts/k6-repository-configuration.d.ts +0 -12
  503. package/dist/engines/contracts/k6-repository-configuration.js +0 -1
  504. package/dist/engines/contracts/test-context.d.ts +0 -15
  505. package/dist/engines/contracts/test-context.js +0 -1
  506. package/dist/engines/definitions.d.ts +0 -23
  507. package/dist/engines/factory.d.ts +0 -6
  508. package/dist/engines/generated-performance.d.ts +0 -1
  509. package/dist/engines/installation-catalog.d.ts +0 -27
  510. package/dist/engines/installation-catalog.js +0 -1
  511. package/dist/engines/installations/k6.d.ts +0 -98
  512. package/dist/engines/installations/k6.js +0 -1
  513. package/dist/engines/installations/node-vitest.d.ts +0 -33
  514. package/dist/engines/installations/package-requirements.d.ts +0 -28
  515. package/dist/engines/installations/package-resolution.d.ts +0 -51
  516. package/dist/engines/installations/playwright-resolution-child.d.ts +0 -1
  517. package/dist/engines/installations/playwright.d.ts +0 -75
  518. package/dist/engines/installations/types.d.ts +0 -10
  519. package/dist/engines/k6/adapter/bundle.d.ts +0 -25
  520. package/dist/engines/k6/adapter/bundle.js +0 -112
  521. package/dist/engines/k6/adapter/evidence.d.ts +0 -15
  522. package/dist/engines/k6/adapter/evidence.js +0 -4
  523. package/dist/engines/k6/adapter/executor.d.ts +0 -13
  524. package/dist/engines/k6/adapter/executor.js +0 -1
  525. package/dist/engines/k6/adapter/index.d.ts +0 -1
  526. package/dist/engines/k6/adapter/index.js +0 -1
  527. package/dist/engines/k6/adapter/input.d.ts +0 -21
  528. package/dist/engines/k6/adapter/input.js +0 -1
  529. package/dist/engines/k6/adapter/native-summary.d.ts +0 -11
  530. package/dist/engines/k6/adapter/native-summary.js +0 -1
  531. package/dist/engines/k6/adapter/repository-configuration.d.ts +0 -2
  532. package/dist/engines/k6/adapter/repository-configuration.js +0 -1
  533. package/dist/engines/k6/authoring-type-paths.d.ts +0 -3
  534. package/dist/engines/k6/authoring-type-paths.js +0 -1
  535. package/dist/engines/k6/runtime/ambient-types/bundle-manifest.json +0 -146
  536. package/dist/engines/k6/runtime/ambient-types/k6/LICENSE +0 -21
  537. package/dist/engines/k6/runtime/ambient-types/k6/browser/index.d.ts +0 -6332
  538. package/dist/engines/k6/runtime/ambient-types/k6/crypto/index.d.ts +0 -218
  539. package/dist/engines/k6/runtime/ambient-types/k6/data/index.d.ts +0 -16
  540. package/dist/engines/k6/runtime/ambient-types/k6/encoding/index.d.ts +0 -46
  541. package/dist/engines/k6/runtime/ambient-types/k6/execution/index.d.ts +0 -127
  542. package/dist/engines/k6/runtime/ambient-types/k6/experimental/csv/index.d.ts +0 -96
  543. package/dist/engines/k6/runtime/ambient-types/k6/experimental/fs/index.d.ts +0 -104
  544. package/dist/engines/k6/runtime/ambient-types/k6/experimental/redis/index.d.ts +0 -821
  545. package/dist/engines/k6/runtime/ambient-types/k6/experimental/streams/index.d.ts +0 -198
  546. package/dist/engines/k6/runtime/ambient-types/k6/global.d.ts +0 -83
  547. package/dist/engines/k6/runtime/ambient-types/k6/html/index.d.ts +0 -1325
  548. package/dist/engines/k6/runtime/ambient-types/k6/http/index.d.ts +0 -806
  549. package/dist/engines/k6/runtime/ambient-types/k6/index.d.ts +0 -126
  550. package/dist/engines/k6/runtime/ambient-types/k6/metrics/index.d.ts +0 -66
  551. package/dist/engines/k6/runtime/ambient-types/k6/net/grpc/index.d.ts +0 -247
  552. package/dist/engines/k6/runtime/ambient-types/k6/options/index.d.ts +0 -459
  553. package/dist/engines/k6/runtime/ambient-types/k6/package.json +0 -79
  554. package/dist/engines/k6/runtime/ambient-types/k6/secrets/index.d.ts +0 -36
  555. package/dist/engines/k6/runtime/ambient-types/k6/timers/index.d.ts +0 -47
  556. package/dist/engines/k6/runtime/ambient-types/k6/websockets/index.d.ts +0 -324
  557. package/dist/engines/k6/runtime/ambient-types/k6/ws/index.d.ts +0 -283
  558. package/dist/engines/k6/runtime/ambient-types/xk6-sql/LICENSE +0 -201
  559. package/dist/engines/k6/runtime/ambient-types/xk6-sql/index.d.ts +0 -397
  560. package/dist/engines/k6/runtime/ambient-types/xk6-sql/package.json +0 -15
  561. package/dist/engines/k6/runtime/artifacts.d.ts +0 -2
  562. package/dist/engines/k6/runtime/artifacts.js +0 -1
  563. package/dist/engines/k6/runtime/checks.d.ts +0 -17
  564. package/dist/engines/k6/runtime/checks.js +0 -1
  565. package/dist/engines/k6/runtime/dal-fixtures.d.ts +0 -24
  566. package/dist/engines/k6/runtime/dal-fixtures.js +0 -1
  567. package/dist/engines/k6/runtime/dal-suite.d.ts +0 -24
  568. package/dist/engines/k6/runtime/dal-suite.js +0 -1
  569. package/dist/engines/k6/runtime/dal.d.ts +0 -10
  570. package/dist/engines/k6/runtime/dal.js +0 -1
  571. package/dist/engines/k6/runtime/fixtures.d.ts +0 -3
  572. package/dist/engines/k6/runtime/fixtures.js +0 -1
  573. package/dist/engines/k6/runtime/http-assertions.d.ts +0 -19
  574. package/dist/engines/k6/runtime/http-assertions.js +0 -1
  575. package/dist/engines/k6/runtime/http-checks.d.ts +0 -19
  576. package/dist/engines/k6/runtime/http-checks.js +0 -1
  577. package/dist/engines/k6/runtime/http-suite-runtime.d.ts +0 -103
  578. package/dist/engines/k6/runtime/http-suite-runtime.js +0 -1
  579. package/dist/engines/k6/runtime/http.d.ts +0 -15
  580. package/dist/engines/k6/runtime/http.js +0 -1
  581. package/dist/engines/k6/runtime/index.d.ts +0 -11
  582. package/dist/engines/k6/runtime/index.js +0 -1
  583. package/dist/engines/k6/runtime/input.d.ts +0 -3
  584. package/dist/engines/k6/runtime/input.js +0 -1
  585. package/dist/engines/k6/runtime/k6-repository-configuration.d.ts +0 -9
  586. package/dist/engines/k6/runtime/k6-repository-configuration.js +0 -1
  587. package/dist/engines/k6/runtime/node-setup.d.ts +0 -13
  588. package/dist/engines/k6/runtime/node-setup.js +0 -1
  589. package/dist/engines/k6/runtime/runtime-globals.d.ts +0 -10
  590. package/dist/engines/k6/runtime/runtime.d.ts +0 -54
  591. package/dist/engines/k6/runtime/runtime.js +0 -1
  592. package/dist/engines/k6/runtime/shared/assertion-details.d.ts +0 -19
  593. package/dist/engines/k6/runtime/shared/assertion-details.js +0 -2
  594. package/dist/engines/k6/runtime/shared/db-normalization.d.ts +0 -19
  595. package/dist/engines/k6/runtime/shared/db-normalization.js +0 -1
  596. package/dist/engines/k6/runtime/shared/error-body.d.ts +0 -3
  597. package/dist/engines/k6/runtime/shared/error-body.js +0 -1
  598. package/dist/engines/k6/runtime/shared/file-data.d.ts +0 -1
  599. package/dist/engines/k6/runtime/shared/file-data.js +0 -1
  600. package/dist/engines/k6/runtime/shared/fixture-engine.d.ts +0 -8
  601. package/dist/engines/k6/runtime/shared/fixture-engine.js +0 -2
  602. package/dist/engines/k6/runtime/shared/http-check-plan.d.ts +0 -29
  603. package/dist/engines/k6/runtime/shared/http-check-plan.js +0 -1
  604. package/dist/engines/k6/runtime/shared/http-parsing.d.ts +0 -10
  605. package/dist/engines/k6/runtime/shared/http-parsing.js +0 -3
  606. package/dist/engines/k6/runtime/shared/ordering.d.ts +0 -2
  607. package/dist/engines/k6/runtime/shared/ordering.js +0 -1
  608. package/dist/engines/k6/runtime/shared/properties.d.ts +0 -1
  609. package/dist/engines/k6/runtime/shared/properties.js +0 -1
  610. package/dist/engines/k6/runtime/suite.d.ts +0 -4
  611. package/dist/engines/k6/runtime/suite.js +0 -1
  612. package/dist/engines/k6/runtime/types.d.ts +0 -244
  613. package/dist/engines/k6/runtime/types.js +0 -1
  614. package/dist/engines/k6/runtime/xk6-sql-driver-postgres.d.ts +0 -7
  615. package/dist/engines/k6/runtime/xk6-sql-driver-postgres.js +0 -1
  616. package/dist/engines/managed-module-resolution-policy-input.d.ts +0 -8
  617. package/dist/engines/managed-module-resolution-policy.d.ts +0 -25
  618. package/dist/engines/managed-module-resolution.d.ts +0 -13
  619. package/dist/engines/manager.d.ts +0 -25
  620. package/dist/engines/node-vitest/adapter/adapter.d.ts +0 -16
  621. package/dist/engines/node-vitest/adapter/consumer-typescript-paths.d.ts +0 -17
  622. package/dist/engines/node-vitest/adapter/consumer-typescript-paths.js +0 -3
  623. package/dist/engines/node-vitest/adapter/evidence.d.ts +0 -33
  624. package/dist/engines/node-vitest/adapter/failure-details.d.ts +0 -3
  625. package/dist/engines/node-vitest/adapter/index.d.ts +0 -1
  626. package/dist/engines/node-vitest/adapter/reporter.d.ts +0 -7
  627. package/dist/engines/node-vitest/adapter/resolution.d.ts +0 -12
  628. package/dist/engines/node-vitest/adapter/resolution.js +0 -1
  629. package/dist/engines/node-vitest/adapter/workspace.d.ts +0 -19
  630. package/dist/engines/node-vitest/runtime/contract/index.d.ts +0 -64
  631. package/dist/engines/node-vitest/runtime/contract/index.js +0 -1
  632. package/dist/engines/node-vitest/runtime/data/http.d.ts +0 -4
  633. package/dist/engines/node-vitest/runtime/data/http.js +0 -1
  634. package/dist/engines/node-vitest/runtime/data/index.d.ts +0 -8
  635. package/dist/engines/node-vitest/runtime/data/primitives.d.ts +0 -1
  636. package/dist/engines/node-vitest/runtime/data/report.d.ts +0 -3
  637. package/dist/engines/node-vitest/runtime/data/runner.d.ts +0 -4
  638. package/dist/engines/node-vitest/runtime/data/runner.js +0 -1
  639. package/dist/engines/node-vitest/runtime/data/scenario.d.ts +0 -11
  640. package/dist/engines/node-vitest/runtime/data/types.d.ts +0 -384
  641. package/dist/engines/node-vitest/runtime/runtime-input.d.ts +0 -64
  642. package/dist/engines/playwright/adapter/adapter.d.ts +0 -18
  643. package/dist/engines/playwright/adapter/attachments.d.ts +0 -26
  644. package/dist/engines/playwright/adapter/config.d.ts +0 -45
  645. package/dist/engines/playwright/adapter/evidence-validation.d.ts +0 -9
  646. package/dist/engines/playwright/adapter/evidence.d.ts +0 -32
  647. package/dist/engines/playwright/adapter/failure-details.d.ts +0 -2
  648. package/dist/engines/playwright/adapter/index.d.ts +0 -3
  649. package/dist/engines/playwright/adapter/reporter.d.ts +0 -12
  650. package/dist/engines/playwright/runtime/config-file.d.ts +0 -2
  651. package/dist/engines/playwright/runtime/config.d.ts +0 -24
  652. package/dist/engines/playwright/runtime/index.d.ts +0 -4
  653. package/dist/engines/playwright/runtime/runtime-input.d.ts +0 -36
  654. package/dist/engines/playwright/runtime/sandbox.d.ts +0 -84
  655. package/dist/engines/runtime-input-file.d.ts +0 -27
  656. package/dist/environment/lifecycle-artifacts.d.ts +0 -7
  657. package/dist/environment/lifecycle-controller.d.ts +0 -60
  658. package/dist/environment/lifecycle.d.ts +0 -32
  659. package/dist/environment/maintenance.d.ts +0 -68
  660. package/dist/environment/planning-types.d.ts +0 -33
  661. package/dist/environment/ports.d.ts +0 -10
  662. package/dist/environment/ready-environment.d.ts +0 -16
  663. package/dist/environment/run-environment.d.ts +0 -39
  664. package/dist/environment/run-stopping.d.ts +0 -13
  665. package/dist/environment/runtime-contexts.d.ts +0 -37
  666. package/dist/environment/runtime-manager.d.ts +0 -87
  667. package/dist/environment/runtime-planning.d.ts +0 -16
  668. package/dist/environment/runtime-preparation.d.ts +0 -30
  669. package/dist/environment/runtime-service.d.ts +0 -12
  670. package/dist/environment/services.d.ts +0 -56
  671. package/dist/environment/state.d.ts +0 -15
  672. package/dist/environment/status-runtime.d.ts +0 -53
  673. package/dist/environment/template.d.ts +0 -164
  674. package/dist/evidence/artifact-config.d.ts +0 -14
  675. package/dist/evidence/artifact-validation.d.ts +0 -4
  676. package/dist/evidence/artifacts.d.ts +0 -75
  677. package/dist/evidence/bundles.d.ts +0 -27
  678. package/dist/evidence/ci-provenance.d.ts +0 -9
  679. package/dist/evidence/contracts.d.ts +0 -154
  680. package/dist/evidence/environment-record.d.ts +0 -22
  681. package/dist/evidence/file-evidence.d.ts +0 -23
  682. package/dist/evidence/finalization.d.ts +0 -9
  683. package/dist/evidence/index.d.ts +0 -8
  684. package/dist/evidence/logs.d.ts +0 -31
  685. package/dist/evidence/operation-timings.d.ts +0 -60
  686. package/dist/evidence/read-bundle.d.ts +0 -4
  687. package/dist/evidence/read-fields.d.ts +0 -21
  688. package/dist/evidence/read-provenance.d.ts +0 -2
  689. package/dist/evidence/read-redaction.d.ts +0 -2
  690. package/dist/evidence/read-retention.d.ts +0 -2
  691. package/dist/evidence/read-run.d.ts +0 -2
  692. package/dist/evidence/reading.d.ts +0 -28
  693. package/dist/evidence/reporting-types.d.ts +0 -349
  694. package/dist/evidence/reporting.d.ts +0 -3
  695. package/dist/evidence/secure-file-copy.d.ts +0 -24
  696. package/dist/evidence/setup-progress.d.ts +0 -63
  697. package/dist/evidence/step-output.d.ts +0 -16
  698. package/dist/evidence/storage-inventory.d.ts +0 -27
  699. package/dist/evidence/storage.d.ts +0 -25
  700. package/dist/evidence/timing.d.ts +0 -23
  701. package/dist/file.d.ts +0 -11
  702. package/dist/index.d.ts +0 -4
  703. package/dist/kernel/error-serialization.d.ts +0 -40
  704. package/dist/kernel/redaction.d.ts +0 -2
  705. package/dist/kernel/unknown-values.d.ts +0 -11
  706. package/dist/kernel/work-metrics.d.ts +0 -6
  707. package/dist/process/capture-output.d.ts +0 -7
  708. package/dist/process/command-shell.d.ts +0 -1
  709. package/dist/process/environment-overlay.d.ts +0 -17
  710. package/dist/process/environment.d.ts +0 -33
  711. package/dist/process/files/contained-path.d.ts +0 -8
  712. package/dist/process/files/directory-status.d.ts +0 -14
  713. package/dist/process/files/dotenv.d.ts +0 -2
  714. package/dist/process/files/file-snapshot.d.ts +0 -34
  715. package/dist/process/files/json-file.d.ts +0 -11
  716. package/dist/process/files/paths.d.ts +0 -3
  717. package/dist/process/files/product-dir.d.ts +0 -1
  718. package/dist/process/files/temp-dir.d.ts +0 -11
  719. package/dist/process/host/metadata.d.ts +0 -6
  720. package/dist/process/host/platform.d.ts +0 -57
  721. package/dist/process/host-command.d.ts +0 -4
  722. package/dist/process/host-inspection-command.d.ts +0 -13
  723. package/dist/process/host-process.d.ts +0 -19
  724. package/dist/process/index.d.ts +0 -9
  725. package/dist/process/lifecycle-fence.d.ts +0 -10
  726. package/dist/process/locks.d.ts +0 -28
  727. package/dist/process/process-contracts.d.ts +0 -78
  728. package/dist/process/process-group.d.ts +0 -12
  729. package/dist/process/process-identity.d.ts +0 -27
  730. package/dist/process/process-limits.d.ts +0 -6
  731. package/dist/process/process.d.ts +0 -12
  732. package/dist/process/readiness.d.ts +0 -43
  733. package/dist/process/recovery.d.ts +0 -3
  734. package/dist/process/runs/inspection.d.ts +0 -5
  735. package/dist/process/runs/manifest.d.ts +0 -86
  736. package/dist/process/runs/ownership.d.ts +0 -11
  737. package/dist/process/runs/product-state.d.ts +0 -2
  738. package/dist/process/runs/schema.d.ts +0 -3
  739. package/dist/process/runs/stop.d.ts +0 -19
  740. package/dist/process/runtime-socket.d.ts +0 -4
  741. package/dist/process/service-processes.d.ts +0 -13
  742. package/dist/process/shutdown.d.ts +0 -10
  743. package/dist/process/stoppable-settlement.d.ts +0 -26
  744. package/dist/process/url-redaction.d.ts +0 -1
  745. package/dist/process/windows-cli-owner.d.ts +0 -2
  746. package/dist/process/windows-native.d.ts +0 -12
  747. package/dist/process/windows-process-identity.d.ts +0 -4
  748. package/dist/repo/ci-environment.d.ts +0 -7
  749. package/dist/repo/fingerprint-policy.d.ts +0 -13
  750. package/dist/repo/git-path.d.ts +0 -2
  751. package/dist/repo/history.d.ts +0 -17
  752. package/dist/repo/managed-git.d.ts +0 -10
  753. package/dist/repo/metadata.d.ts +0 -3
  754. package/dist/repo/physical-tree.d.ts +0 -37
  755. package/dist/repo/publish-directory.d.ts +0 -20
  756. package/dist/repo/remote.d.ts +0 -6
  757. package/dist/repo/state.d.ts +0 -26
  758. package/dist/repo/tree-listing.d.ts +0 -10
  759. package/dist/steps/build-config.d.ts +0 -34
  760. package/dist/steps/configured-step-testkit-modules.d.ts +0 -19
  761. package/dist/steps/configured-steps.d.ts +0 -51
  762. package/dist/steps/environment.d.ts +0 -82
  763. package/dist/steps/index.d.ts +0 -2
  764. package/dist/steps/module-runner.d.ts +0 -1
  765. package/dist/steps/run.d.ts +0 -36
  766. package/dist/toolchains/archive.d.ts +0 -53
  767. package/dist/toolchains/esbuild.d.ts +0 -9
  768. package/dist/toolchains/host-node-support.d.ts +0 -3
  769. package/dist/toolchains/index.d.ts +0 -114
  770. package/dist/toolchains/managed-node-releases.d.ts +0 -28
  771. package/dist/toolchains/node-cache.d.ts +0 -20
  772. package/dist/toolchains/node-integrity.d.ts +0 -18
  773. package/dist/toolchains/node-provisioning.d.ts +0 -29
  774. package/dist/toolchains/semver.d.ts +0 -13
  775. package/dist/toolchains/shared-operation.d.ts +0 -11
  776. package/dist/toolchains/timeouts.d.ts +0 -1
  777. package/dist/toolchains/vitest/index.d.ts +0 -13
  778. package/dist/tracker/gitea.d.ts +0 -14
  779. package/dist/tracker/github.d.ts +0 -14
  780. package/dist/tracker/http.d.ts +0 -33
  781. package/dist/tracker/index.d.ts +0 -4
  782. package/dist/tracker/redaction.d.ts +0 -4
  783. package/dist/tracker/requests.d.ts +0 -17
  784. package/dist/tracker/responses.d.ts +0 -24
  785. package/dist/tracker/types.d.ts +0 -51
  786. package/docs/engine-architecture.md +0 -682
  787. /package/dist/engines/{k6/runtime/runtime-globals.js → api/profiles.js} +0 -0
@@ -1 +1 @@
1
- import{sanitizeErrorMessage as p}from"../../../kernel/error-serialization.js";import{isUnknownRecord as q}from"../../../kernel/unknown-values.js";export function formatDuration(e){const t=Math.max(0,Math.round(e/1e3)),i=Math.floor(t/60),n=t%60;return i===0?`${String(n)}s`:`${String(i)}m ${String(n).padStart(2,"0")}s`}function I(e){const t=e.skippedSuiteCount||0,i=e.completedSuiteCount-e.failedSuiteCount-t,n=e.suiteCount-e.completedSuiteCount;let s=`${String(i)}/${String(e.suiteCount)} suites passed`;return(e.totalFileCount||0)>0&&(s+=`, ${String(e.passedFileCount)}/${String(e.totalFileCount)} files passed`),t>0?s+=`, ${String(t)} ${S(t,"suite","suites")} skipped`:(e.skippedFileCount||0)>0&&(s+=`, ${String(e.skippedFileCount)} ${S(e.skippedFileCount,"file","files")} skipped`),n>0?s+=`, ${String(n)} ${S(n,"suite","suites")} not run`:(e.notRunFileCount||0)>0&&(s+=`, ${String(e.notRunFileCount)} ${S(e.notRunFileCount,"file","files")} not run`),s}function P(e){return e.reduce((t,i)=>Math.max(t,i.name.length),4)}export function buildRunSummaryData(e,t,i=null){const n=M(e),s=j(e);return{result:i==="failed"||i==="interrupted"||n.failedServices>0||n.infraFailedServices>0?"FAILED":"PASSED",totalServices:n.totalServices,failedServices:n.failedServices,infraFailedServices:n.infraFailedServices,blockedByRuntimeServices:n.blockedByRuntimeServices,passed:n.passedFiles,failed:n.failedFiles,skipped:n.skippedFiles,notRun:n.notRunFiles,files:n.totalFiles,duration:formatDuration(t),serviceErrors:s}}export function buildDebugRunSummaryLines(e,t,i=null){const n=e.length,s=e.filter(r=>!r.skipped),d=e.filter(r=>r.skipped),c=s.filter(r=>r.failed),u=s.filter(r=>r.infraFailed),f=s.filter(r=>!r.failed&&!r.infraFailed),C=s.reduce((r,o)=>r+o.suiteCount,0),R=s.reduce((r,o)=>r+o.completedSuiteCount,0),F=s.reduce((r,o)=>r+(o.skippedSuiteCount||0),0),E=s.reduce((r,o)=>r+o.failedSuiteCount,0),y=R-E-F,k=s.reduce((r,o)=>r+(o.totalFileCount||0),0),D=s.reduce((r,o)=>r+(o.passedFileCount||0),0),m=s.reduce((r,o)=>r+(o.skippedFileCount||0),0),a=["","\u2550\u2550 Summary \u2550\u2550",[`services ${String(f.length)}/${String(s.length)} passed`,`suites ${String(y)}/${String(C)} passed`,k>0?`files ${String(D)}/${String(k)} passed`:null,F>0?`suites ${String(F)} skipped`:null,m>0?`files ${String(m)} skipped`:null,d.length>0?`${String(d.length)} skipped`:null,`duration ${formatDuration(t)}`].filter(Boolean).join(" \xB7 ")];for(const r of e){const o=N(r)?"SKIP":r.failed?"FAIL":r.infraFailed?"INFRA":"PASS",b=r.skipped?"no matching suites":I(r);if(a.push(`${o.padEnd(4)} ${r.name.padEnd(P(e))} ${b} \xB7 ${formatDuration(r.durationMs)}`),!(!r.failed&&!r.infraFailed)){for(const l of r.suites.filter($=>$.failed)){const $=l.failedFiles.length>0?` (${l.failedFiles.join(", ")})`:"";a.push(` - ${l.testType}:${l.name}${$} \xB7 ${formatDuration(l.durationMs)}`),l.error&&a.push(` ${l.error}`)}for(const l of r.errors)a.push(` - worker error: ${l}`)}}return i==="failed"||i==="interrupted"||c.length>0||u.length>0?(a.push("",c.length===0&&u.length===0?"Result: FAILED (run gate)":`Result: FAILED (${x({failedServices:c.length,infraFailedServices:u.length,totalServices:n})})`),a):(a.push("","Result: PASSED"),a)}export function buildFailurePresentation(e){const t=L(e.failureDetails||[]),i=t[0]||null,n=t.map(u=>p((u.message||u.title).trim())),s=[],d=w(i);d&&s.push(d);const c=B(i);c&&s.push(c);for(const u of t.slice(1)){const f=h(u.message||u.title,220);f&&!s.includes(f)&&s.push(f)}return{primary:h(A(e,{error:e.suiteError||null},i,n),240),details:s}}function M(e){const t=e.filter(i=>!i.skipped);return{totalServices:e.length,failedServices:t.filter(i=>i.failed).length,infraFailedServices:t.filter(i=>i.infraFailed).length,blockedByRuntimeServices:t.filter(i=>i.blockedByRuntime).length,totalFiles:t.reduce((i,n)=>i+(n.totalFileCount||0),0),passedFiles:t.reduce((i,n)=>i+(n.passedFileCount||0),0),failedFiles:t.reduce((i,n)=>i+(n.failedFileCount||0),0),skippedFiles:t.reduce((i,n)=>i+(n.skippedFileCount||0),0),notRunFiles:t.reduce((i,n)=>i+(n.notRunFileCount||0),0)}}function x(e){const t=[`${String(e.failedServices)}/${String(e.totalServices)} services failed`];return(e.infraFailedServices||0)>0&&t.push(`${String(e.infraFailedServices)} infra-blocked`),t.join(", ")}function A(e,t,i,n){if(i?.message)return p(i.message.trim());const s=p(e.error||"");return s&&!z(s)?s:n.length>0?n[0]:s||p(t.error||"Failed")}function L(e){return[...e].sort((t,i)=>v(t)-v(i)||(t.key||"").localeCompare(i.key||""))}function v(e){return e.kind==="http-assertion"?1:e.request&&e.response?2:e.location||e.stack?3:e.message?4:5}function w(e){const t=g(e?.response,"bodyPreview");return t?`response: ${h(t,220)}`:null}function B(e){const t=e?.request,i=g(t,"method"),n=g(t,"path");if(!i||!n)return null;const s=g(t,"requestId");return s?`logs: requestId=${s}`:`request: ${i} ${n}`}function z(e){return/k6 thresholds failed:/.test(e)}function h(e,t=180){return e.replace(/\s+/g," ").trim().slice(0,t)}function j(e){return e.reduce((t,i)=>t+i.errors.length,0)}function S(e,t,i){return e===1?t:i}function N(e){return e.skipped?!0:!e.failed&&(e.skippedSuiteCount||0)>0&&(e.skippedSuiteCount||0)===e.suiteCount&&(e.notRunFileCount||0)===0}function g(e,t){if(!q(e))return null;const i=e[t];return typeof i=="string"&&i.length>0?i:null}
1
+ import{sanitizeErrorMessage as c}from"../../../kernel/error-serialization.js";export function formatDuration(e){const t=Math.max(0,Math.round(e/1e3)),i=Math.floor(t/60),r=t%60;return i===0?`${String(r)}s`:`${String(i)}m ${String(r).padStart(2,"0")}s`}function x(e){const t=e.skippedSuiteCount||0,i=e.completedSuiteCount-e.failedSuiteCount-t,r=e.suiteCount-e.completedSuiteCount;let s=`${String(i)}/${String(e.suiteCount)} suites passed`;return(e.totalFileCount||0)>0&&(s+=`, ${String(e.passedFileCount)}/${String(e.totalFileCount)} files passed`),t>0?s+=`, ${String(t)} ${f(t,"suite","suites")} skipped`:(e.skippedFileCount||0)>0&&(s+=`, ${String(e.skippedFileCount)} ${f(e.skippedFileCount,"file","files")} skipped`),r>0?s+=`, ${String(r)} ${f(r,"suite","suites")} not run`:(e.notRunFileCount||0)>0&&(s+=`, ${String(e.notRunFileCount)} ${f(e.notRunFileCount,"file","files")} not run`),s}function A(e){return e.reduce((t,i)=>Math.max(t,i.name.length),4)}export function buildRunSummaryData(e,t,i=null){const r=M(e),s=L(e);return{result:i==="failed"||i==="interrupted"||r.failedServices>0||r.infraFailedServices>0?"FAILED":"PASSED",totalServices:r.totalServices,failedServices:r.failedServices,infraFailedServices:r.infraFailedServices,blockedByRuntimeServices:r.blockedByRuntimeServices,passed:r.passedFiles,failed:r.failedFiles,skipped:r.skippedFiles,notRun:r.notRunFiles,files:r.totalFiles,duration:formatDuration(t),serviceErrors:s}}export function buildDebugRunSummaryLines(e,t,i=null){const r=e.length,s=e.filter(n=>!n.skipped),u=e.filter(n=>n.skipped),d=s.filter(n=>n.failed),p=s.filter(n=>n.infraFailed),m=s.filter(n=>!n.failed&&!n.infraFailed),C=s.reduce((n,o)=>n+o.suiteCount,0),h=s.reduce((n,o)=>n+o.completedSuiteCount,0),S=s.reduce((n,o)=>n+(o.skippedSuiteCount||0),0),R=s.reduce((n,o)=>n+o.failedSuiteCount,0),E=h-R-S,g=s.reduce((n,o)=>n+(o.totalFileCount||0),0),D=s.reduce((n,o)=>n+(o.passedFileCount||0),0),$=s.reduce((n,o)=>n+(o.skippedFileCount||0),0),a=["","\u2550\u2550 Summary \u2550\u2550",[`groups ${String(m.length)}/${String(s.length)} passed`,`suites ${String(E)}/${String(C)} passed`,g>0?`files ${String(D)}/${String(g)} passed`:null,S>0?`suites ${String(S)} skipped`:null,$>0?`files ${String($)} skipped`:null,u.length>0?`${String(u.length)} skipped`:null,`duration ${formatDuration(t)}`].filter(Boolean).join(" \xB7 ")];for(const n of e){const o=j(n)?"SKIP":n.failed?"FAIL":n.infraFailed?"INFRA":"PASS",b=n.skipped?"no matching suites":x(n);if(a.push(`${o.padEnd(4)} ${n.name.padEnd(A(e))} ${b} \xB7 ${formatDuration(n.durationMs)}`),!(!n.failed&&!n.infraFailed)){for(const l of n.suites.filter(F=>F.failed)){const F=l.failedFiles.length>0?` (${l.failedFiles.join(", ")})`:"",y=[l.testType,l.name].filter(Boolean).join(":");a.push(` - ${y}${F} \xB7 ${formatDuration(l.durationMs)}`),l.error&&a.push(` ${l.error}`)}for(const l of n.errors)a.push(` - error: ${l}`)}}return i==="failed"||i==="interrupted"||d.length>0||p.length>0?(a.push("",d.length===0&&p.length===0?"Result: FAILED (run gate)":`Result: FAILED (${I({failedServices:d.length,infraFailedServices:p.length,totalServices:r})})`),a):(a.push("","Result: PASSED"),a)}export function buildFailurePresentation(e){const t=P(e.failureDetails||[]),i=t[0]||null,r=t.map(u=>c((u.message||u.title).trim())),s=[];for(const u of t.slice(1)){const d=v(u.message||u.title,220);d&&!s.includes(d)&&s.push(d)}return{primary:v(B(e,{error:e.suiteError||null},i,r),240),details:s}}function M(e){const t=e.filter(i=>!i.skipped);return{totalServices:e.length,failedServices:t.filter(i=>i.failed).length,infraFailedServices:t.filter(i=>i.infraFailed).length,blockedByRuntimeServices:t.filter(i=>i.blockedByRuntime).length,totalFiles:t.reduce((i,r)=>i+(r.totalFileCount||0),0),passedFiles:t.reduce((i,r)=>i+(r.passedFileCount||0),0),failedFiles:t.reduce((i,r)=>i+(r.failedFileCount||0),0),skippedFiles:t.reduce((i,r)=>i+(r.skippedFileCount||0),0),notRunFiles:t.reduce((i,r)=>i+(r.notRunFileCount||0),0)}}function I(e){const t=[`${String(e.failedServices)}/${String(e.totalServices)} groups failed`];return(e.infraFailedServices||0)>0&&t.push(`${String(e.infraFailedServices)} infra-blocked`),t.join(", ")}function B(e,t,i,r){if(i?.message)return c(i.message.trim());const s=c(e.error||"");return s||(r.length>0?r[0]:s||c(t.error||"Failed"))}function P(e){return[...e].sort((t,i)=>k(t)-k(i)||(t.key||"").localeCompare(i.key||""))}function k(e){return e.location||e.stack?3:e.message?4:5}function v(e,t=180){return e.replace(/\s+/g," ").trim().slice(0,t)}function L(e){return e.reduce((t,i)=>t+i.errors.length,0)}function f(e,t,i){return e===1?t:i}function j(e){return e.skipped?!0:!e.failed&&(e.skippedSuiteCount||0)>0&&(e.skippedSuiteCount||0)===e.suiteCount&&(e.notRunFileCount||0)===0}
@@ -1 +1 @@
1
- import{describeLiveArtifactState as c,latestOperation as l}from"../../../app/status/runs.js";import{formatOperationSummary as m}from"../../../domain/operation-display.js";import{asUnknownRecord as a,displayString as p}from"../../../kernel/unknown-values.js";export function renderRunStatusLines(s){const t=["Testkit Run Status",` product: ${s.productDir}`],r=s.runs??[];if(r.length===0)t.push(" local runs: none");else{t.push(" local runs:");for(const n of r)t.push(` ${String(n.runId)}: ${n.active?"active":n.terminal?"terminal":"stale"} pid=${String(n.pid)} status=${n.status||"unknown"}`)}const o=a(s.live),i=o?a(o.operation):null,e=o?a(o.timings):null,u=l(i?[i]:e?.operations??[]);if(o){const n=c({...s,live:o});t.push(" live artifact:"),t.push(` run: ${n.runId} status=${n.status}`),n.reason&&t.push(` reason: ${n.reason}`),u&&t.push(` operation: ${formatStatusOperation(u)}`)}return t}export function formatStatusOperation(s={},{nameSeparator:t=""}={}){const r=a(s)??{},o=m(r),i=p(r.name,"operation"),e=p(r.status,"unknown");return`${i}${t} ${e}${o?` - ${o}`:""}`}
1
+ import{describeLiveArtifactState as c,latestOperation as l}from"../../../app/status/runs.js";import{formatOperationSummary as m}from"../../../domain/operation-display.js";import{asUnknownRecord as a,displayString as u}from"../../../kernel/unknown-values.js";export function renderRunStatusLines(s){const t=["Testkit Run Status",` product: ${s.productDir}`],r=s.runs??[];if(r.length===0)t.push(" local runs: none");else{t.push(" local runs:");for(const n of r)t.push(` ${String(n.runId)}: ${n.active?"active":n.terminal?"terminal":"stale"} pid=${String(n.pid)} status=${n.status||"unknown"}`)}const o=a(s.live),i=o?a(o.operation):null,p=o?a(o.timings):null,e=l(i?[i]:p?.operations??[]);if(o){const n=c({...s,live:o});t.push(" live artifact:"),t.push(` run: ${n.runId} status=${n.status}`),n.reason&&t.push(` reason: ${n.reason}`),e&&t.push(` operation: ${formatStatusOperation(e)}`)}return t}export function formatStatusOperation(s={}){const t=a(s)??{},r=m(t),o=u(t.name,"operation"),i=u(t.status,"unknown");return`${o} ${i}${r?` - ${r}`:""}`}
@@ -1,23 +1,25 @@
1
- import k from"node:path";import{buildDebugRunSummaryLines as L,buildRunSummaryData as I,formatDuration as m}from"./formatting.js";import{formatOperationSummary as F,isNeutralOperationStatus as T,isSuccessfulOperationStatus as M,operationStatusLabel as O}from"../../../domain/operation-display.js";import{boldRed as p,colorSectionLine as P,dim as c,statusLabel as o}from"../../terminal/colors.js";import{getTerminalWidth as A}from"../../terminal/layout.js";import{renderFailureBlock as D}from"./failure.js";export function createRunTextListener(t={}){const{outputMode:s="compact",stdout:e=process.stdout}=t;let u=0,n=0;return r=>{switch(r.type){case"run.total_files":n=r.total;return;case"run.debug":e.write(`${r.line}
2
- `);return;case"run.phase_started":f(s,e,r.label);return;case"run.toolchain_resolved":$(s,e,r.service,r.runtimeLabel,r.summary);return;case"run.setup_finished":g(s,e,r.operation);return;case"run.operation_started":case"run.operation_progress":if(!h(s,r.operation))return;e.write(`${o("RUN")} INFRA ${w(r.operation)}
3
- `);return;case"run.operation_finished":{if(!h(s,r.operation,{finished:!0}))return;const i=O(r.operation.status);e.write(`${o(i)} INFRA ${w(r.operation)}
4
- `);return}case"run.local_service_starting":if(s!=="debug")return;e.write(`Starting ${r.runtimeLabel}:${r.service}: ${r.command}
5
- `);return;case"run.service_skipped":e.write(`${o("SKIP")} ${r.service} ${r.reason}
6
- `);return;case"run.task_planned_skip":e.write(`${o("SKIP")} ${r.service} ${r.testType} ${S(r.file)} ${c("0s")} ${l(r.reason||"skipped")}
7
- `);return;case"run.task_started":if(s!=="debug")return;e.write(`${o("RUN")} ${r.targetName} ${r.testType} ${r.file}
8
- `);return;case"run.task_finished":{u+=1;const i=r.outcome,a=i.status==="not_run"?"NOT RUN":i.status==="skipped"||i.status==="cancelled"||i.status==="interrupted"?"SKIP":i.status==="failed"?"FAIL":"PASS",d=m(i.durationMs||0),y=i.status==="not_run"||i.status==="cancelled"||i.status==="interrupted"?` ${c(l(i.reason||"not run"))}`:"",_=s==="compact"&&n>0?`${c(`[${String(u)}/${String(n)}]`)} `:"";if(e.write(`${_}${o(a)} ${r.service} ${r.testType} ${S(r.file)} ${c(d)}${y}
9
- `),a==="FAIL"){const R=D({engineId:r.engineId,file:r.file,profileId:r.profileId,serviceName:r.service,testType:r.testType},i,{width:A(e,100)});for(const N of R)e.write(`${N}
10
- `)}return}case"run.runtime_error":e.write(`${o("FAIL")} ${r.service} runtime error
11
- `),e.write(` ${p(l(r.message||"runtime error"))}
12
- `);return;case"run.summary":U(s,e,r.results,r.durationMs,r.runStatus);return;case"run.service_plans":case"run.warning":return}}}export function createTextStepProgressReporter(t={}){const{debug:s=!1,stdout:e=process.stdout}=t,u=s?"debug":"compact";return{outputMode:u,phaseStarted(n){f(u,e,n)},setupOperationFinished(n){n&&g(u,e,n)},toolchainResolved(n,r){$(u,e,n.name,n.runtimeLabel||n.name,r.summary)},writeDebugLine(n=""){e.write(`${n}
13
- `)}}}function f(t,s,e){t==="debug"&&s.write(`
1
+ import k from"node:path";import{buildDebugRunSummaryLines as I,buildRunSummaryData as F,formatDuration as p}from"./formatting.js";import{formatOperationSummary as T,isNeutralOperationStatus as A,isSuccessfulOperationStatus as M,operationStatusLabel as O}from"../../../domain/operation-display.js";import{boldRed as m,colorSectionLine as P,dim as c,statusLabel as a}from"../../terminal/colors.js";import{getTerminalWidth as D}from"../../terminal/layout.js";import{renderFailureBlock as U}from"./failure.js";export function createRunTextListener(t={}){const{outputMode:n="compact",stdout:e=process.stdout}=t;let u=0,s=0;return r=>{switch(r.type){case"run.total_files":s=r.total;return;case"run.debug":e.write(`${r.line}
2
+ `);return;case"run.phase_started":$(n,e,r.label);return;case"run.toolchain_resolved":g(n,e,r.service,r.runtimeLabel,r.summary);return;case"run.setup_finished":S(n,e,r.operation);return;case"run.operation_started":case"run.operation_progress":if(!w(n,r.operation))return;e.write(`${a("RUN")} INFRA ${b(r.operation)}
3
+ `);return;case"run.operation_finished":{if(!w(n,r.operation,{finished:!0}))return;const i=O(r.operation.status);e.write(`${a(i)} INFRA ${b(r.operation)}
4
+ `);return}case"run.local_service_starting":if(n!=="debug")return;e.write(`Starting ${r.runtimeLabel}:${r.service}: ${r.command}
5
+ `);return;case"run.group_skipped":e.write(`${a("SKIP")} ${r.group} ${r.reason}
6
+ `);return;case"run.task_planned_skip":e.write(`${a("SKIP")} ${f(r.group,r.testType,h(r.file))} ${c("0s")} ${l(r.reason||"skipped")}
7
+ `);return;case"run.task_started":if(n!=="debug")return;e.write(`${a("RUN")} ${f(r.targetName,r.testType,r.file)}
8
+ `);return;case"run.task_finished":{u+=1;const i=r.outcome,o=i.status==="not_run"?"NOT RUN":i.status==="skipped"||i.status==="cancelled"||i.status==="interrupted"?"SKIP":i.status==="failed"?"FAIL":"PASS",d=p(i.durationMs||0),y=i.status==="not_run"||i.status==="cancelled"||i.status==="interrupted"?` ${c(l(i.reason||"not run"))}`:"",L=n==="compact"&&s>0?`${c(`[${String(u)}/${String(s)}]`)} `:"";if(e.write(`${L}${a(o)} ${f(r.group,r.testType,h(r.file))} ${c(d)}${y}
9
+ `),o==="FAIL"){const N=U({engineId:r.engineId,file:r.file,profileId:r.profileId,serviceName:r.group,testType:r.testType},i,{width:D(e,100)});for(const R of N)e.write(`${R}
10
+ `)}return}case"run.error":e.write(`${a("FAIL")} run error
11
+ `),e.write(` ${m(l(r.message))}
12
+ `);return;case"run.runtime_error":e.write(`${a("FAIL")} ${r.group} runtime error
13
+ `),e.write(` ${m(l(r.message||"runtime error"))}
14
+ `);return;case"run.summary":x(n,e,r.results,r.durationMs,r.runStatus);return;case"run.group_plans":case"run.warning":return}}}export function createTextStepProgressReporter(t={}){const{debug:n=!1,stdout:e=process.stdout}=t,u=n?"debug":"compact";return{outputMode:u,phaseStarted(s){$(u,e,s)},setupOperationFinished(s){s&&S(u,e,s)},toolchainResolved(s,r){g(u,e,s.serviceName,s.runtimeLabel,r)},writeDebugLine(s=""){e.write(`${s}
15
+ `)}}}function $(t,n,e){t==="debug"&&n.write(`
14
16
  \u2500\u2500 ${e} \u2500\u2500
15
- `)}function $(t,s,e,u,n){t==="debug"&&s.write(`[testkit] ${u}:${e} toolchain ${n}
16
- `)}function g(t,s,e){if(e.status==="cached")return;const u=m(e.durationMs||0);if(e.status==="failed"){const n=l(e.error||e.summary||e.stage);s.write(`${o("FAIL")} SETUP ${e.serviceName} ${e.stage} ${c(u)} ${p(n)}
17
- `);return}if(t==="compact"&&x(e)&&(e.durationMs||0)>=5e3){const n=l(e.summary||e.stage);s.write(`${o("RUN")} SETUP ${e.serviceName} ${n} ${c(u)}
18
- `)}}function U(t,s,e,u,n){if(t==="debug"){const a=L(e,u,n);s.write(`
19
- `);for(const d of a)s.write(`${P(d)}
20
- `);return}const r=I(e,u,n),i=[["Result",r.result],["Passed",String(r.passed)],["Failed",String(r.failed)],["Skipped",String(r.skipped)],["Not run",String(r.notRun)],["Files",String(r.files)]];r.serviceErrors>0&&i.push(["Runtime errors",String(r.serviceErrors)]),i.push(["Duration",r.duration]),s.write(`
21
- `),s.write(`Summary
22
- `);for(const[a,d]of i)s.write(`${a}: ${d}
23
- `)}function l(t){return(t??"").replace(/\s+/g," ").trim().slice(0,180)}function S(t){return t.split(k.sep).join("/")}function x(t){return t.kind==="database-template"||t.kind==="runtime-prepare"}function h(t,s,{finished:e=!1}={}){return t==="debug"?!0:K(s)?e?M(s.status)?(s.durationMs||0)>=5e3:!T(s.status):!0:!1}function K(t){return t.kind==="runtime"}function w(t){const s=t.scope??{},e=E(t.name||t.kind||"operation"),u=b(s.serviceName),n=b(s.graphKey),r=[u?`service=${u}`:"",n?`graph=${n}`:""].filter(Boolean).join(" "),i=l(F(t)),a=t.durationMs==null?j(t.startedAt):m(t.durationMs||0);return[e,r?c(r):"",i?l(i):"",a?c(a):""].filter(Boolean).join(" ")}function b(t){return typeof t=="string"?t:""}function E(t){return t.replace(/^testkit\./,"").replaceAll("_","-")}function j(t){const s=Date.parse(t||"");return Number.isFinite(s)?m(Math.max(0,Date.now()-s)):""}
17
+ `)}function g(t,n,e,u,s){t==="debug"&&n.write(`[testkit] ${u}:${e} toolchain ${s}
18
+ `)}function S(t,n,e){if(e.status==="cached")return;const u=p(e.durationMs||0);if(e.status==="failed"){const s=l(e.error||e.summary||e.stage);n.write(`${a("FAIL")} SETUP ${e.serviceName} ${e.stage} ${c(u)} ${m(s)}
19
+ `);return}if(t==="compact"&&K(e)&&(e.durationMs||0)>=5e3){const s=l(e.summary||e.stage);n.write(`${a("RUN")} SETUP ${e.serviceName} ${s} ${c(u)}
20
+ `)}}function x(t,n,e,u,s){if(t==="debug"){const o=I(e,u,s);n.write(`
21
+ `);for(const d of o)n.write(`${P(d)}
22
+ `);return}const r=F(e,u,s),i=[["Result",r.result],["Passed",String(r.passed)],["Failed",String(r.failed)],["Skipped",String(r.skipped)],["Not run",String(r.notRun)],["Files",String(r.files)]];r.serviceErrors>0&&i.push(["Runtime errors",String(r.serviceErrors)]),i.push(["Duration",r.duration]),n.write(`
23
+ `),n.write(`Summary
24
+ `);for(const[o,d]of i)n.write(`${o}: ${d}
25
+ `)}function l(t){return(t??"").replace(/\s+/g," ").trim().slice(0,180)}function h(t){return t.split(k.sep).join("/")}function K(t){return t.kind==="database-template"||t.kind==="runtime-prepare"}function w(t,n,{finished:e=!1}={}){return t==="debug"?!0:E(n)?e?M(n.status)?(n.durationMs||0)>=5e3:!A(n.status):!0:!1}function E(t){return t.kind==="runtime"}function b(t){const n=t.scope??{},e=j(t.name||t.kind||"operation"),u=_(n.serviceName),s=_(n.graphKey),r=[u?`service=${u}`:"",s?`graph=${s}`:""].filter(Boolean).join(" "),i=l(T(t)),o=t.durationMs==null?B(t.startedAt):p(t.durationMs||0);return[e,r?c(r):"",i?l(i):"",o?c(o):""].filter(Boolean).join(" ")}function _(t){return typeof t=="string"?t:""}function j(t){return t.replace(/^testkit\./,"").replaceAll("_","-")}function B(t){const n=Date.parse(t||"");return Number.isFinite(n)?p(Math.max(0,Date.now()-n)):""}function f(t,n,e){return n===void 0?`${t} ${e}`:`${t} ${n} ${e}`}
@@ -1 +1 @@
1
- import{createColors as o}from"picocolors";const e=o(!!(process.stdout.isTTY||process.env.FORCE_COLOR));export function statusLabel(r){return r==="PASS"?e.green("PASS"):r==="FAIL"?e.red("FAIL"):r==="SKIP"?e.yellow("SKIP"):r==="NOT RUN"?e.yellow("NOT RUN"):r==="RUN"?e.cyan("RUN"):r}export function dim(r){return e.dim(r)}export function bold(r){return e.bold(r)}export function boldRed(r){return e.bold(e.red(r))}export function muted(r){return e.dim(r)}export function colorHeading(r){return e.bold(r)}export function colorService(r){return e.cyan(e.bold(r))}export function colorTypeBadge(r){return r==="INT"?e.blue(r):r==="E2E"?e.magenta(r):r==="DAL"?e.green(r):r==="LOAD"?e.cyan(r):r==="PW"?e.blue(e.bold(r)):r}export function colorDiagnosticSeverity(r){return r==="error"?e.red(e.bold("ERR")):r==="warning"?e.yellow(e.bold("WARN")):e.dim("INFO")}export function colorSectionLine(r){return r==="Case store issues:"||r==="Diagnosis:"?e.bold(r):/^Summary: /.test(r)?r.replace("Summary:",e.bold("Summary:")):/^Result: PASSED\b/.test(r)?r.replace("PASSED",e.green("PASSED")):/^Result: FAILED\b/.test(r)?r.replace("FAILED",e.red("FAILED")):r}
1
+ import t from"node:tty";import{createColors as n}from"picocolors";const{FORCE_COLOR:o,NO_COLOR:u}=process.env,e=n(o===void 0?!u&&t.isatty(1):!["0","false"].includes(o));export function statusLabel(r){return r==="PASS"?e.green("PASS"):r==="FAIL"?e.red("FAIL"):r==="SKIP"?e.yellow("SKIP"):r==="NOT RUN"?e.yellow("NOT RUN"):r==="RUN"?e.cyan("RUN"):r}export function dim(r){return e.dim(r)}export function bold(r){return e.bold(r)}export function boldRed(r){return e.bold(e.red(r))}export function colorService(r){return e.cyan(e.bold(r))}export function colorTypeBadge(r){return r==="PW"?e.blue(e.bold(r)):r}export function colorDiagnosticSeverity(r){return r==="error"?e.red(e.bold("ERR")):r==="warning"?e.yellow(e.bold("WARN")):e.dim("INFO")}export function colorSectionLine(r){return r==="Case store issues:"||r==="Diagnosis:"?e.bold(r):/^Summary: /.test(r)?r.replace("Summary:",e.bold("Summary:")):/^Result: PASSED\b/.test(r)?r.replace("PASSED",e.green("PASSED")):/^Result: FAILED\b/.test(r)?r.replace("FAILED",e.red("FAILED")):r}
@@ -1,2 +1,2 @@
1
- import u from"string-width";import s from"wrap-ansi";export function getTerminalWidth(r=process.stdout,t=100){const n=Number(r.columns);return Number.isFinite(n)&&n>0?n:t}export function measureWidth(r){return u(r)}export function wrapText(r,t){return t<=0?[r]:s(r,t,{hard:!0,trim:!1,wordWrap:!0}).split(`
2
- `)}export function renderIndentedBlock(r,{width:t,indent:n=" "}){const e=measureWidth(n),o=Math.max(12,t-e);return wrapText(r,o).map(i=>`${n}${i}`)}
1
+ import u from"string-width";import s from"wrap-ansi";export function getTerminalWidth(r=process.stdout,t=100){const n=Number(r.columns);return Number.isFinite(n)&&n>0?n:t}export function wrapText(r,t){return t<=0?[r]:s(r,t,{hard:!0,trim:!1,wordWrap:!0}).split(`
2
+ `)}export function renderIndentedBlock(r,{width:t,indent:n=" "}){const e=u(n),o=Math.max(12,t-e);return wrapText(r,o).map(i=>`${n}${i}`)}
@@ -0,0 +1 @@
1
+ export const DATABASE_FIXTURE_DISCOVERY=Object.freeze({roots:Object.freeze([".testkit-fixture"])});
@@ -1 +1 @@
1
- export function createBodyMethods(c){return{post:(r,t,...e)=>c("POST",r,t,...e),put:(r,t,...e)=>c("PUT",r,t,...e),patch:(r,t,...e)=>c("PATCH",r,t,...e)}}export function createHttpMethods(c,r){return{...createBodyMethods(c),get:(t,...e)=>c("GET",t,r,...e),delete:(t,e=r,...p)=>c("DELETE",t,e,...p)}}
1
+ export function createHttpMethods(T){return{post:(t,e,...p)=>T("POST",t,e,...p),put:(t,e,...p)=>T("PUT",t,e,...p),patch:(t,e,...p)=>T("PATCH",t,e,...p),get:(t,...e)=>T("GET",t,void 0,...e),delete:(t,e,...p)=>T("DELETE",t,e,...p)}}
@@ -1 +1 @@
1
- import{clearRepoConfig as I,getRepoConfig as O,registerRepoConfig as $}from"./runtime.js";import{normalizeDatabaseEnvToken as b,normalizeNextPresetEnv as N,normalizePresetEnv as A}from"./preset-env.js";const P=String;export function defineConfig(e){return e||{}}function F(e={}){return{...e,...e.maxConnections?{maxConnections:e.maxConnections}:{},...e.reservedConnections?{reservedConnections:e.reservedConnections}:{},...e.runtimeConnections?{runtimeConnections:e.runtimeConnections}:{}}}function v(e,n="baseUrl"){const t=b(e,"service name",!1);return`{${b(n,"endpoint field",!1)}:${t}}`}function R(e={}){const n=E(e.migrate),t=E(e.seed),r=E(e.verify);return{inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0,migrate:n,seed:t,verify:r}}function z(e,n={}){return{kind:"command",run:e,...U(n)}}function _(e,n={}){return{kind:"sql-file",path:e,...U(n)}}function u(e,n={}){return{kind:"module",target:e,...U(n)}}function U(e={}){return{...e.cwd!==void 0?{cwd:e.cwd}:{},...e.inputs!==void 0?{inputs:[...e.inputs]}:{},...e.args!==void 0?{args:e.args}:{}}}function q(e,n={}){if(typeof e!="string"||e.trim().length===0)throw new Error("database.schema.fromEnv(...) requires a non-empty env var name");return{kind:"env",env:e.trim(),...n}}function f(e){return`@gfdelarue/testkit/config/database-steps#${e}`}function M(e={}){return u(f("verifySeed"),{args:e})}function V(e={}){return u(f("verifyRows"),{args:e})}function X(e={}){return u(f("runSql"),{args:e})}function G(e={}){return u(f("seedRows"),{args:e})}function H(e={}){return u(f("materializePostgresBinding"),{args:e})}function L(e={}){return u(f("updateRows"),{args:e})}function W(){return{kind:"now"}}function J(e){return{kind:"env",name:b(e,"database.values.env(...) name",!1)}}function K(e){return{kind:"json",value:e}}function Q(e){return{kind:"postgres-connection-from-env",prefix:b(e,"database.values.postgresConnectionFromEnv(...) prefix",!1)}}function Y(e={}){const{discovery:n,envFiles:t,template:r,inputs:s,migrate:o,seed:a,verify:d,...c}=e,i=r||D(e)?R({inputs:s,migrate:o,seed:a,verify:d,...r||{}}):void 0;return{discovery:n||{roots:[".testkit-fixture"]},envFiles:t,local:!1,database:F(i?{...c,template:i}:c)}}function D(e={}){return["inputs","migrate","seed","verify"].some(n=>Object.prototype.hasOwnProperty.call(e,n))}function B(e={}){return{...e}}function Z(e={}){return{kind:"tsc",cwd:e.cwd,entry:e.entry||"src/index.ts",tsconfig:e.tsconfig||"tsconfig.json",outDir:e.outDir||"dist",inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0}}function ee(e={}){return{kind:"next",cwd:e.cwd,distDir:e.distDir||"dist",tsconfig:e.tsconfig||"tsconfig.json",inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0}}function ne(e={}){const{baseUrl:n,build:t,buildInputs:r,cwd:s=".",entry:o="src/index.ts",env:a,envFiles:d,outDir:c="dist",port:i,readyPath:g="/health",readyTimeoutMs:S,shutdownTimeoutMs:p,readyUrl:h,runtime:m,start:C,toolchain:k,tsconfig:T="tsconfig.json",...l}=e,y=A(a),x=n||"http://127.0.0.1:{port}",w=t===void 0?Z({cwd:s,entry:o,tsconfig:T,outDir:c,inputs:r}):t,j=C||re(w,o);return{...l,envFiles:d,runtime:{...m||{},build:w,toolchain:k??m?.toolchain},local:{cwd:s,start:j,...i===void 0?{}:{port:i},baseUrl:x,readyUrl:h??`${x}${g}`,readyTimeoutMs:S,...p===void 0?{}:{shutdownTimeoutMs:p},env:y}}}function te(e={}){const{api:n,baseUrl:t,build:r,buildInputs:s,cwd:o=".",dependsOn:a,env:d,envFiles:c,mode:i="dev",port:g,readyTimeoutMs:S,shutdownTimeoutMs:p,readyUrl:h,runtime:m,start:C,toolchain:k,...T}=e,l={...N({api:n}),...A(d)},y=t||"http://127.0.0.1:{port}",x=r===void 0?i==="start"?ee({cwd:o,inputs:s}):null:r,w=C||(i==="start"?"{bin:next} start --port {port}":"{bin:next} dev -p {port}");return{...T,envFiles:c,dependsOn:Array.isArray(a)?[...a]:a,runtime:{...m||{},build:x,toolchain:k??m?.toolchain},local:{cwd:o,start:w,...g===void 0?{}:{port:g},baseUrl:y,readyUrl:h??y,readyTimeoutMs:S,...p===void 0?{}:{shutdownTimeoutMs:p},env:i==="start"?{NEXT_DIST_DIR:l.NEXT_DIST_DIR||".next-testkit/{runtimeId}/dist",NEXT_TSCONFIG_PATH:l.NEXT_TSCONFIG_PATH||".next-testkit/{runtimeId}/tsconfig.json",...l}:l}}}export const app={node:ne,next:te},database={schema:{fromEnv:q},steps:{materializePostgresBinding:H,runSql:X,seedRows:G,updateRows:L,verifyRows:V,verifySeed:M},values:{env:J,json:K,now:W,postgresConnectionFromEnv:Q},postgres(e={}){const{template:n,sourceSchema:t,inputs:r,migrate:s,seed:o,verify:a,...d}=e,c=t===void 0?d:{...d,sourceSchema:t},i=n||D(e)?R({inputs:r,migrate:s,seed:o,verify:a,...n||{}}):void 0;return F(i?{...c,template:i}:c)},fixture:Y},endpoint={baseUrl(e){return v(e,"baseUrl")},readyUrl(e){return v(e,"readyUrl")},publicBaseUrl(e){return v(e,"publicBaseUrl")},privateBaseUrl(e){return v(e,"privateBaseUrl")},serviceContextUrl(e){return v(e,"serviceContextUrl")}},step={command:z,module:u,sqlFile:_},presets={nodeNext(e={}){const n=e.workers;if(e.taskConcurrency!=null&&n!=null&&e.taskConcurrency!==n)throw new Error("presets.nodeNext taskConcurrency and workers must match when both are provided.");return{execution:{taskConcurrency:e.taskConcurrency??n??1,fileTimeoutSeconds:e.fileTimeoutSeconds??120},toolchains:{node:B({install:e.install??"download",...e.node?{node:e.node}:{},...e.npm?{npm:e.npm}:{}})}}}},toolchain={node:B};export{I as clearRepoConfig,O as getRepoConfig,$ as registerRepoConfig};function re(e,n){return e?.kind==="tsc"?`node {prepareDir}/${ie(n||e.entry||"src/index.ts",e.outDir||"dist")}`:`{bin:tsx} ${n||"src/index.ts"}`}function E(e){return e==null?[]:(Array.isArray(e)?e:[e]).map(t=>typeof t=="string"?z(t):t)}function ie(e,n){const r=P(e||"src/index.ts").replaceAll("\\","/").replace(/\.[cm]?[jt]sx?$/i,".js"),s=r.startsWith("src/")?r.slice(4):r;return`${n}/${s}`.replace(/\/+/g,"/")}
1
+ import{normalizeDatabaseEnvToken as S,normalizeNextPresetEnv as O,normalizePresetEnv as A}from"./preset-env.js";import{DATABASE_FIXTURE_DISCOVERY as j}from"./database-fixture-discovery.js";const _=String;export function defineConfig(e){return e||{}}function D(e={}){return{...e,...e.maxConnections?{maxConnections:e.maxConnections}:{},...e.reservedConnections?{reservedConnections:e.reservedConnections}:{},...e.runtimeConnections?{runtimeConnections:e.runtimeConnections}:{}}}function v(e,n="baseUrl"){const t=S(e,"service name",!1);return`{${S(n,"endpoint field",!1)}:${t}}`}function F(e={}){const n=E(e.migrate),t=E(e.seed),r=E(e.verify);return{inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0,migrate:n,seed:t,verify:r}}function z(e,n={}){return{kind:"command",run:e,...k(n)}}function $(e,n={}){return{kind:"sql-file",path:e,...k(n)}}function u(e,n={}){return{kind:"module",target:e,...k(n)}}function k(e={}){return{...e.cwd!==void 0?{cwd:e.cwd}:{},...e.inputs!==void 0?{inputs:[...e.inputs]}:{},...e.args!==void 0?{args:e.args}:{}}}function N(e,n={}){if(typeof e!="string"||e.trim().length===0)throw new Error("database.schema.fromEnv(...) requires a non-empty env var name");return{kind:"env",env:e.trim(),...n}}function f(e){return`@gfdelarue/testkit/config/database-steps#${e}`}function P(e={}){return u(f("verifySeed"),{args:e})}function q(e={}){return u(f("verifyRows"),{args:e})}function V(e={}){return u(f("runSql"),{args:e})}function X(e={}){return u(f("seedRows"),{args:e})}function M(e={}){return u(f("materializePostgresBinding"),{args:e})}function G(e={}){return u(f("updateRows"),{args:e})}function H(){return{kind:"now"}}function L(e){return{kind:"env",name:S(e,"database.values.env(...) name",!1)}}function W(e){return{kind:"json",value:e}}function Y(e){return{kind:"postgres-connection-from-env",prefix:S(e,"database.values.postgresConnectionFromEnv(...) prefix",!1)}}function J(e={}){const{discovery:n,envFiles:t,template:r,inputs:s,migrate:o,seed:a,verify:d,...c}=e,i=r||R(e)?F({inputs:s,migrate:o,seed:a,verify:d,...r||{}}):void 0;return{discovery:n||{roots:[...j.roots]},envFiles:t,local:!1,database:D(i?{...c,template:i}:c)}}function R(e={}){return["inputs","migrate","seed","verify"].some(n=>Object.prototype.hasOwnProperty.call(e,n))}function B(e={}){return{...e}}function K(e={}){return{kind:"tsc",cwd:e.cwd,entry:e.entry||"src/index.ts",tsconfig:e.tsconfig||"tsconfig.json",outDir:e.outDir||"dist",inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0}}function Q(e={}){return{kind:"next",cwd:e.cwd,distDir:e.distDir||"dist",tsconfig:e.tsconfig||"tsconfig.json",inputs:Array.isArray(e.inputs)?[...e.inputs]:void 0}}function Z(e={}){const{baseUrl:n,build:t,buildInputs:r,cwd:s=".",entry:o="src/index.ts",env:a,envFiles:d,outDir:c="dist",port:i,readyPath:g="/health",readyTimeoutMs:b,shutdownTimeoutMs:p,readyUrl:h,runtime:m,start:C,toolchain:T,tsconfig:U="tsconfig.json",...l}=e,y=A(a),x=n||"http://127.0.0.1:{port}",w=t===void 0?K({cwd:s,entry:o,tsconfig:U,outDir:c,inputs:r}):t,I=C||ne(w,o);return{...l,envFiles:d,runtime:{...m||{},build:w,toolchain:T??m?.toolchain},local:{cwd:s,start:I,...i===void 0?{}:{port:i},baseUrl:x,readyUrl:h??`${x}${g}`,readyTimeoutMs:b,...p===void 0?{}:{shutdownTimeoutMs:p},env:y}}}function ee(e={}){const{api:n,baseUrl:t,build:r,buildInputs:s,cwd:o=".",dependsOn:a,env:d,envFiles:c,mode:i="dev",port:g,readyTimeoutMs:b,shutdownTimeoutMs:p,readyUrl:h,runtime:m,start:C,toolchain:T,...U}=e,l={...O({api:n}),...A(d)},y=t||"http://127.0.0.1:{port}",x=r===void 0?i==="start"?Q({cwd:o,inputs:s}):null:r,w=C||(i==="start"?"{bin:next} start --port {port}":"{bin:next} dev -p {port}");return{...U,envFiles:c,dependsOn:Array.isArray(a)?[...a]:a,runtime:{...m||{},build:x,toolchain:T??m?.toolchain},local:{cwd:o,start:w,...g===void 0?{}:{port:g},baseUrl:y,readyUrl:h??y,readyTimeoutMs:b,...p===void 0?{}:{shutdownTimeoutMs:p},env:i==="start"?{NEXT_DIST_DIR:l.NEXT_DIST_DIR||".next-testkit/{runtimeId}/dist",NEXT_TSCONFIG_PATH:l.NEXT_TSCONFIG_PATH||".next-testkit/{runtimeId}/tsconfig.json",...l}:l}}}export const app={node:Z,next:ee},database={schema:{fromEnv:N},steps:{materializePostgresBinding:M,runSql:V,seedRows:X,updateRows:G,verifyRows:q,verifySeed:P},values:{env:L,json:W,now:H,postgresConnectionFromEnv:Y},postgres(e={}){const{template:n,sourceSchema:t,inputs:r,migrate:s,seed:o,verify:a,...d}=e,c=t===void 0?d:{...d,sourceSchema:t},i=n||R(e)?F({inputs:r,migrate:s,seed:o,verify:a,...n||{}}):void 0;return D(i?{...c,template:i}:c)},fixture:J},endpoint={baseUrl(e){return v(e,"baseUrl")},readyUrl(e){return v(e,"readyUrl")},publicBaseUrl(e){return v(e,"publicBaseUrl")},privateBaseUrl(e){return v(e,"privateBaseUrl")},serviceContextUrl(e){return v(e,"serviceContextUrl")}},step={command:z,module:u,sqlFile:$},presets={nodeNext(e={}){const n=e.workers;if(e.taskConcurrency!=null&&n!=null&&e.taskConcurrency!==n)throw new Error("presets.nodeNext taskConcurrency and workers must match when both are provided.");return{execution:{taskConcurrency:e.taskConcurrency??n??1,fileTimeoutSeconds:e.fileTimeoutSeconds??120},toolchains:{node:B({install:e.install??"download",...e.node?{node:e.node}:{},...e.npm?{npm:e.npm}:{}})}}}},toolchain={node:B};function ne(e,n){return e?.kind==="tsc"?`node {prepareDir}/${te(n||e.entry||"src/index.ts",e.outDir||"dist")}`:`{bin:tsx} ${n||"src/index.ts"}`}function E(e){return e==null?[]:(Array.isArray(e)?e:[e]).map(t=>typeof t=="string"?z(t):t)}function te(e,n){const r=_(e||"src/index.ts").replaceAll("\\","/").replace(/\.[cm]?[jt]sx?$/i,".js"),s=r.startsWith("src/")?r.slice(4):r;return`${n}/${s}`.replace(/\/+/g,"/")}
@@ -1 +1 @@
1
- import m from"node:crypto";import{isUnknownRecord as c}from"../../kernel/unknown-values.js";import o from"node:fs";import e from"node:path";import{fileURLToPath as d,pathToFileURL as p}from"node:url";import{buildWithEsbuildRetry as h}from"../../toolchains/esbuild.js";const u=e.resolve(e.dirname(d(import.meta.url)),"..","..",".."),k=e.join(u,"dist","index.js"),j=e.join(u,"dist","config","authoring","index.js"),w=new Set(["/k6","/node-vitest/data","/node-vitest/contract","/playwright"]),y=["testkit.config.ts","testkit.config.mts","testkit.config.mjs","testkit.config.js"];export function findConfigFile(t){for(const n of y){const i=e.join(t,n);if(o.existsSync(i))return i}return null}export async function loadTestkitConfig(t,n={}){const i=findConfigFile(t);if(!i)return{config:{},configFile:null};const r=e.join(t,".testkit","_config");o.mkdirSync(r,{recursive:!0});const s=b(i),a=e.join(r,`config-${s.slice(0,12)}.mjs`);await h({absWorkingDir:t,bundle:!0,entryPoints:[i],format:"esm",legalComments:"none",outfile:a,platform:"node",sourcemap:"inline",target:"es2020",plugins:[C()]});const l=[s,n.importCacheSalt||""].filter(Boolean).join("-"),g=await import(`${p(a).href}?v=${l}`),f=S(g);if(!c(f))throw new Error(`testkit config file must export an object: ${e.basename(i)}`);return{config:f,configFile:i}}function b(t){const n=o.readFileSync(t,"utf8");return m.createHash("sha256").update(t).update("\0").update(n).digest("hex")}function C(){return{name:"testkit-config-alias",setup(t){t.onResolve({filter:/^@gfdelarue\/testkit(?:\/.*)?$/},n=>({namespace:"file",path:E(n.path)}))}}}function E(t){const n=t.slice(18);if(!n)return k;if(n==="/config")return j;throw w.has(n)?new Error(`testkit.config.ts may not import engine authoring module "${t}". Use repository config helpers from @gfdelarue/testkit/config instead.`):new Error(`Unsupported @gfdelarue/testkit import "${t}" while loading testkit config`)}function S(t){if(c(t))return t.default||t.config||{}}
1
+ import g from"node:crypto";import{rejectUnknownKeys as p}from"../../kernel/known-keys.js";import{isUnknownRecord as c}from"../../kernel/unknown-values.js";import r from"node:fs";import i from"node:path";import{fileURLToPath as d,pathToFileURL as h}from"node:url";import{buildWithEsbuildRetry as k}from"../../toolchains/esbuild.js";import{migrationText as b}from"../../domain/retired-test-types.js";const u=i.resolve(i.dirname(d(import.meta.url)),"..","..",".."),w=i.join(u,"dist","index.js"),y=i.join(u,"dist","config","authoring","index.js"),j=new Set(["/environment","/node-vitest/data","/playwright"]),E=["testkit.config.ts","testkit.config.mts","testkit.config.mjs","testkit.config.js"],T=Object.keys({areas:!0,artifacts:!0,bugs:!0,discovery:!0,execution:!0,fingerprints:!0,groups:!0,lint:!0,redact:!0,services:!0,toolchains:!0,ui:!0});export function findConfigFile(t){for(const e of E){const o=i.join(t,e);if(r.existsSync(o))return o}return null}export async function loadTestkitConfig(t,e={}){const o=findConfigFile(t);if(!o)return{config:{},configFile:null};const s=i.join(t,".testkit","_config");r.mkdirSync(s,{recursive:!0});const a=C(o),f=i.join(s,`config-${a.slice(0,12)}.mjs`);await k({absWorkingDir:t,bundle:!0,entryPoints:[o],format:"esm",legalComments:"none",outfile:f,platform:"node",sourcemap:"inline",target:"es2020",plugins:[v()]});const l=[a,e.importCacheSalt||""].filter(Boolean).join("-"),m=await import(`${h(f).href}?v=${l}`),n=x(m);if(!c(n))throw new Error(`testkit config file must export an object: ${i.basename(o)}`);if(Object.hasOwn(n,"profiles"))throw new Error(`${i.basename(o)}: Testkit 0.6.0 removed HTTP profiles; log in from test code. ${b("Remove the data test type")}.`);return p(n,T,i.basename(o)),{config:n,configFile:o}}function C(t){const e=r.readFileSync(t,"utf8");return g.createHash("sha256").update(t).update("\0").update(e).digest("hex")}function v(){return{name:"testkit-config-alias",setup(t){t.onResolve({filter:/^@gfdelarue\/testkit(?:\/.*)?$/},e=>({namespace:"file",path:O(e.path)}))}}}function O(t){const e=t.slice(18);if(!e)return w;if(e==="/config")return y;throw j.has(e)?new Error(`testkit.config.ts may not import engine authoring module "${t}". Use repository config helpers from @gfdelarue/testkit/config instead.`):new Error(`Unsupported @gfdelarue/testkit import "${t}" while loading testkit config`)}function x(t){if(c(t))return t.default||t.config||{}}
@@ -1 +1 @@
1
- import s from"node:path";import{normalizeDiscoveryPath as n}from"./path-policy.js";export function normalizeDiscoveryConfig(r,{allowRoots:t=!0}={}){if(r==null)return{};if(typeof r!="object"||Array.isArray(r))throw new Error("testkit discovery config must be an object");const e={};return t&&Object.prototype.hasOwnProperty.call(r,"roots")&&(e.roots=i(Reflect.get(r,"roots"),"testkit discovery roots")),Object.prototype.hasOwnProperty.call(r,"exclude")&&(e.exclude=i(Reflect.get(r,"exclude"),"testkit discovery exclude")),e}function i(r,t){if(!Array.isArray(r))throw new Error(`${t} must be an array of relative paths`);const e=r.map(o=>{if(typeof o!="string"||o.trim().length===0)throw new Error(`${t} entries must be non-empty strings`);if(s.isAbsolute(o))throw new Error(`${t} entries must be relative paths`);return n(o)}).filter(Boolean);return[...new Set(e)]}
1
+ import s from"node:path";import{rejectUnknownKeys as n}from"../../kernel/known-keys.js";import{normalizeDiscoveryPath as c}from"./path-policy.js";const f=Object.keys({exclude:!0,roots:!0});export function normalizeDiscoveryConfig(t,{allowRoots:r=!0}={}){if(t==null)return{};if(typeof t!="object"||Array.isArray(t))throw new Error("testkit discovery config must be an object");n(t,f,"testkit discovery config");const e={};return r&&Object.prototype.hasOwnProperty.call(t,"roots")&&(e.roots=i(Reflect.get(t,"roots"),"testkit discovery roots")),Object.prototype.hasOwnProperty.call(t,"exclude")&&(e.exclude=i(Reflect.get(t,"exclude"),"testkit discovery exclude")),e}function i(t,r){if(!Array.isArray(t))throw new Error(`${r} must be an array of relative paths`);const e=t.map(o=>{if(typeof o!="string"||o.trim().length===0)throw new Error(`${r} entries must be non-empty strings`);if(s.isAbsolute(o))throw new Error(`${r} entries must be relative paths`);return c(o)}).filter(Boolean);return[...new Set(e)]}
@@ -1 +1 @@
1
- import{DEFAULT_FILE_TIMEOUT_SECONDS as u,normalizeFileTimeoutSeconds as a}from"../../domain/file-timeout.js";export function parseTaskConcurrencyOptions(e,n){return i(e,n,"--task-concurrency","--workers")??null}export function normalizeRuntimeInstances(e,n="runtime.instances"){return c(e,n)}export function normalizeRuntimeMaxConcurrentTasks(e,n="runtime.maxConcurrentTasks"){return e==null?Number.POSITIVE_INFINITY:c(e,n)}export function normalizeDatabaseBinding(e,n="database.binding"){const r=String(e).trim();if(r!=="shared"&&r!=="per-runtime")throw new Error(`Invalid ${n} value "${String(e)}". Expected one of: shared, per-runtime.`);return r}export function resolveExecutionConfig({cli:e={},repo:n={}}={}){const r=i(n.taskConcurrency,n.workers);return{taskConcurrency:i(e.taskConcurrency,e.workers,"--task-concurrency","--workers")??r??1,fileTimeoutSeconds:a(e.fileTimeoutSeconds??n.fileTimeoutSeconds??u)}}export function normalizeExecutionConfig(e={}){const n=new Set(["workers","taskConcurrency","fileTimeoutSeconds"]),r=Object.keys(e).filter(o=>!n.has(o));if(r.length>0)throw new Error(`execution received unexpected key(s): ${r.join(", ")}`);return{taskConcurrency:i(e.taskConcurrency,e.workers)??1,fileTimeoutSeconds:a(e.fileTimeoutSeconds??u)}}function i(e,n,r="execution.taskConcurrency",t="execution.workers"){const o=e==null?void 0:c(e,r),s=n==null?void 0:c(n,t);if(o!==void 0&&s!==void 0&&o!==s)throw new Error(`${r} and ${t} must match when both are provided.`);return o??s}function c(e,n){const r=Number(e);if(!Number.isInteger(r)||r<=0)throw new Error(`${n} must be a positive integer.`);return r}
1
+ import{DEFAULT_FILE_TIMEOUT_SECONDS as u,normalizeFileTimeoutSeconds as a,normalizePositiveInteger as c}from"../../domain/file-timeout.js";export function parseTaskConcurrencyOptions(e,n){return i(e,n,"--task-concurrency","--workers")??null}export function normalizeRuntimeInstances(e,n="runtime.instances"){return c(e,n)}export function normalizeRuntimeMaxConcurrentTasks(e,n="runtime.maxConcurrentTasks"){return e==null?Number.POSITIVE_INFINITY:c(e,n)}export function normalizeDatabaseBinding(e,n="database.binding"){const r=String(e).trim();if(r!=="shared"&&r!=="per-runtime")throw new Error(`Invalid ${n} value "${String(e)}". Expected one of: shared, per-runtime.`);return r}export function resolveExecutionConfig({cli:e={},repo:n={}}={}){const r=i(n.taskConcurrency,n.workers);return{taskConcurrency:i(e.taskConcurrency,e.workers,"--task-concurrency","--workers")??r??1,fileTimeoutSeconds:a(e.fileTimeoutSeconds??n.fileTimeoutSeconds??u)}}export function normalizeExecutionConfig(e={}){const n=new Set(["workers","taskConcurrency","fileTimeoutSeconds"]),r=Object.keys(e).filter(o=>!n.has(o));if(r.length>0)throw new Error(`execution received unexpected key(s): ${r.join(", ")}`);return{taskConcurrency:i(e.taskConcurrency,e.workers)??1,fileTimeoutSeconds:a(e.fileTimeoutSeconds??u)}}function i(e,n,r="execution.taskConcurrency",t="execution.workers"){const o=e==null?void 0:c(e,r),s=n==null?void 0:c(n,t);if(o!==void 0&&s!==void 0&&o!==s)throw new Error(`${r} and ${t} must match when both are provided.`);return o??s}
@@ -1 +1 @@
1
- export function resolveRuntimeConfigs(o,m){const t=[],n=new Set,r=new Set,s=e=>{if(!r.has(e.name)){if(n.has(e.name))throw new Error(`Dependency cycle detected involving "${e.name}"`);n.add(e.name);for(const d of e.testkit.dependsOn||[]){const a=m.get(d);if(!a)throw new Error(`Service "${e.name}" depends on unknown service "${d}"`);s(a)}n.delete(e.name),r.add(e.name),t.push(e)}};return s(o),t}
1
+ export function resolveRuntimeClosure(s,o){const n=new Map;for(const t of s)for(const r of resolveRuntimeConfigs(t,o))n.set(r.name,r);return[...n.values()]}export function resolveRuntimeConfigs(s,o){const n=[],t=new Set,r=new Set,a=e=>{if(!r.has(e.name)){if(t.has(e.name))throw new Error(`Dependency cycle detected involving "${e.name}"`);t.add(e.name);for(const d of e.testkit.dependsOn||[]){const u=o.get(d);if(!u)throw new Error(`Service "${e.name}" depends on unknown service "${d}"`);a(u)}t.delete(e.name),r.add(e.name),n.push(e)}};return a(s),n}
@@ -1 +1 @@
1
- import g from"path";import{randomUUID as z}from"node:crypto";import{isUnknownRecord as D}from"../../kernel/unknown-values.js";import{loadConfigContext as P,resolveProductDir as A}from"./load.js";import{discoverProject as B,hasDiscoveryErrors as H,buildDiscoveryErrorFromDiagnostics as L}from"./discovery.js";import{loadTestkitConfig as V}from"./config-loader.js";import{TEST_TYPE_ORDER as _,isRunType as U}from"../../domain/test-types.js";import"../../domain/identifiers.js";import{DEFAULT_RUNTIME_ISOLATION_POLICY as q,resolveRuntimeIsolationPolicy as G}from"./runtime-isolation.js";import{resolveEngineProfile as Y}from"../../engines/catalog.js";import{readTestFileMetadata as K}from"./file-metadata.js";import{normalizeDiscoveryConfig as J}from"./decode-discovery.js";import"./path-policy.js";import{buildDiscoverySummary as Q,emptyDiscoverySummary as W}from"./discovery-summary.js";import{matchesSelectedTypes as X,matchesSuiteSelectors as k,normalizeTypeValues as Z,parseSuiteSelectors as ee}from"../../domain/suite-selection.js";import{errorMessage as E}from"../../kernel/error-serialization.js";import{readObjectRecord as I,readProperty as f}from"./values.js";const ie=9,C=String;export async function discoverTests(e={}){return(await loadDiscoveryContext(e)).discovery}export async function loadDiscoveredConfigContext(e={}){const i=await P({dir:e.dir,configImportCacheSalt:z()}),{discovery:t}=await loadDiscoveryContext({dir:i.productDir,diagnostics:"error"},i);return{context:i,discovery:t}}export async function loadDiscoveryContext(e={},i){const t=i?.productDir??A(process.cwd(),e.dir),o=le(e);if(i&&o.diagnosticsMode==="error"&&H(i.discovery.diagnostics))throw L(i.discovery.diagnostics);const r=i?{config:i.config,configFile:i.configFile,diagnostics:[]}:await te(t,o.diagnosticsMode),s={schemaVersion:ie,source:"testkit-discovery",product:{name:g.basename(t),directory:t},configFile:r.configFile?g.relative(t,r.configFile)||g.basename(r.configFile):null,filters:{service:o.serviceFilter,types:o.typeValues,suiteSelectors:o.suiteSelectors.map(n=>n.raw),fileNames:o.fileNames,runnableOnly:o.runnableOnly,diagnostics:o.diagnosticsMode},services:[],suites:[],files:[],diagnostics:[...r.diagnostics],summary:W()};if(!r.config)return{discovery:R(s),context:null};const a=ue(r.config),l=fe(a.services),p=i?.discovery??B(t,l,{strict:o.diagnosticsMode==="error",discovery:a.discovery}),v={project:p,fileMetadataByPath:new Map(i?.configs.flatMap(n=>[...n.testkit.fileMetadataByPath])??[])};s.diagnostics.push(...p.diagnostics),ae(o.serviceFilter,a.services,p);let y=i??null;try{y=i??await P({dir:t,preparedDiscovery:v,configContext:{config:r.config,configFile:r.configFile},discoveryOptions:{strict:o.diagnosticsMode==="error"}})}catch(n){if(o.diagnosticsMode==="error")throw n;s.diagnostics.push({code:"config_invalid",severity:"error",message:E(n)})}const h=ne({productDir:t,rawDiscovery:p,explicitServices:a.services,configs:y?.configs??[],fileMetadataByPath:v.fileMetadataByPath,filters:o});return{discovery:R({...s,...h}),context:y}}export function formatDisplayName(e){return C(e||"").split(/[-_/]+/g).filter(Boolean).map(i=>i.replace(/^\w/,t=>t.toUpperCase())).join(" ")}export function testTypeContract(e,i,t){const o=Y(e,i);if(o.id!==t)throw new Error(`Discovery profile mismatch for ${e}: metadata resolved ${t}, catalog resolved ${o.id}`);return e==="data"?{authoringApi:"@gfdelarue/testkit/node-vitest/data",executionHost:o.capabilities.executionHost,summary:"Data suites use the node-vitest engine and record Testkit data evidence; they are not raw Vitest or service-namespace tests."}:e==="contract"?{authoringApi:"@gfdelarue/testkit/node-vitest/contract",executionHost:o.capabilities.executionHost,summary:"Contract suites use the node-vitest engine for Node-backed service/runtime contracts without data-flow evidence requirements."}:i==="k6"?{authoringApi:"@gfdelarue/testkit/k6",executionHost:o.capabilities.executionHost}:i==="playwright"?{authoringApi:"@gfdelarue/testkit/playwright",executionHost:o.capabilities.executionHost}:{executionHost:o.capabilities.executionHost}}async function te(e,i){try{const t=await V(e),{config:o,configFile:r}=oe(t);return{config:o,configFile:r,diagnostics:[]}}catch(t){if(i==="error")throw t;return{config:null,configFile:null,diagnostics:[{code:"config_invalid",severity:"error",message:E(t)}]}}}function oe(e){if(!D(e))throw new Error("testkit config loader must return an object");const i=f(e,"config"),t=f(e,"configFile");if(!D(i)){const o=typeof t=="string"?g.basename(t):"testkit config file";throw new Error(`testkit config file must export an object: ${o}`)}if(t!==null&&typeof t!="string")throw new Error("testkit config loader returned an invalid config path");return{config:i,configFile:t}}function ne({configs:e,fileMetadataByPath:i,productDir:t,rawDiscovery:o,explicitServices:r,filters:s}){const a=new Map(e.map(n=>[n.name,n])),l=new Map,p=new Map,v=[],y=new Set([...Object.keys(r),...Object.keys(o.services),...a.keys()]);for(const n of y){if(s.serviceFilter&&n!==s.serviceFilter)continue;const c=a.get(n),u=o.services[n],d=r[n];l.set(n,{name:n,discovered:c!==void 0||!!u,localCwd:c?c.testkit.local?.cwd||".":d?.localCwd||u?.inferredLocalCwd||".",dependsOn:[...c?.testkit.dependsOn??d?.dependsOn??[]],suiteCount:0,fileCount:0,activeFileCount:0,skippedFileCount:0})}for(const n of o.files){const c=n.testType;if(!X(c,s.typeValues)||!k(c,n.suiteName,s.suiteSelectors)||s.serviceFilter&&n.serviceName!==s.serviceFilter||s.fileNameSet.size>0&&!s.fileNameSet.has(n.filePath))continue;const u=i.get(n.filePath)??K(t,n.filePath);i.set(n.filePath,u);const d=a.get(n.serviceName),m=d?.suites[c]?.find(j=>j.name===n.suiteName);if(d&&(!m||m.testType!==c||m.engineId!==u.engineId||m.profileId!==u.profileId))throw new Error(`Normalized suite ${n.serviceName}/${c}:${n.suiteName} conflicts with file ${n.filePath}`);const b=d&&(u.skipReason||d.testkit.skip?.fileReasonByPath.get(n.filePath)||me(d,c,n.suiteName))||null;if(s.runnableOnly&&b)continue;const x=d?[...new Set([...ge(d,c,n.suiteName),...d.testkit.requirements.fileLocksByPath.get(n.filePath)||[],...u.locks])].sort():[],$=l.get(n.serviceName)?.dependsOn||[],w=re({serviceName:n.serviceName,suiteName:n.suiteName,testType:c,filePath:n.filePath,engineId:u.engineId,profileId:u.profileId,skipReason:b,locks:x,runtimeIsolation:d&&m?G(d,m,n.filePath):q,dependsOn:$});v.push(w);const F=[n.serviceName,c,n.suiteName].join("|"),O=p.get(F);O?O.files.push(w):p.set(F,{serviceName:n.serviceName,testType:c,suiteName:n.suiteName,files:[w]})}const h=[...p.values()].map(n=>se(n.serviceName,n.testType,n.suiteName,n.files,l.get(n.serviceName)?.dependsOn||[]));for(const n of h){const c=l.get(n.service)||{name:n.service,discovered:!0,localCwd:o.services[n.service]?.inferredLocalCwd||".",dependsOn:[...r[n.service]?.dependsOn||[]],suiteCount:0,fileCount:0,activeFileCount:0,skippedFileCount:0};c.suiteCount+=1,c.fileCount+=n.fileCount,c.activeFileCount+=n.activeFileCount,c.skippedFileCount+=n.skippedFileCount,l.set(n.service,c)}return{services:[...l.values()].sort((n,c)=>n.name.localeCompare(c.name)),suites:h.sort(he),files:v.sort(Ce)}}function re(e){const i=testTypeContract(e.testType,e.engineId,e.profileId);return{id:ye(e.serviceName,e.testType,e.engineId,e.profileId,e.filePath),path:e.filePath,displayName:fileDisplayName(e.filePath),service:e.serviceName,suiteName:e.suiteName,groupLabel:formatDisplayName(e.suiteName),testType:e.testType,engineId:e.engineId,profileId:e.profileId,skipped:!!e.skipReason,skipReason:e.skipReason,locks:e.locks,runtimeIsolation:e.runtimeIsolation,dependsOn:[...e.dependsOn],contract:i}}function se(e,i,t,o,r){const s=ce(e,i,t,o),a=o.filter(l=>l.skipped).length;return{id:ve(e,i,s.engineId,s.profileId,t),service:e,name:t,displayName:formatDisplayName(t),testType:i,engineId:s.engineId,profileId:s.profileId,groupLabel:formatDisplayName(t),fileCount:o.length,activeFileCount:o.length-a,skippedFileCount:a,dependsOn:[...r],locks:[...new Set(o.flatMap(l=>l.locks))].sort(),filePaths:o.map(l=>l.path),contract:s.contract}}function ce(e,i,t,o){const r=o[0];for(const s of o.slice(1))if(s.engineId!==r.engineId||s.profileId!==r.profileId)throw new Error(`Discovery suite ${e}/${i}:${t} mixes engine profiles ${r.engineId}/${r.profileId} and ${s.engineId}/${s.profileId}`);return{contract:r.contract,engineId:r.engineId,profileId:r.profileId}}function R(e){return{...e,diagnostics:e.diagnostics.sort(we),summary:Q({diagnostics:e.diagnostics,files:e.files,serviceCount:e.services.length,suiteCount:e.suites.length})}}function ae(e,i,t){if(!e)return;const o=new Set([...Object.keys(i),...Object.keys(t.services),...Object.keys(t.suitesByService)]);if(o.has(e))return;const r=[...o].sort((s,a)=>s.localeCompare(a)).join(", ");throw new Error(r.length>0?`Service "${e}" not found. Available: ${r}`:`Service "${e}" not found.`)}function le(e){const i=de(Z(N(e.type))),t=ee(N(e.suite)),o=N(e.file).map(S);return{typeValues:i,suiteSelectors:t,fileNames:o,fileNameSet:new Set(o),serviceFilter:e.service||null,runnableOnly:!!e.runnableOnly,diagnosticsMode:e.diagnostics==="error"?"error":"report"}}function de(e){const i=[];for(const t of e){if(!U(t))throw new Error(`Discovery produced unsupported test type "${t}".`);i.push(t)}return i}function ue(e){const i=I(f(e,"services")),t={};for(const[o,r]of Object.entries(i)){const s=I(r),a=I(f(s,"local"));t[o]={dependsOn:pe(f(s,"dependsOn")),discovery:M(f(s,"discovery")),localCwd:S(f(a,"cwd")||"."),localDisabled:f(s,"local")===!1}}return{discovery:M(f(e,"discovery")),services:t}}function fe(e){const i={};for(const[t,o]of Object.entries(e))o&&(i[t]={discovery:o.discovery,local:o.localDisabled?!1:{baseUrl:"",cwd:o.localCwd,env:{},start:""}});return i}function M(e){try{return J(e,{allowRoots:!0})}catch{return{}}}function pe(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function me(e,i,t){for(const o of e.testkit.skip?.suites||[])if(k(i,t,[o.selector]))return o.reason;return null}function ge(e,i,t){const o=new Set;for(const r of e.testkit.requirements.suites)if(k(i,t,[r.selector]))for(const s of r.locks)o.add(s);return[...o].sort()}function N(e){return Array.isArray(e)?e.filter(t=>t!=null).map(t=>C(t)):e==null||e===""?[]:[C(e)]}function S(e){return C(e).split(g.sep).join("/").replace(/^\.\/+/,"")}export function fileDisplayName(e){const i=new RegExp(`\\.(${_.join("|")})\\.testkit\\.ts$`),t=g.posix.basename(e).replace(i,"");return formatDisplayName(t)}function ve(e,i,t,o,r){return[e,i,t,o,r].join("|")}function ye(e,i,t,o,r){return[e,i,t,o,S(r)].join("|")}function he(e,i){return e.service.localeCompare(i.service)||e.testType.localeCompare(i.testType)||e.name.localeCompare(i.name)}function Ce(e,i){return e.service.localeCompare(i.service)||e.testType.localeCompare(i.testType)||e.suiteName.localeCompare(i.suiteName)||e.path.localeCompare(i.path)}function we(e,i){return T(e.severity)-T(i.severity)||e.code.localeCompare(i.code)||(e.path||"").localeCompare(i.path||"")}function T(e){return e==="error"?1:2}
1
+ import m from"path";import{randomUUID as j}from"node:crypto";import{isUnknownRecord as S,readDynamicProperty as D}from"../../kernel/unknown-values.js";import{loadConfigContext as P,resolveProductDir as x}from"./load.js";import{hasDiscoveryErrors as z,buildDiscoveryErrorFromDiagnostics as B}from"./discovery.js";import{discoverOwnedTests as _}from"./owned-discovery.js";import{loadTestkitConfig as V}from"./config-loader.js";import{TEST_TYPE_ORDER as L,isRunType as A}from"../../domain/test-types.js";import"../../domain/identifiers.js";import{DEFAULT_RUNTIME_ISOLATION_POLICY as U,resolveRuntimeIsolationPolicy as q}from"./runtime-isolation.js";import{resolveExecutionProfile as Y}from"../../engines/catalog.js";import{readTestFileMetadata as G}from"./file-metadata.js";import{buildDiscoverySummary as K,emptyDiscoverySummary as H}from"./discovery-summary.js";import{matchesSelectedTypes as J,matchesSuiteSelectors as C,normalizeTypeValues as Q,parseSuiteSelectors as W,suiteKey as E}from"../../domain/suite-selection.js";import{errorMessage as T}from"../../kernel/error-serialization.js";const X=10,h=String;export async function discoverTests(e={}){return(await loadDiscoveryContext(e)).discovery}export async function loadDiscoveredConfigContext(e={}){const{group:o,...i}=e,n=await P({...i,configImportCacheSalt:j()}),{discovery:r}=await loadDiscoveryContext({dir:n.productDir,diagnostics:"error",group:o},n);return{context:n,discovery:r}}export async function loadDiscoveryContext(e={},o){const i=o?.productDir??x(process.cwd(),e.dir),n=se(e);if(o&&n.diagnosticsMode==="error"&&z(o.discovery.diagnostics))throw B(o.discovery.diagnostics);const r=o?{config:o.config,configFile:o.configFile,diagnostics:[]}:await Z(i,n.diagnosticsMode),a={schemaVersion:X,source:"testkit-discovery",product:{name:m.basename(i),directory:i},configFile:r.configFile?m.relative(i,r.configFile)||m.basename(r.configFile):null,filters:{group:n.groupFilter,types:n.typeValues,suiteSelectors:n.suiteSelectors.map(t=>t.raw),fileNames:n.fileNames,runnableOnly:n.runnableOnly,diagnostics:n.diagnosticsMode},groups:[],suites:[],files:[],diagnostics:[...r.diagnostics],summary:H()};if(!r.config)return{discovery:b(a),context:null};const c=o?{groups:o.groups,migration:null,plainFiles:[],problems:[],project:o.discovery}:await _(i,r.config,{selection:e.vitest,strict:n.diagnosticsMode==="error"}),p=c.project,f={owned:c,fileMetadataByPath:new Map(o?.groups.flatMap(t=>[...t.testkit.fileMetadataByPath])??[])};a.diagnostics.push(...p.diagnostics),re(n.groupFilter,c.groups);let d=o??null;try{d=o??await P({dir:i,preparedDiscovery:f,configContext:{config:r.config,configFile:r.configFile},discoveryOptions:{strict:n.diagnosticsMode==="error"}})}catch(t){if(n.diagnosticsMode==="error")throw t;a.diagnostics.push({code:"config_invalid",severity:"error",message:T(t)})}const y=oe({productDir:i,rawDiscovery:p,declarations:c.groups,groups:d?.groups??[],fileMetadataByPath:f.fileMetadataByPath,filters:n});return{discovery:b({...a,...y}),context:d}}export function formatDisplayName(e){return h(e||"").split(/[-_/]+/g).filter(Boolean).map(o=>o.replace(/^\w/,i=>i.toUpperCase())).join(" ")}export function testTypeContract(e,o,i){return Y({engineId:o,profileId:i,testType:e}),o==="playwright"?{authoringApi:"@gfdelarue/testkit/playwright"}:{}}async function Z(e,o){try{const i=await V(e),{config:n,configFile:r}=ee(i);return{config:n,configFile:r,diagnostics:[]}}catch(i){if(o==="error")throw i;return{config:null,configFile:null,diagnostics:[{code:"config_invalid",severity:"error",message:T(i)}]}}}function ee(e){if(!S(e))throw new Error("testkit config loader must return an object");const o=D(e,"config"),i=D(e,"configFile");if(!S(o)){const n=typeof i=="string"?m.basename(i):"testkit config file";throw new Error(`testkit config file must export an object: ${n}`)}if(i!==null&&typeof i!="string")throw new Error("testkit config loader returned an invalid config path");return{config:o,configFile:i}}function oe({declarations:e,fileMetadataByPath:o,filters:i,groups:n,productDir:r,rawDiscovery:a}){const c=new Map(n.map(t=>[t.name,t])),p=new Map,f=new Map,d=[];for(const t of e)i.groupFilter&&t.name!==i.groupFilter||p.set(t.name,{name:t.name,roots:[...t.roots],uses:[...t.uses],source:t.source,suiteCount:0,fileCount:0,activeFileCount:0,skippedFileCount:0});for(const t of a.files){const s=t.testType;if(!J(s,i.typeValues)||!C(s,t.suiteName,i.suiteSelectors)||i.groupFilter&&t.serviceName!==i.groupFilter||i.fileNameSet.size>0&&!i.fileNameSet.has(t.filePath))continue;const u=o.get(t.filePath)??G(r,t.filePath);o.set(t.filePath,u);const l=c.get(t.serviceName),g=l?.suites.find(F=>F.testType===s&&F.name===t.suiteName);if(l&&(!g||g.engineId!==u.engineId||g.profileId!==u.profileId))throw new Error(`Normalized suite ${t.serviceName}/${E({name:t.suiteName,testType:s})} conflicts with file ${t.filePath}`);const w=l&&(u.skipReason||l.testkit.skip?.fileReasonByPath.get(t.filePath)||ce(l,s,t.suiteName))||null;if(i.runnableOnly&&w)continue;const O=l?[...new Set([...le(l,s,t.suiteName),...l.testkit.requirements.fileLocksByPath.get(t.filePath)||[],...u.locks])].sort():[],v=ie({groupName:t.serviceName,suiteName:t.suiteName,testType:s,filePath:t.filePath,engineId:u.engineId,profileId:u.profileId,skipReason:w,locks:O,runtimeIsolation:l&&g?q(l,g,t.filePath):U});d.push(v);const k=[t.serviceName,s??"",t.suiteName].join("|"),N=f.get(k);N?N.files.push(v):f.set(k,{groupName:t.serviceName,testType:s,suiteName:t.suiteName,files:[v]})}const y=[...f.values()].map(t=>te(t.groupName,t.testType,t.suiteName,t.files));for(const t of y){const s=p.get(t.group);if(s===void 0)throw new Error(`Discovered suite ${t.id} belongs to no declared group`);s.suiteCount+=1,s.fileCount+=t.fileCount,s.activeFileCount+=t.activeFileCount,s.skippedFileCount+=t.skippedFileCount}return{groups:[...p.values()].sort((t,s)=>t.name.localeCompare(s.name)),suites:y.sort(ue),files:d.sort(pe)}}function ie(e){const o=testTypeContract(e.testType,e.engineId,e.profileId);return{id:R(e.groupName,e.testType,e.engineId,e.profileId,M(e.filePath)),path:e.filePath,displayName:fileDisplayName(e.filePath),group:e.groupName,suiteName:e.suiteName,suiteLabel:formatDisplayName(e.suiteName),...e.testType===void 0?{}:{testType:e.testType},engineId:e.engineId,profileId:e.profileId,skipped:!!e.skipReason,skipReason:e.skipReason,locks:e.locks,runtimeIsolation:e.runtimeIsolation,contract:o}}function te(e,o,i,n){const r=ne(e,o,i,n),a=n.filter(c=>c.skipped).length;return{id:R(e,o,r.engineId,r.profileId,i),group:e,name:i,displayName:formatDisplayName(i),...o===void 0?{}:{testType:o},engineId:r.engineId,profileId:r.profileId,suiteLabel:formatDisplayName(i),fileCount:n.length,activeFileCount:n.length-a,skippedFileCount:a,locks:[...new Set(n.flatMap(c=>c.locks))].sort(),filePaths:n.map(c=>c.path),contract:r.contract}}function ne(e,o,i,n){const r=n[0];for(const a of n.slice(1))if(a.engineId!==r.engineId||a.profileId!==r.profileId)throw new Error(`Discovery suite ${e}/${E({name:i,testType:o})} mixes engine profiles ${r.engineId}/${r.profileId} and ${a.engineId}/${a.profileId}`);return{contract:r.contract,engineId:r.engineId,profileId:r.profileId}}function b(e){return{...e,diagnostics:e.diagnostics.sort(fe),summary:K({diagnostics:e.diagnostics,files:e.files,groupCount:e.groups.length,suiteCount:e.suites.length})}}function re(e,o){if(!e||o.some(n=>n.name===e))return;const i=o.map(n=>n.name).sort((n,r)=>n.localeCompare(r)).join(", ");throw new Error(`Group "${e}" not found. Available: ${i}`)}function se(e){const o=ae(Q(I(e.type))),i=W(I(e.suite)),n=I(e.file).map(M);return{typeValues:o,suiteSelectors:i,fileNames:n,fileNameSet:new Set(n),groupFilter:e.group||null,runnableOnly:!!e.runnableOnly,diagnosticsMode:e.diagnostics==="error"?"error":"report"}}function ae(e){const o=[];for(const i of e){if(!A(i))throw new Error(`Discovery produced unsupported test type "${i}".`);o.push(i)}return o}function ce(e,o,i){for(const n of e.testkit.skip?.suites||[])if(C(o,i,[n.selector]))return n.reason;return null}function le(e,o,i){const n=new Set;for(const r of e.testkit.requirements.suites)if(C(o,i,[r.selector]))for(const a of r.locks)n.add(a);return[...n].sort()}function I(e){return Array.isArray(e)?e.filter(i=>i!=null).map(i=>h(i)):e==null||e===""?[]:[h(e)]}function M(e){return h(e).split(m.sep).join("/").replace(/^\.\/+/,"")}export function fileDisplayName(e){const o=new RegExp(`\\.(${L.join("|")})\\.testkit\\.ts$`),i=m.posix.basename(e).replace(o,"");return formatDisplayName(i)}function R(e,o,i,n,r){return[e,...o===void 0?[]:[o],i,n,r].join("|")}function ue(e,o){return e.group.localeCompare(o.group)||(e.testType??"").localeCompare(o.testType??"")||e.name.localeCompare(o.name)}function pe(e,o){return e.group.localeCompare(o.group)||(e.testType??"").localeCompare(o.testType??"")||e.suiteName.localeCompare(o.suiteName)||e.path.localeCompare(o.path)}function fe(e,o){return $(e.severity)-$(o.severity)||e.code.localeCompare(o.code)||(e.path||"").localeCompare(o.path||"")}function $(e){return e==="error"?1:2}
@@ -1 +1 @@
1
- export function buildDiscoverySummary(s){const i={},r={};for(const e of s.files)i[e.service]=(i[e.service]||0)+1,r[e.testType]=(r[e.testType]||0)+1;return{activeFiles:s.files.filter(e=>!e.skipped).length,byService:i,byTestType:r,diagnostics:{errors:s.diagnostics.filter(e=>e.severity==="error").length,warnings:s.diagnostics.filter(e=>e.severity==="warning").length},files:s.files.length,services:s.serviceCount,skippedFiles:s.files.filter(e=>e.skipped).length,suites:s.suiteCount}}export function emptyDiscoverySummary(){return{activeFiles:0,byService:{},byTestType:{},diagnostics:{errors:0,warnings:0},files:0,services:0,skippedFiles:0,suites:0}}
1
+ export function buildDiscoverySummary(s){const i={},r={};for(const e of s.files)i[e.group]=(i[e.group]||0)+1,e.testType!==void 0&&(r[e.testType]=(r[e.testType]||0)+1);return{activeFiles:s.files.filter(e=>!e.skipped).length,byGroup:i,byTestType:r,diagnostics:{errors:s.diagnostics.filter(e=>e.severity==="error").length,warnings:s.diagnostics.filter(e=>e.severity==="warning").length},files:s.files.length,groups:s.groupCount,skippedFiles:s.files.filter(e=>e.skipped).length,suites:s.suiteCount}}export function emptyDiscoverySummary(){return{activeFiles:0,byGroup:{},byTestType:{},diagnostics:{errors:0,warnings:0},files:0,groups:0,skippedFiles:0,suites:0}}
@@ -1,2 +1,2 @@
1
- import L from"fs";import h from"path";import{recordWork as k}from"../../kernel/work-metrics.js";import{DEFAULT_DISCOVERY_EXCLUDES as F,normalizeDiscoveryPath as K,resolveDiscoveryRoots as z,shouldExcludeDiscoveryPath as D}from"./path-policy.js";import{normalizeDiscoveryConfig as C}from"./decode-discovery.js";const E=String,j="__testkit__",O=[{suffix:".int.testkit.ts",testType:"int"},{suffix:".e2e.testkit.ts",testType:"e2e"},{suffix:".contract.testkit.ts",testType:"contract"},{suffix:".data.testkit.ts",testType:"data"},{suffix:".dal.testkit.ts",testType:"dal"},{suffix:".load.testkit.ts",testType:"load"},{suffix:".ui.testkit.ts",testType:"ui"}];export function discoverProject(t,e={},r={}){const n=r.strict!==!1,o=C(r.discovery,{allowRoots:!0}),{suiteFiles:s,legacyFiles:a}=A(t,o),i={},p={},u=X(a),g=[];for(const c of s){const l=R(c);if(!l)continue;const f=M(c,e,o);if(f===null)continue;if(f.length===0){u.push({code:"unowned_test",severity:"error",message:`Unowned test file: ${c}`,path:c});continue}if(f.length>1){u.push({code:"ambiguous_test",severity:"error",message:`Ambiguous test file: ${c} -> ${f.map(v=>v.name).sort((v,m)=>v.localeCompare(m)).join(", ")}`,path:c,serviceNames:f.map(v=>v.name).sort((v,m)=>v.localeCompare(m))});continue}const d=f[0];p[d.name]=Y(p[d.name],d);const y=W(d,c),w=q(y,l.suffix);g.push({serviceName:d.name,testType:l.testType,filePath:c,suitePath:w.suitePath})}if(n&&hasDiscoveryErrors(u))throw buildDiscoveryErrorFromDiagnostics(u);for(const c of g){const l=i[c.serviceName]||{},f=l[c.testType]||[],d=c.suitePath.join("/");let y=f.find(w=>w._suiteKey===d);y||(y={files:[],_suiteKey:d,_suitePath:c.suitePath},f.push(y),l[c.testType]=f,i[c.serviceName]=l),y.files.push(c.filePath)}const _=[],T={};for(const[c,l]of Object.entries(i)){if(!l)continue;const f={};for(const[d,y]of Object.entries(l)){if(!y)continue;const w=B(y),v=[];for(const m of y){const P=I(w,m._suiteKey);m.files.sort((S,$)=>S.localeCompare($));for(const S of m.files)_.push({serviceName:c,testType:d,suiteName:P,suitePath:[...m._suitePath],filePath:S});v.push({name:P,files:m.files})}f[d]=v.sort((m,P)=>m.name.localeCompare(P.name))}T[c]=f}return{services:p,suitesByService:T,files:_.sort((c,l)=>c.serviceName.localeCompare(l.serviceName)||c.testType.localeCompare(l.testType)||c.suiteName.localeCompare(l.suiteName)||c.filePath.localeCompare(l.filePath)),diagnostics:u}}export function hasDiscoveryErrors(t=[]){return t.some(e=>e?.severity==="error")}export function buildDiscoveryErrorFromDiagnostics(t=[]){const e=["Filesystem discovery failed for one or more .testkit.ts files."],r=t.filter(s=>s.code==="legacy_path").map(s=>s.path),n=t.filter(s=>s.code==="unowned_test").map(s=>s.path),o=t.filter(s=>s.code==="ambiguous_test");if(r.length>0){e.push(""),e.push("Legacy test files outside __testkit__:");for(const s of r)e.push(`- ${s}`)}if(n.length>0){e.push(""),e.push("Unowned test files:");for(const s of n)e.push(`- ${s}`)}if(o.length>0){e.push(""),e.push("Ambiguous test files:");for(const s of o)e.push(`- ${s.path} -> ${s.serviceNames.join(", ")}`)}return e.push(""),e.push('Expected test files to live under a "__testkit__" directory within a service root.'),new Error(e.join(`
2
- `))}function A(t,e={}){const r=[],n=[],o=[...new Set([...F,...(e.exclude||[]).map(x)])],s=z(t,e.roots,".");for(;s.length>0;){const a=s.pop();if(a!==void 0){k("discovery.directoriesRead");for(const i of L.readdirSync(a,{withFileTypes:!0})){k("discovery.entriesVisited");const p=h.join(a,i.name);if(i.isSymbolicLink())continue;if(i.isDirectory()){const g=K(h.relative(t,p));if(D(g,o))continue;s.push(p);continue}if(!i.isFile())continue;const u=x(h.relative(t,p));R(u)&&(u.split("/").includes(j)?r.push(u):n.push(u))}}}return{suiteFiles:r.sort((a,i)=>a.localeCompare(i)),legacyFiles:n.sort((a,i)=>a.localeCompare(i))}}function M(t,e,r={}){const n=Object.entries(e).flatMap(([i,p])=>U(i,p,r));if(n.length===0)return[{name:"app",source:"implicit-root",cwdPrefix:"."}];const o=n.filter(i=>i.depth===0||i.matchPrefix&&b(t,i.matchPrefix)),s=o.filter(i=>V(i,t));if(s.length===0)return o.length>0&&o.every(i=>N(i,t))?null:[];const a=Math.max(...s.map(i=>i.depth));return s.filter(i=>i.depth===a)}function B(t){const e=new Map,r=new Map;for(const n of t){const o=n._suitePath;let s="";for(let a=1;a<=o.length;a+=1){s=o.slice(-a).join("-");const i=e.get(s);if(!i){e.set(s,n._suiteKey);break}if(i===n._suiteKey)break;s=""}s||(s=o.join("-")),r.set(n._suiteKey,s)}if(r.size!==t.length)for(const n of t)r.has(n._suiteKey)||r.set(n._suiteKey,n._suitePath.join("-"));if(new Set(r.values()).size!==t.length){const n=new Map;for(const o of t){const s=o._suitePath.join("-"),a=n.get(s)||0;n.set(s,a+1),r.set(o._suiteKey,a===0?s:`${s}-${E(a+1)}`)}}return r}function I(t,e){const r=t.get(e);if(r===void 0)throw new Error(`Discovery suite name was not resolved for "${e}"`);return r}function U(t,e,r={}){const n=e?.local,o=x(n&&n.cwd||"."),s=C(e?.discovery,{allowRoots:!0}),a=Array.isArray(s.roots)&&s.roots.length>0?s.roots:["."],i=(s.exclude||[]).map(u=>x(o==="."?u:h.posix.join(o,u))),p=[...new Set([...F,...(r.exclude||[]).map(x),...i])];return a.map(u=>{const g=x(u||"."),_=o==="."?g:g==="."?o:x(h.posix.join(o,g));return{name:t,source:"cwd",cwdPrefix:o==="."?null:o,matchPrefix:_==="."?null:_,depth:_==="."?0:_.split("/").filter(Boolean).length,exclude:p}})}function V(t,e){return N(t,e)?!1:!!(t.depth===0||t.matchPrefix&&b(e,t.matchPrefix))}function W(t,e){return t.matchPrefix&&b(e,t.matchPrefix)?h.posix.relative(t.matchPrefix,e):t.cwdPrefix&&b(e,t.cwdPrefix)?h.posix.relative(t.cwdPrefix,e):e}function N(t,e){return D(x(e),t.exclude)}function q(t,e){const r=t.split("/").filter(Boolean),n=r.indexOf(j);if(n===-1)return{suitePath:[h.posix.basename(t,e)]};const o=r.slice(0,n),s=r.slice(n+1);return s.length===0?{suitePath:[h.posix.basename(t,e)]}:s.length===1?o.length===0?{suitePath:[h.posix.basename(s[0],e)]}:{suitePath:o}:{suitePath:[...o,s[0]]}}function Y(t,e){return t?{...t,inferredLocalCwd:t.inferredLocalCwd==="."?e.cwdPrefix||".":t.inferredLocalCwd}:{name:e.name,inferredLocalCwd:e.cwdPrefix||".",source:e.source}}function R(t){return O.find(e=>t.endsWith(e.suffix))||null}function b(t,e){return t===e||t.startsWith(`${e}/`)}function x(t){const e=E(t).split(h.sep).join("/");return e==="."||e==="./"?".":e.replace(/^\.\/+/,"").replace(/\/+$/,"")||"."}function X(t){return t.map(e=>({code:"legacy_path",severity:"error",message:`Legacy test file outside __testkit__: ${e}`,path:e}))}
1
+ import T from"fs";import y from"path";import{recordWork as v}from"../../kernel/work-metrics.js";import{DEFAULT_DISCOVERY_EXCLUDES as k,normalizeDiscoveryPath as C,resolveDiscoveryRoots as D,shouldExcludeDiscoveryPath as E}from"./path-policy.js";const P=String,w="__testkit__";export const PLAIN_TEST_SUFFIX=/\.(?:test|spec)\.[cm]?[jt]sx?$/u;const N=[{suffix:".ui.testkit.ts",testType:"ui"}];export function scanTestFiles(o,e={}){const i=[],n=[],t=[],u=[...new Set([...k,...(e.exclude||[]).map(x)])],l=D(o,e.roots,".");for(;l.length>0;){const c=l.pop();if(c!==void 0){v("discovery.directoriesRead");for(const s of T.readdirSync(c,{withFileTypes:!0})){v("discovery.entriesVisited");const r=y.join(c,s.name);if(s.isSymbolicLink())continue;if(s.isDirectory()){const p=C(y.relative(o,r));if(E(p,u))continue;l.push(r);continue}if(!s.isFile())continue;const a=x(y.relative(o,r));if(!b(a)){a.endsWith(".testkit.ts")&&t.push(a);continue}a.split("/").includes(w)?i.push(a):n.push(a)}}}return{suiteFiles:i.sort((c,s)=>c.localeCompare(s)),legacyFiles:n.sort((c,s)=>c.localeCompare(s)),untypedFiles:t.sort((c,s)=>c.localeCompare(s))}}export function buildDiscoveryProject(o,e,i={}){const n=i.strict!==!1,t=L(o),u=new Map;for(const s of[...e].sort((r,a)=>r.filePath.localeCompare(a.filePath))){const r=s.filePath;if(s.kind==="ambiguous"){const g=[...s.owners].sort((S,F)=>S.localeCompare(F));t.push({code:"ambiguous_test",severity:"error",message:`Ambiguous test file: ${r} -> ${g.join(", ")}`,path:r,groupNames:g});continue}const a=b(r),p=`${s.owner}|${a?.testType??""}`,m=u.get(p)??new Map;u.set(p,m);const f=K(s.relativePath,a),d=f.join("/"),h=a===null?{}:{testType:a.testType},_=m.get(d)??{_suiteKey:d,_suitePath:f,serviceName:s.owner,suite:{files:[],name:"",...h},type:h};m.set(d,_),_.suite.files.push(r)}if(n&&hasDiscoveryErrors(t))throw buildDiscoveryErrorFromDiagnostics(t);const l=[],c={};for(const s of u.values()){const r=$([...s.values()]);for(const{_suiteKey:a,_suitePath:p,serviceName:m,suite:f,type:d}of s.values()){f.name=j(r,a),f.files.sort((h,_)=>h.localeCompare(_));for(const h of f.files)l.push({...d,filePath:h,serviceName:m,suiteName:f.name,suitePath:[...p]});(c[m]??=[]).push(f)}}for(const s of Object.values(c))s?.sort((r,a)=>(r.testType??"").localeCompare(a.testType??"")||r.name.localeCompare(a.name));return{suitesByService:c,files:l.sort((s,r)=>s.serviceName.localeCompare(r.serviceName)||(s.testType??"").localeCompare(r.testType??"")||s.suiteName.localeCompare(r.suiteName)||s.filePath.localeCompare(r.filePath)),diagnostics:t}}export function hasDiscoveryErrors(o=[]){return o.some(e=>e?.severity==="error")}export function buildDiscoveryErrorFromDiagnostics(o=[]){const e=["Filesystem discovery failed for one or more .testkit.ts files."],i=o.filter(t=>t.code==="legacy_path").map(t=>t.path),n=o.filter(t=>t.code==="ambiguous_test");if(i.length>0){e.push(""),e.push("Legacy test files outside __testkit__:");for(const t of i)e.push(`- ${t}`)}if(n.length>0){e.push(""),e.push("Ambiguous test files:");for(const t of n)e.push(`- ${t.path} -> ${t.groupNames.join(", ")}`)}return e.push(""),e.push('Expected test files to live under a "__testkit__" directory within a group root.'),new Error(e.join(`
2
+ `))}function $(o){const e=new Map,i=new Map;for(const n of o){const t=n._suitePath;let u="";for(let l=1;l<=t.length;l+=1){u=t.slice(-l).join("-");const c=e.get(u);if(!c){e.set(u,n._suiteKey);break}if(c===n._suiteKey)break;u=""}u||(u=t.join("-")),i.set(n._suiteKey,u)}if(new Set(i.values()).size!==o.length){const n=new Set;for(const t of o){const u=t._suitePath.join("-");let l=u;for(let c=2;n.has(l);c+=1)l=`${u}-${P(c)}`;n.add(l),i.set(t._suiteKey,l)}}return i}function j(o,e){const i=o.get(e);if(i===void 0)throw new Error(`Discovery suite name was not resolved for "${e}"`);return i}function K(o,e){const i=o.split("/").slice(0,-1);if(e===null)return i.length>0?i:[y.posix.basename(o).replace(PLAIN_TEST_SUFFIX,"")];const n=i.indexOf(w),t=n===-1?[]:[...i.slice(0,n),...i.slice(n+1,n+2)];return t.length>0?t:[y.posix.basename(o,e.suffix)]}function b(o){return N.find(e=>o.endsWith(e.suffix))||null}function x(o){const e=P(o).split(y.sep).join("/");return e==="."||e==="./"?".":e.replace(/^\.\/+/,"").replace(/\/+$/,"")||"."}function L(o){return o.map(e=>({code:"legacy_path",severity:"error",message:`Legacy test file outside __testkit__: ${e}`,path:e}))}
@@ -1 +1 @@
1
- import d from"fs";import p from"path";import{parseDotenv as m}from"../../process/files/dotenv.js";import{resolveServiceCwd as l}from"./paths.js";import{isUnknownArray as h,isUnknownRecord as w}from"../../kernel/unknown-values.js";export{m as parseDotenv};export function inferEnvFiles(n,e,r){const o=u(e,"service config"),v=u(r,"local config"),s=a(o?.envFile,"service.envFile"),f=g(o?.envFiles,"service.envFiles");if(s||f){const i=[];return s&&i.push(s),f&&i.push(...f),i}const t=[],c=a(v?.cwd,"service.local.cwd")??".";return c!=="."&&(t.push(p.posix.join(c,".env.testkit")),t.push(p.posix.join(c,".env"))),t.push(".env.testkit"),t.push(".env"),[...new Set(t)].map(i=>i.split(p.sep).join("/")).filter(i=>d.existsSync(l(n,i)))}export function loadServiceEnv(n,e){const r={};for(const o of e)Object.assign(r,m(l(n,o)));return r}function u(n,e){if(n!=null){if(!w(n))throw new Error(`${e} must be an object`);return n}}function a(n,e){if(n!=null){if(typeof n!="string"||n.trim().length===0)throw new Error(`${e} must be a non-empty string`);return n.trim()}}function g(n,e){if(n!=null){if(!h(n))throw new Error(`${e} must be an array of non-empty strings`);return n.map(r=>{if(typeof r!="string"||r.trim().length===0)throw new Error(`${e} must be an array of non-empty strings`);return r.trim()})}}
1
+ import h from"fs";import f from"path";import{parseDotenv as l}from"../../process/files/dotenv.js";import{resolveServiceCwd as m}from"./paths.js";import{isUnknownArray as d}from"../../kernel/unknown-values.js";import{normalizeOptionalRecord as v}from"../../evidence/artifact-config.js";export{l as parseDotenv};export function inferEnvFiles(e,t,n){const o=v(t,"service config"),a=v(n,"local config"),s=u(o?.envFile,"service.envFile"),p=w(o?.envFiles,"service.envFiles");if(s||p){const r=[];return s&&r.push(s),p&&r.push(...p),r}const i=[],c=u(a?.cwd,"service.local.cwd")??".";return c!=="."&&(i.push(f.posix.join(c,".env.testkit")),i.push(f.posix.join(c,".env"))),i.push(".env.testkit"),i.push(".env"),[...new Set(i)].map(r=>r.split(f.sep).join("/")).filter(r=>h.existsSync(m(e,r)))}export function loadServiceEnv(e,t){const n={};for(const o of t)Object.assign(n,l(m(e,o)));return n}export function withEnvFileValues(e){const t=e.testkit.envFiles??[];return t.length===0?e:{...e,testkit:{...e.testkit,serviceEnv:{...loadServiceEnv(e.productDir,t),...e.testkit.serviceEnv}}}}function u(e,t){if(e!=null){if(typeof e!="string"||e.trim().length===0)throw new Error(`${t} must be a non-empty string`);return e.trim()}}function w(e,t){if(e!=null){if(!d(e))throw new Error(`${t} must be an array of non-empty strings`);return e.map(n=>{if(typeof n!="string"||n.trim().length===0)throw new Error(`${t} must be an array of non-empty strings`);return n.trim()})}}
@@ -1 +1 @@
1
- import{isWorkObserved as M,recordWork as L}from"../../kernel/work-metrics.js";import{isPathWithin as h}from"../../process/files/paths.js";import d from"fs";import E from"path";import{createRequire as A}from"node:module";import{fileURLToPath as O}from"node:url";import{ENGINE_IDS as j,PUBLIC_TEST_TYPES as B,isEngineId as K}from"../../domain/identifiers.js";import{normalizeRuntimeIsolationPolicy as V}from"../../domain/runtime-isolation-contract.js";import{resolveEngineProfile as _,expectedEngineAuthoringModule as W,invalidEngineAuthoringImport as z,requireMatchingHostImport as U}from"../../engines/catalog.js";const G=A(import.meta.url),J=O(import.meta.resolve("typescript"));let H;function a(){return H??=G(J)}const g="@gfdelarue/testkit",X="@gfdelarue/testkit-engine-";export function loadTestFileMetadataMap(e,t={},i=new Map){for(const r of Object.values(t||{}))for(const s of Object.values(r||{}))for(const n of s||[])for(const o of n.files||[])i.has(o)||i.set(o,readTestFileMetadata(e,o));return i}export function readTestFileMetadata(e,t){const i=a(),r=Ee(e,t),s=ke(t);let n;if(M()){const m=d.readFileSync(r);L("metadata.filesRead",1),L("metadata.bytesRead",m.byteLength),n=m.toString("utf8")}else n=d.readFileSync(r,"utf8");const o=i.createSourceFile(r,n,i.ScriptTarget.Latest,!0,i.ScriptKind.TS),u=Ie(o);if(u.length>0){const m=u.map(f=>i.flattenDiagnosticMessageText(f.messageText," ")).join("; ");throw c(t,`TypeScript syntax is invalid: ${m}`)}let l=null,p=null;for(const m of o.statements)if(!(!i.isVariableStatement(m)||!ie(m))){for(const f of m.declarationList.declarations)if(!(!i.isIdentifier(f.name)||f.name.text!=="testkit")){if(l)throw c(t,'exported "testkit" metadata must be declared exactly once');if(!re(m))throw c(t,'exported "testkit" metadata must be const');l=f,p=m}}if(!l||!p)throw c(t,'export const testkit = defineFile({ engine: "..." }) is required');se(o,p,t);const S=Y(l.initializer,t,s);return requireMatchingEngineAuthoringImports(o,t,S),S}function Y(e,t,i){const r=a();if(!e)throw c(t,'exported "testkit" metadata has no value');if(!r.isCallExpression(e))throw c(t,"testkit metadata must use defineFile({ ... })");if(te(e.expression)!=="defineFile")throw c(t,"testkit metadata must call defineFile");if(e.arguments.length!==1)throw c(t,"defineFile metadata must receive exactly one object literal");const s=e.arguments[0];if(!r.isObjectLiteralExpression(s))throw c(t,"defineFile metadata must receive an object literal");return Q(s,t,i)}function Q(e,t,i){const r=a(),s={locks:[],runtimeIsolation:null,skipReason:null};let n=null;const o=new Set;for(const l of e.properties){if(r.isSpreadAssignment(l))throw c(t,"testkit metadata may not contain spread properties");if(!r.isPropertyAssignment(l))throw c(t,"testkit metadata properties must use key: value assignments");const p=b(l.name,t,"testkit metadata");if(!ne(p))throw c(t,`unknown metadata property "${p}"`);if(o.has(p))throw c(t,`duplicate metadata property "${p}"`);if(o.add(p),p==="engine"){n=I(l.initializer,t,'metadata property "engine"');continue}if(p==="locks"){s.locks=Z(l.initializer,t);continue}if(p==="skip"){s.skipReason=P(l.initializer,t);continue}s.runtimeIsolation=ee(l.initializer,t)}if(!n)throw c(t,'a literal "engine" property is required');if(!K(n))throw c(t,`unsupported engine "${n}"; expected one of: ${j.join(", ")}`);let u;try{u=_(i,n)}catch(l){throw c(t,$(l),l)}return{engineId:n,locks:s.locks,profileId:u.id,runtimeIsolation:s.runtimeIsolation,skipReason:s.skipReason}}function Z(e,t){const i=a();if(!i.isArrayLiteralExpression(e))throw c(t,'metadata property "locks" must be an array');const r=[];for(const s of e.elements){if(i.isSpreadElement(s)||i.isOmittedExpression(s))throw c(t,'metadata property "locks" must contain only string literals');r.push(T(s,t,'metadata property "locks" entry'))}return[...new Set(r)].sort()}function P(e,t){const i=a(),r=x(e);if(r!==null)return D(r,t,'metadata property "skip"').trim();if(!i.isObjectLiteralExpression(e))throw c(t,'metadata property "skip" must be a string literal or { reason: string literal }');if(e.properties.length!==1)throw c(t,'metadata property "skip" object must contain exactly one reason property');const s=e.properties[0];if(!i.isPropertyAssignment(s))throw c(t,'metadata property "skip" reason must use a string-literal assignment');if(b(s.name,t,'metadata property "skip"')!=="reason")throw c(t,'metadata property "skip" object only accepts "reason"');return T(s.initializer,t,'metadata property "skip.reason"')}function ee(e,t){const i=I(e,t,'metadata property "runtimeIsolation"');try{return V(i,"defineFile runtimeIsolation")}catch(r){throw c(t,$(r),r)}}function te(e){return a().isIdentifier(e)?e.text:null}function b(e,t,i){const r=a();if(r.isIdentifier(e)||r.isStringLiteral(e))return e.text;throw c(t,`${i} property names must be plain identifiers or string literals`)}function x(e){const t=a();return t.isStringLiteral(e)||t.isNoSubstitutionTemplateLiteral(e)?e.text:null}function I(e,t,i){const r=x(e);if(r===null)throw c(t,`${i} must be a string literal`);return D(r,t,i)}function T(e,t,i){return I(e,t,i).trim()}function D(e,t,i){if(e.trim().length===0)throw c(t,`${i} must not be empty`);return e}function ie(e){const t=a();return(e.modifiers||[]).some(i=>i.kind===t.SyntaxKind.ExportKeyword)}function re(e){const t=a();return(e.declarationList.flags&t.NodeFlags.Const)!==0}function ne(e){return["engine","locks","runtimeIsolation","skip"].includes(e)}function se(e,t,i){const r=a();let s=null,n=0;for(const o of e.statements){if(r.isImportDeclaration(o)){const u=o.importClause;if(!u||u.phaseModifier===r.SyntaxKind.TypeKeyword)continue;u.name?.text==="defineFile"&&(n+=1);const l=u.namedBindings;if(l&&r.isNamespaceImport(l)){l.name.text==="defineFile"&&(n+=1);continue}if(!l||!r.isNamedImports(l))continue;for(const p of l.elements){if(p.isTypeOnly||p.name.text!=="defineFile")continue;if(n+=1,(p.propertyName?.text??p.name.text)==="defineFile"&&r.isStringLiteral(o.moduleSpecifier)&&o.moduleSpecifier.text===g){if(s)throw c(i,`defineFile must have exactly one named value import from "${g}"`);s=o}}continue}n+=Se(o)}if(!s)throw c(i,`defineFile must be a named value import from "${g}"`);if(n!==1)throw c(i,"the imported defineFile binding may not be shadowed or redeclared");if(s.getStart(e)>t.getStart(e))throw c(i,"the defineFile import must precede metadata")}export function requireMatchingEngineAuthoringImports(e,t,i){oe(e,t,i);const r=W(i.profileId);for(const s of collectModuleSpecifiers(e))if(U(t,i,s),!(s===g||s===r||!s.startsWith(`${g}/`)&&!s.startsWith(X)))throw z(t,i,s,r)}function oe(e,t,i){const r=a(),s=N(e),n=o=>{if(ae(o,t,i),ce(o,s,t,i),r.isCallExpression(o)&&F(o,s)){const u=o.arguments.at(0);if(!u||!r.isStringLiteralLike(u)){const l=o.expression.kind===r.SyntaxKind.ImportKeyword?"import()":"require()";throw new Error(`Invalid Testkit authoring in "${t}": ${i.engineId}/${i.profileId} may not use non-literal ${l}; module specifiers must be string literals so engine boundaries can be verified`)}}for(const u of C(o))n(u);r.forEachChild(o,n)};n(e)}function F(e,t){const i=a();return e.expression.kind===i.SyntaxKind.ImportKeyword||i.isIdentifier(e.expression)&&e.expression.text==="require"&&!k(e.expression,t)}function ae(e,t,i){const r=a();if(r.isImportDeclaration(e)){const n=e.importClause?.namedBindings;if(n&&r.isNamedImports(n)&&n.elements.find(u=>!u.isTypeOnly&&(u.propertyName?.text??u.name.text)==="createRequire"))throw y(t,i,"createRequire")}if(r.isPropertyAccessExpression(e)&&e.name.text==="createRequire"||r.isElementAccessExpression(e)&&x(e.argumentExpression)==="createRequire"||r.isBindingElement(e)&&(me(e)==="createRequire"||r.isIdentifier(e.name)&&e.name.text==="createRequire"))throw y(t,i,"createRequire")}function ce(e,t,i,r){const s=a();if(s.isPropertyAccessExpression(e)&&e.name.text==="require"&&q(e.expression,t)||s.isElementAccessExpression(e)&&x(e.argumentExpression)==="require"&&q(e.expression,t))throw y(i,r,e.getText());if(s.isIdentifier(e)&&e.text==="require"&&!k(e,t)&&!ue(e)&&!le(e))throw y(i,r,"global require")}function y(e,t,i){return new Error(`Invalid Testkit authoring in "${e}": ${t.engineId}/${t.profileId} may not alias or indirectly access the module loader through ${i}; use literal import and require specifiers so engine boundaries can be verified`)}function q(e,t){return a().isIdentifier(e)&&(e.text==="globalThis"||e.text==="module")&&!k(e,t)}function ue(e){return a().isCallExpression(e.parent)&&e.parent.expression===e}function le(e){const t=a(),i=e.parent;return pe(e)||t.isPropertyAccessExpression(i)&&i.name===e||t.isPropertyAssignment(i)&&i.name===e||t.isImportSpecifier(i)&&i.propertyName===e||t.isExportSpecifier(i)&&i.parent.parent.moduleSpecifier!==void 0}function pe(e){const t=a(),i=e.parent;return i.name===e&&!t.isShorthandPropertyAssignment(i)&&!t.isExportSpecifier(i)}function me(e){const t=a(),i=e.propertyName;return i&&(t.isIdentifier(i)||t.isStringLiteralLike(i))?i.text:null}function N(e){const t=a(),i=new WeakMap,r=(n,o)=>{let u=i.get(n);u||(u=new Set,i.set(n,u)),v(u,o)},s=n=>{if(t.isImportDeclaration(n))fe(n,e,r);else if(t.isImportEqualsDeclaration(n)&&!n.isTypeOnly)r(e,n.name);else if(t.isVariableDeclaration(n)){const o=n.parent,u=t.isVariableDeclarationList(o)&&(o.flags&t.NodeFlags.BlockScoped)===0?de(n):w(n);r(u,n.name)}else t.isParameter(n)?r(ge(n),n.name):t.isFunctionDeclaration(n)&&n.name?r(w(n),n.name):t.isFunctionExpression(n)&&n.name?r(n,n.name):(t.isClassDeclaration(n)||t.isEnumDeclaration(n)||t.isModuleDeclaration(n))&&n.name&&t.isIdentifier(n.name)?r(w(n),n.name):t.isClassExpression(n)&&n.name?r(n,n.name):t.isCatchClause(n)&&n.variableDeclaration&&r(n,n.variableDeclaration.name);t.forEachChild(n,s)};return s(e),i}function fe(e,t,i){const r=a(),s=e.importClause;if(!s||s.phaseModifier===r.SyntaxKind.TypeKeyword)return;s.name&&i(t,s.name);const n=s.namedBindings;if(n&&r.isNamespaceImport(n))i(t,n.name);else if(n&&r.isNamedImports(n))for(const o of n.elements)o.isTypeOnly||i(t,o.name)}function v(e,t){const i=a();if(i.isIdentifier(t)){e.add(t.text);return}for(const r of t.elements)i.isOmittedExpression(r)||v(e,r.name)}function k(e,t){const i=a();let r=e;for(;;){if(t.get(r)?.has(e.text))return!0;if(i.isSourceFile(r))return!1;r=r.parent}}function w(e){let t=e.parent;for(;;){if(ye(t))return t;t=t.parent}}function de(e){const t=a();let i=e.parent;for(;;){if(t.isFunctionLike(i)||t.isSourceFile(i))return i;i=i.parent}}function ge(e){const t=a();let i=e.parent;for(;;){if(t.isFunctionLike(i)||t.isSourceFile(i))return i;i=i.parent}}function ye(e){const t=a();return t.isSourceFile(e)||t.isBlock(e)||t.isCaseBlock(e)||t.isCatchClause(e)||t.isForStatement(e)||t.isForInStatement(e)||t.isForOfStatement(e)||t.isFunctionLike(e)||t.isClassStaticBlockDeclaration(e)}export function collectModuleSpecifiers(e){const t=a(),i=new Set,r=N(e),s=n=>{const o=xe(n,r);o&&i.add(o);for(const u of C(n))s(u);t.forEachChild(n,s)};return s(e),i}function C(e){return e.jsDoc??[]}function xe(e,t){const i=a();if(i.isJSDocImportTag(e)&&i.isStringLiteralLike(e.moduleSpecifier)||(i.isImportDeclaration(e)||i.isExportDeclaration(e))&&e.moduleSpecifier&&i.isStringLiteralLike(e.moduleSpecifier))return e.moduleSpecifier.text;if(i.isImportEqualsDeclaration(e)&&i.isExternalModuleReference(e.moduleReference)&&i.isStringLiteralLike(e.moduleReference.expression))return e.moduleReference.expression.text;if(i.isImportTypeNode(e)){const s=e.argument;if(i.isLiteralTypeNode(s)&&i.isStringLiteralLike(s.literal))return s.literal.text}if(!i.isCallExpression(e)||!F(e,t))return null;const r=e.arguments[0];return i.isStringLiteralLike(r)?r.text:null}function Se(e){const t=a();return t.isVariableStatement(e)?e.declarationList.declarations.reduce((i,r)=>i+R(r.name,"defineFile"),0):(t.isClassDeclaration(e)||t.isEnumDeclaration(e)||t.isFunctionDeclaration(e))&&e.name?.text==="defineFile"?1:0}function R(e,t){const i=a();return i.isIdentifier(e)?e.text===t?1:0:e.elements.reduce((r,s)=>i.isOmittedExpression(s)?r:r+R(s.name,t),0)}function Ee(e,t){const i=E.resolve(e);if(E.isAbsolute(t))throw new Error(`Test file metadata path must be product-relative: ${t}`);const r=E.resolve(i,t);if(!h(i,r))throw new Error(`Test file metadata path escapes the product root: ${t}`);if(!d.existsSync(r))throw new Error(`Test file metadata source does not exist: ${t}`);const s=d.realpathSync(i),n=d.realpathSync(r);if(!h(s,n))throw new Error(`Test file metadata path resolves outside the product root: ${t}`);return n}function Ie(e){return e.parseDiagnostics??[]}function ke(e){const t=B.find(i=>e.endsWith(`.${i}.testkit.ts`));if(t)return t;throw new Error(`Cannot read Testkit file metadata from noncanonical path: ${e}`)}function c(e,t,i){return new Error(`Invalid testkit metadata in "${e}": ${t}.`,{cause:i})}function $(e){return e instanceof Error?e.message.replace(/\.$/u,""):String(e)}
1
+ import{isWorkObserved as $,recordWork as L}from"../../kernel/work-metrics.js";import{isPathWithin as h}from"../../process/files/paths.js";import d from"fs";import S from"path";import{createRequire as A}from"node:module";import{fileURLToPath as B}from"node:url";import{ENGINE_IDS as O,PUBLIC_TEST_TYPES as j,isEngineId as K}from"../../domain/identifiers.js";import{normalizeRuntimeIsolationPolicy as V}from"../../domain/runtime-isolation-contract.js";import{resolveEngineProfile as W,allowsEngineAuthoringImport as _,expectedEngineAuthoringModule as z,invalidEngineAuthoringImport as U,requireMatchingEngineImport as G}from"../../engines/catalog.js";const J=A(import.meta.url),Y=B(import.meta.resolve("typescript"));let H;function a(){return H??=J(Y)}const I="@gfdelarue/testkit";export function loadTestFileMetadataMap(e,t={},i=new Map){for(const r of Object.values(t||{}).flatMap(s=>s??[]))for(const s of r.files||[])i.has(s)||i.set(s,readTestFileMetadata(e,s));return i}export function readTestFileMetadata(e,t){const i=j.find(m=>t.endsWith(`.${m}.testkit.ts`));if(i===void 0)return{engineId:"node-vitest",locks:[],profileId:"node-vitest",runtimeIsolation:null,skipReason:null};const r=a(),s=Ie(e,t);let n;if($()){const m=d.readFileSync(s);L("metadata.filesRead",1),L("metadata.bytesRead",m.byteLength),n=m.toString("utf8")}else n=d.readFileSync(s,"utf8");const o=r.createSourceFile(s,n,r.ScriptTarget.Latest,!0,r.ScriptKind.TS),l=ke(o);if(l.length>0){const m=l.map(f=>r.flattenDiagnosticMessageText(f.messageText," ")).join("; ");throw c(t,`TypeScript syntax is invalid: ${m}`)}let u=null,p=null;for(const m of o.statements)if(!(!r.isVariableStatement(m)||!ie(m))){for(const f of m.declarationList.declarations)if(!(!r.isIdentifier(f.name)||f.name.text!=="testkit")){if(u)throw c(t,'exported "testkit" metadata must be declared exactly once');if(!re(m))throw c(t,'exported "testkit" metadata must be const');u=f,p=m}}if(!u||!p)throw c(t,'export const testkit = defineFile({ engine: "..." }) is required');se(o,p,t);const x=Q(u.initializer,t,i);return requireMatchingEngineAuthoringImports(o,t,x),x}function Q(e,t,i){const r=a();if(!e)throw c(t,'exported "testkit" metadata has no value');if(!r.isCallExpression(e))throw c(t,"testkit metadata must use defineFile({ ... })");if(te(e.expression)!=="defineFile")throw c(t,"testkit metadata must call defineFile");if(e.arguments.length!==1)throw c(t,"defineFile metadata must receive exactly one object literal");const s=e.arguments[0];if(!r.isObjectLiteralExpression(s))throw c(t,"defineFile metadata must receive an object literal");return X(s,t,i)}function X(e,t,i){const r=a(),s={locks:[],runtimeIsolation:null,skipReason:null};let n=null;const o=new Set;for(const u of e.properties){if(r.isSpreadAssignment(u))throw c(t,"testkit metadata may not contain spread properties");if(!r.isPropertyAssignment(u))throw c(t,"testkit metadata properties must use key: value assignments");const p=b(u.name,t,"testkit metadata");if(!ne(p))throw c(t,`unknown metadata property "${p}"`);if(o.has(p))throw c(t,`duplicate metadata property "${p}"`);if(o.add(p),p==="engine"){n=k(u.initializer,t,'metadata property "engine"');continue}if(p==="locks"){s.locks=Z(u.initializer,t);continue}if(p==="skip"){s.skipReason=P(u.initializer,t);continue}s.runtimeIsolation=ee(u.initializer,t)}if(!n)throw c(t,'a literal "engine" property is required');if(!K(n))throw c(t,`unsupported engine "${n}"; expected one of: ${O.join(", ")}`);let l;try{l=W(i,n)}catch(u){throw c(t,M(u),u)}return{engineId:n,locks:s.locks,profileId:l.id,runtimeIsolation:s.runtimeIsolation,skipReason:s.skipReason}}function Z(e,t){const i=a();if(!i.isArrayLiteralExpression(e))throw c(t,'metadata property "locks" must be an array');const r=[];for(const s of e.elements){if(i.isSpreadElement(s)||i.isOmittedExpression(s))throw c(t,'metadata property "locks" must contain only string literals');r.push(D(s,t,'metadata property "locks" entry'))}return[...new Set(r)].sort()}function P(e,t){const i=a(),r=y(e);if(r!==null)return F(r,t,'metadata property "skip"').trim();if(!i.isObjectLiteralExpression(e))throw c(t,'metadata property "skip" must be a string literal or { reason: string literal }');if(e.properties.length!==1)throw c(t,'metadata property "skip" object must contain exactly one reason property');const s=e.properties[0];if(!i.isPropertyAssignment(s))throw c(t,'metadata property "skip" reason must use a string-literal assignment');if(b(s.name,t,'metadata property "skip"')!=="reason")throw c(t,'metadata property "skip" object only accepts "reason"');return D(s.initializer,t,'metadata property "skip.reason"')}function ee(e,t){const i=k(e,t,'metadata property "runtimeIsolation"');try{return V(i,"defineFile runtimeIsolation")}catch(r){throw c(t,M(r),r)}}function te(e){return a().isIdentifier(e)?e.text:null}function b(e,t,i){const r=a();if(r.isIdentifier(e)||r.isStringLiteral(e))return e.text;throw c(t,`${i} property names must be plain identifiers or string literals`)}function y(e){const t=a();return t.isStringLiteral(e)||t.isNoSubstitutionTemplateLiteral(e)?e.text:null}function k(e,t,i){const r=y(e);if(r===null)throw c(t,`${i} must be a string literal`);return F(r,t,i)}function D(e,t,i){return k(e,t,i).trim()}function F(e,t,i){if(e.trim().length===0)throw c(t,`${i} must not be empty`);return e}function ie(e){const t=a();return(e.modifiers||[]).some(i=>i.kind===t.SyntaxKind.ExportKeyword)}function re(e){const t=a();return(e.declarationList.flags&t.NodeFlags.Const)!==0}function ne(e){return["engine","locks","runtimeIsolation","skip"].includes(e)}function se(e,t,i){const r=a();let s=null,n=0;for(const o of e.statements){if(r.isImportDeclaration(o)){const l=o.importClause;if(!l||l.phaseModifier===r.SyntaxKind.TypeKeyword)continue;l.name?.text==="defineFile"&&(n+=1);const u=l.namedBindings;if(u&&r.isNamespaceImport(u)){u.name.text==="defineFile"&&(n+=1);continue}if(!u||!r.isNamedImports(u))continue;for(const p of u.elements){if(p.isTypeOnly||p.name.text!=="defineFile")continue;if(n+=1,(p.propertyName?.text??p.name.text)==="defineFile"&&r.isStringLiteral(o.moduleSpecifier)&&o.moduleSpecifier.text===I){if(s)throw c(i,`defineFile must have exactly one named value import from "${I}"`);s=o}}continue}n+=Se(o)}if(!s)throw c(i,`defineFile must be a named value import from "${I}"`);if(n!==1)throw c(i,"the imported defineFile binding may not be shadowed or redeclared");if(s.getStart(e)>t.getStart(e))throw c(i,"the defineFile import must precede metadata")}export function requireMatchingEngineAuthoringImports(e,t,i){oe(e,t,i);const r=z(i.profileId);for(const s of collectModuleSpecifiers(e))if(G(t,i,s),!_(r,s))throw U(t,i,s,r)}function oe(e,t,i){const r=a(),s=q(e),n=o=>{if(ae(o,t,i),ce(o,s,t,i),r.isCallExpression(o)&&T(o,s)){const l=o.arguments.at(0);if(!l||!r.isStringLiteralLike(l)){const u=o.expression.kind===r.SyntaxKind.ImportKeyword?"import()":"require()";throw new Error(`Invalid Testkit authoring in "${t}": ${i.engineId}/${i.profileId} may not use non-literal ${u}; module specifiers must be string literals so engine boundaries can be verified`)}}for(const l of C(o))n(l);r.forEachChild(o,n)};n(e)}function T(e,t){const i=a();return e.expression.kind===i.SyntaxKind.ImportKeyword||i.isIdentifier(e.expression)&&e.expression.text==="require"&&!E(e.expression,t)}function ae(e,t,i){const r=a();if(r.isImportDeclaration(e)){const n=e.importClause?.namedBindings;if(n&&r.isNamedImports(n)&&n.elements.find(l=>!l.isTypeOnly&&(l.propertyName?.text??l.name.text)==="createRequire"))throw g(t,i,"createRequire")}if(r.isPropertyAccessExpression(e)&&e.name.text==="createRequire"||r.isElementAccessExpression(e)&&y(e.argumentExpression)==="createRequire"||r.isBindingElement(e)&&(me(e)==="createRequire"||r.isIdentifier(e.name)&&e.name.text==="createRequire"))throw g(t,i,"createRequire")}function ce(e,t,i,r){const s=a();if(s.isPropertyAccessExpression(e)&&e.name.text==="require"&&v(e.expression,t)||s.isElementAccessExpression(e)&&y(e.argumentExpression)==="require"&&v(e.expression,t))throw g(i,r,e.getText());if(s.isIdentifier(e)&&e.text==="require"&&!E(e,t)&&!le(e)&&!ue(e))throw g(i,r,"global require")}function g(e,t,i){return new Error(`Invalid Testkit authoring in "${e}": ${t.engineId}/${t.profileId} may not alias or indirectly access the module loader through ${i}; use literal import and require specifiers so engine boundaries can be verified`)}function v(e,t){return a().isIdentifier(e)&&(e.text==="globalThis"||e.text==="module")&&!E(e,t)}function le(e){return a().isCallExpression(e.parent)&&e.parent.expression===e}function ue(e){const t=a(),i=e.parent;return pe(e)||t.isPropertyAccessExpression(i)&&i.name===e||t.isPropertyAssignment(i)&&i.name===e||t.isImportSpecifier(i)&&i.propertyName===e||t.isExportSpecifier(i)&&i.parent.parent.moduleSpecifier!==void 0}function pe(e){const t=a(),i=e.parent;return i.name===e&&!t.isShorthandPropertyAssignment(i)&&!t.isExportSpecifier(i)}function me(e){const t=a(),i=e.propertyName;return i&&(t.isIdentifier(i)||t.isStringLiteralLike(i))?i.text:null}function q(e){const t=a(),i=new WeakMap,r=(n,o)=>{let l=i.get(n);l||(l=new Set,i.set(n,l)),N(l,o)},s=n=>{if(t.isImportDeclaration(n))fe(n,e,r);else if(t.isImportEqualsDeclaration(n)&&!n.isTypeOnly)r(e,n.name);else if(t.isVariableDeclaration(n)){const o=n.parent,l=t.isVariableDeclarationList(o)&&(o.flags&t.NodeFlags.BlockScoped)===0?de(n):w(n);r(l,n.name)}else t.isParameter(n)?r(ge(n),n.name):t.isFunctionDeclaration(n)&&n.name?r(w(n),n.name):t.isFunctionExpression(n)&&n.name?r(n,n.name):(t.isClassDeclaration(n)||t.isEnumDeclaration(n)||t.isModuleDeclaration(n))&&n.name&&t.isIdentifier(n.name)?r(w(n),n.name):t.isClassExpression(n)&&n.name?r(n,n.name):t.isCatchClause(n)&&n.variableDeclaration&&r(n,n.variableDeclaration.name);t.forEachChild(n,s)};return s(e),i}function fe(e,t,i){const r=a(),s=e.importClause;if(!s||s.phaseModifier===r.SyntaxKind.TypeKeyword)return;s.name&&i(t,s.name);const n=s.namedBindings;if(n&&r.isNamespaceImport(n))i(t,n.name);else if(n&&r.isNamedImports(n))for(const o of n.elements)o.isTypeOnly||i(t,o.name)}function N(e,t){const i=a();if(i.isIdentifier(t)){e.add(t.text);return}for(const r of t.elements)i.isOmittedExpression(r)||N(e,r.name)}function E(e,t){const i=a();let r=e;for(;;){if(t.get(r)?.has(e.text))return!0;if(i.isSourceFile(r))return!1;r=r.parent}}function w(e){let t=e.parent;for(;;){if(ye(t))return t;t=t.parent}}function de(e){const t=a();let i=e.parent;for(;;){if(t.isFunctionLike(i)||t.isSourceFile(i))return i;i=i.parent}}function ge(e){const t=a();let i=e.parent;for(;;){if(t.isFunctionLike(i)||t.isSourceFile(i))return i;i=i.parent}}function ye(e){const t=a();return t.isSourceFile(e)||t.isBlock(e)||t.isCaseBlock(e)||t.isCatchClause(e)||t.isForStatement(e)||t.isForInStatement(e)||t.isForOfStatement(e)||t.isFunctionLike(e)||t.isClassStaticBlockDeclaration(e)}export function collectModuleSpecifiers(e){const t=a(),i=new Set,r=q(e),s=n=>{const o=xe(n,r);o&&i.add(o);for(const l of C(n))s(l);t.forEachChild(n,s)};return s(e),i}function C(e){return e.jsDoc??[]}function xe(e,t){const i=a();if(i.isJSDocImportTag(e)&&i.isStringLiteralLike(e.moduleSpecifier)||(i.isImportDeclaration(e)||i.isExportDeclaration(e))&&e.moduleSpecifier&&i.isStringLiteralLike(e.moduleSpecifier))return e.moduleSpecifier.text;if(i.isImportEqualsDeclaration(e)&&i.isExternalModuleReference(e.moduleReference)&&i.isStringLiteralLike(e.moduleReference.expression))return e.moduleReference.expression.text;if(i.isImportTypeNode(e)){const s=e.argument;if(i.isLiteralTypeNode(s)&&i.isStringLiteralLike(s.literal))return s.literal.text}if(!i.isCallExpression(e)||!T(e,t))return null;const r=e.arguments[0];return i.isStringLiteralLike(r)?r.text:null}function Se(e){const t=a();return t.isVariableStatement(e)?e.declarationList.declarations.reduce((i,r)=>i+R(r.name,"defineFile"),0):(t.isClassDeclaration(e)||t.isEnumDeclaration(e)||t.isFunctionDeclaration(e))&&e.name?.text==="defineFile"?1:0}function R(e,t){const i=a();return i.isIdentifier(e)?e.text===t?1:0:e.elements.reduce((r,s)=>i.isOmittedExpression(s)?r:r+R(s.name,t),0)}function Ie(e,t){const i=S.resolve(e);if(S.isAbsolute(t))throw new Error(`Test file metadata path must be product-relative: ${t}`);const r=S.resolve(i,t);if(!h(i,r))throw new Error(`Test file metadata path escapes the product root: ${t}`);if(!d.existsSync(r))throw new Error(`Test file metadata source does not exist: ${t}`);const s=d.realpathSync(i),n=d.realpathSync(r);if(!h(s,n))throw new Error(`Test file metadata path resolves outside the product root: ${t}`);return n}function ke(e){return e.parseDiagnostics??[]}function c(e,t,i){return new Error(`Invalid testkit metadata in "${e}": ${t}.`,{cause:i})}function M(e){return e instanceof Error?e.message.replace(/\.$/u,""):String(e)}
@@ -1 +1,2 @@
1
- import p from"node:path";import{requireServiceName as O}from"../../domain/service-name.js";import{errorMessage as m}from"../../kernel/error-serialization.js";import{isUnknownRecord as y}from"../../kernel/unknown-values.js";import{normalizeDiscoveryConfig as S}from"./decode-discovery.js";import{DEFAULT_DISCOVERY_EXCLUDES as C,shouldExcludeDiscoveryPath as w}from"./path-policy.js";import{readProperty as f}from"./values.js";export const ROOT_GROUP="root",LEGACY_OWNERSHIP_NOTICE="testkit.config.ts has services but no groups, so each service owns the tests under its directory as a group of the same name. Legacy ownership will be removed; declare groups with roots and uses instead.";export function resolveGroups(e,t){const s=[],r=G(e,s),i=e&&Object.hasOwn(e,"groups")?b(f(e,"groups"),r,s):z(r,s),o=$(f(e,"discovery"),null,s),c=[...C,...(o.exclude??[]).map(h)],a=t.map(n=>A(n,i.rules,c)),l=new Set(i.groups.filter(n=>n.source==="services").map(n=>n.name));return{assignments:a,groups:[...i.groups,{name:ROOT_GROUP,roots:["."],source:"implicit",uses:[]}],notice:a.some(n=>n.status==="owned"&&l.has(n.group))?LEGACY_OWNERSHIP_NOTICE:null,problems:s}}function A(e,t,s){const r=L(e.path);if(w(r,s))return{path:r,status:"excluded"};const i=t.filter(u=>u.prefix===null||v(r,u.prefix)),o=i.filter(u=>!w(r,u.exclude));if(i.length>0&&o.length===0)return{path:r,status:"excluded"};const c=o.filter(u=>e.kind==="typed"||!u.typedOnly);if(c.length===0)return{group:ROOT_GROUP,path:r,relativePath:r,status:"owned"};const a=Math.max(...c.map(u=>u.depth)),l=c.filter(u=>u.depth===a),n=[...new Set(l.map(u=>u.group))].sort((u,d)=>u.localeCompare(d));return n.length>1?{groups:n,path:r,status:"ambiguous"}:{group:n[0],path:r,relativePath:R(l[0],r),status:"owned"}}function b(e,t,s){const r={groups:[],rules:[]};if(!y(e))return s.push("testkit.config.ts groups must be an object"),r;for(const[i,o]of Object.entries(e)){const c=`groups.${i}`;if(i===ROOT_GROUP){s.push(`${c} is reserved for the implicit group that owns files no other group claims; rename it`);continue}try{O(i,`Group name "${i}"`)}catch(n){s.push(m(n));continue}if(!y(o)){s.push(`${c} must be an object with roots`);continue}const a=x(o.roots,`${c}.roots`,!0,s),l=x(o.exclude,`${c}.exclude`,!1,s);r.groups.push({name:i,roots:a,source:"groups",uses:j(o.uses,c,t,s)});for(const n of a)r.rules.push({depth:n==="."?0:n.split("/").length,exclude:l,group:i,legacyCwd:null,prefix:n==="."?null:n,typedOnly:!1})}return r}function x(e,t,s,r){if(e===void 0&&!s)return[];if(!Array.isArray(e)||s&&e.length===0)return r.push(`${t} must be ${s?"a non-empty array":"an array"} of repo-relative paths`),[];const i=e,o=new Set;for(const c of i){const a=P(c);a===null?r.push(`${t} entry ${JSON.stringify(c)} must be a relative path inside the product directory`):o.add(a)}return[...o]}function j(e,t,s,r){if(e===void 0)return[];if(!D(e))return r.push(`${t}.uses must be an array of service names`),[];const i=[];for(const o of new Set(e))Object.hasOwn(s,o)?i.push(o):r.push(`${t}.uses names "${o}", which is not a service; declare services.${o} or remove it from ${t}.uses`);return i}function z(e,t){const s={groups:[],rules:[]};for(const[r,i]of Object.entries(e)){if(r===ROOT_GROUP){t.push("services.root is reserved for the implicit group that owns files no other group claims; rename the service");continue}const o=E(i,r,t),c=$(f(i,"discovery"),r,t),a=c.roots&&c.roots.length>0?c.roots:["."],l=(c.exclude??[]).map(u=>h(o==="."?u:p.posix.join(o,u))),n=a.map(u=>{const d=h(u),g=o==="."?d:d==="."?o:h(p.posix.join(o,d));return{depth:g==="."?0:g.split("/").filter(Boolean).length,exclude:l,group:r,legacyCwd:o==="."?null:o,prefix:g==="."?null:g,typedOnly:!0}});s.rules.push(...n),s.groups.push({name:r,roots:[...new Set(n.map(u=>u.prefix??"."))],source:"services",uses:[r]})}return s}function E(e,t,s){const r=f(f(e,"local"),"cwd");return r===void 0?".":typeof r!="string"?(s.push(`Service "${t}" local.cwd must be a string`),"."):h(r||".")}function G(e,t){const s=f(e,"services");return s==null?{}:y(s)?s:(t.push("testkit.config.ts services must be an object"),{})}function $(e,t,s){try{return S(e,{allowRoots:!0})}catch(r){return s.push(t===null?m(r):`Service "${t}" has invalid discovery config: ${m(r)}`),{}}}function R(e,t){return e.prefix!==null&&v(t,e.prefix)?p.posix.relative(e.prefix,t):e.legacyCwd!==null&&v(t,e.legacyCwd)?p.posix.relative(e.legacyCwd,t):t}function D(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function v(e,t){return e===t||e.startsWith(`${t}/`)}function P(e){if(typeof e!="string")return null;const t=e.trim(),s=t.replaceAll("\\","/");if(s===""||p.posix.isAbsolute(s)||p.win32.isAbsolute(t))return null;const r=p.posix.normalize(s).replace(/\/+$/u,"")||".";return r===".."||r.startsWith("../")?null:r}function L(e){return p.posix.normalize(e.replaceAll("\\","/")).replace(/\/+$/u,"")}function h(e){const t=e.split(p.sep).join("/");return t==="."||t==="./"?".":t.replace(/^\.\/+/u,"").replace(/\/+$/u,"")||"."}
1
+ import f from"node:path";import{migrationText as P}from"../../domain/retired-test-types.js";import{requireServiceName as b}from"../../domain/service-name.js";import{errorMessage as x}from"../../kernel/error-serialization.js";import{unknownKeysMessage as A}from"../../kernel/known-keys.js";import{isUnknownRecord as h,readDynamicProperty as a}from"../../kernel/unknown-values.js";import{DATABASE_FIXTURE_DISCOVERY as D}from"../authoring/database-fixture-discovery.js";import{normalizeDiscoveryConfig as k}from"./decode-discovery.js";import{DEFAULT_DISCOVERY_EXCLUDES as z,shouldExcludeDiscoveryPath as m}from"./path-policy.js";const E=String,R=Object.keys({exclude:!0,requirements:!0,roots:!0,runtimeIsolation:!0,skip:!0,uses:!0});export const ROOT_GROUP="root";export function resolveGroups(e,r){const t=[],s=g(a(e,"discovery"),t),i=T(e,t),u=(s.exclude??[]).map(d),n=[...z,...u],o=e!=null&&Object.hasOwn(e,"groups"),p=o?G(a(e,"groups"),i,t):{groups:[],rules:[]};return o&&t.push(...C(i,p.groups)),{assignments:r.map(l=>v(l,p.rules,l.kind==="typed"?n:u)),groups:[...p.groups,{name:ROOT_GROUP,roots:["."],source:"implicit",uses:[]}],migration:o?null:I(i,r,n),problems:t}}export function readDiscoveryScan(e){return g(a(e,"discovery"),[])}export function repoDiscoveryProblem(e){const r=[];return g(a(e,"discovery"),r),r[0]??null}function v(e,r,t){const s=F(e.path);if(m(s,t))return{path:s,status:"excluded"};const i=r.filter(c=>c.prefix===null||O(s,c.prefix)),u=i.filter(c=>!m(s,c.exclude));if(i.length>0&&u.length===0)return{path:s,status:"excluded"};if(u.length===0)return{group:ROOT_GROUP,path:s,relativePath:s,status:"owned"};const n=Math.max(...u.map(c=>c.depth)),o=u.filter(c=>c.depth===n),p=[...new Set(o.map(c=>c.group))].sort((c,j)=>c.localeCompare(j));if(p.length>1)return{groups:p,path:s,status:"ambiguous"};const l=o[0].prefix;return{group:p[0],path:s,relativePath:l===null?s:f.posix.relative(l,s),status:"owned"}}function G(e,r,t){const s={groups:[],rules:[]};if(!h(e))return t.push("testkit.config.ts groups must be an object"),s;for(const[i,u]of Object.entries(e)){const n=`groups.${i}`;if(i===ROOT_GROUP){t.push(`${n} is reserved for the implicit group that owns files no other group claims; rename it`);continue}try{b(i,`Group name "${i}"`)}catch(c){t.push(x(c));continue}if(!h(u)){t.push(`${n} must be an object with roots`);continue}const o=A(u,R,n);o!==null&&t.push(o);const p=w(u.roots,`${n}.roots`,!0,t),l=w(u.exclude,`${n}.exclude`,!1,t);s.groups.push({name:i,roots:p,source:"groups",uses:U(u.uses,n,r,t)});for(const c of p)s.rules.push({depth:c==="."?0:c.split("/").length,exclude:l,group:i,prefix:c==="."?null:c})}return s}const _=["skip","requirements","runtimeIsolation"];function C(e,r){return Object.entries(e).flatMap(([t,s])=>{const i=r.find(o=>o.uses.includes(t))?.name??t,u=_.filter(o=>a(s,o)!==void 0).map(o=>`services.${t}.${o} applies to tests, and services own no tests when groups is set; move it to groups.${i}.${o}`),n=a(s,"discovery");return n!==void 0&&!L(n)&&u.push(`services.${t}.discovery applies to tests, and services own no tests when groups is set; move its roots and exclude to groups.${i}.roots and groups.${i}.exclude, as paths from the product directory`),u})}function L(e){return h(e)&&JSON.stringify(e)===JSON.stringify(D)}function w(e,r,t,s){if(e===void 0&&!t)return[];if(!Array.isArray(e)||t&&e.length===0)return s.push(`${r} must be ${t?"a non-empty array":"an array"} of repo-relative paths`),[];const i=e,u=new Set;for(const n of i){const o=S(n);o===null?s.push(`${r} entry ${JSON.stringify(n)} must be a relative path inside the product directory`):u.add(o)}return[...u]}function U(e,r,t,s){if(e===void 0)return[];if(!J(e))return s.push(`${r}.uses must be an array of service names`),[];const i=[];for(const u of new Set(e))Object.hasOwn(t,u)?i.push(u):s.push(`${r}.uses names "${u}", which is not a service; declare services.${u} or remove it from ${r}.uses`);return i}function I(e,r,t){const s=Object.entries(e).flatMap(([n,o])=>M(n,o)),i=new Set;for(const n of r){if(n.kind!=="typed")continue;const o=v(n,s,t);if(o.status==="ambiguous")for(const p of o.groups)i.add(p);if(o.status==="owned"&&o.group!==ROOT_GROUP&&i.add(o.group),o.status==="excluded"&&!m(o.path,t))for(const p of s)(p.prefix===null||O(o.path,p.prefix))&&i.add(p.group)}return i.size===0?null:["testkit.config.ts has services and no groups. Testkit 0.6.0 removed legacy service ownership, so services no longer own the test files under their directories. Add these groups to keep each typed test file with the service that owned it:","","groups: {",...Object.keys(e).filter(n=>i.has(n)).map(n=>{const o=s.filter(c=>c.group===n),p=o[0].exclude.filter($),l=[`roots: ${y([...new Set(o.map(c=>c.prefix??"."))].filter($))}`,`uses: ${y([n])}`,...p.length>0?[`exclude: ${y(p)}`]:[]];return` ${/^[A-Za-z_$][\w$]*$/u.test(n)?n:JSON.stringify(n)}: { ${l.join(", ")} },`}),"},","","A group also owns the plain Vitest files under its roots.",`${P("Remove legacy service ownership")}.`].join(`
2
+ `)}function M(e,r){if(e===ROOT_GROUP)return[];const t=g(a(r,"discovery"),null);if(t===null)return[];const s=N(r),i=(t.exclude??[]).map(u=>d(s==="."?u:f.posix.join(s,u)));return(t.roots&&t.roots.length>0?t.roots:["."]).map(u=>{const n=d(u),o=s==="."?n:n==="."?s:d(f.posix.join(s,n));return{depth:o==="."?0:o.split("/").filter(Boolean).length,exclude:i,group:e,prefix:o==="."?null:o}})}function $(e){return S(e)!==null}function y(e){return`[${e.map(r=>JSON.stringify(r)).join(", ")}]`}function N(e){return d(E(a(a(e,"local"),"cwd")||"."))}function T(e,r){const t=a(e,"services");return t==null?{}:h(t)?t:(r.push("testkit.config.ts services must be an object"),{})}function g(e,r){try{return k(e,{allowRoots:!0})}catch(t){return r===null?null:(r.push(x(t)),{})}}function J(e){return Array.isArray(e)&&e.every(r=>typeof r=="string")}function O(e,r){return e===r||e.startsWith(`${r}/`)}function S(e){if(typeof e!="string")return null;const r=e.trim(),t=r.replaceAll("\\","/");if(t===""||f.posix.isAbsolute(t)||f.win32.isAbsolute(r))return null;const s=f.posix.normalize(t).replace(/\/+$/u,"")||".";return s===".."||s.startsWith("../")?null:s}function F(e){return f.posix.normalize(e.split(f.sep).join("/")).replace(/\/+$/u,"")}function d(e){const r=e.split(f.sep).join("/");return r==="."||r==="./"?".":r.replace(/^\.\/+/u,"").replace(/\/+$/u,"")||"."}
@@ -1 +1 @@
1
- export{loadConfigContext,loadConfigs,parseDotenv,resolveProductDir,resolveServiceCwd}from"./load.js";export{discoverTests,loadDiscoveredConfigContext,loadDiscoveryContext,fileDisplayName,formatDisplayName,testTypeContract}from"./discover-tests.js";export{findConfigFile,loadTestkitConfig}from"./config-loader.js";export{materializeDatabaseConfig}from"./database-materialization.js";export{detectNextApp}from"./runtime.js";export{DEFAULT_RUNTIME_ISOLATION_POLICY,resolveRuntimeIsolationPolicy}from"./runtime-isolation.js";export{collectModuleSpecifiers,requireMatchingEngineAuthoringImports}from"./file-metadata.js";export{hasDiscoveryErrors,buildDiscoveryErrorFromDiagnostics}from"./discovery.js";
1
+ export{loadConfigContext,loadConfigs,parseDotenv,resolveProductDir,resolveServiceCwd}from"./load.js";export{discoverTests,loadDiscoveredConfigContext,loadDiscoveryContext,fileDisplayName,formatDisplayName,testTypeContract}from"./discover-tests.js";export{findConfigFile,loadTestkitConfig}from"./config-loader.js";export{materializeDatabaseConfig}from"./database-materialization.js";export{detectNextApp}from"./runtime.js";export{DEFAULT_RUNTIME_ISOLATION_POLICY}from"./runtime-isolation.js";export{collectModuleSpecifiers,requireMatchingEngineAuthoringImports}from"./file-metadata.js";export{hasDiscoveryErrors,buildDiscoveryErrorFromDiagnostics}from"./discovery.js";
@@ -1 +1 @@
1
- import{selectDiscoveredSuites as J,discoveredRuleSuites as Q}from"./test-selection.js";import V from"path";import{isUnknownRecord as w}from"../../kernel/unknown-values.js";import{buildEngineConfigurations as W}from"../../engines/catalog.js";import{isPublicTestType as X}from"../../domain/identifiers.js";import{discoverProject as Y}from"./discovery.js";import{loadTestkitConfig as Z}from"./config-loader.js";import{normalizeToolchainRegistry as N}from"../../toolchains/index.js";import{loadTestFileMetadataMap as ee}from"./file-metadata.js";import{mergeDiscoveryConfigs as re}from"./path-policy.js";import{normalizeDiscoveryConfig as I}from"./decode-discovery.js";import{normalizeFingerprintPolicy as te}from"../../repo/fingerprint-policy.js";import{normalizeDatabaseConfig as oe}from"./database.js";import{inferEnvFiles as ie,loadServiceEnv as ne,parseDotenv as se}from"./env.js";import{normalizeRuntimeIsolationConfig as ce}from"./runtime-isolation.js";import{resolveProductDir as U,resolveServiceCwd as ae}from"./paths.js";import{normalizeRepoExecution as fe,normalizeRuntimeConfig as le}from"./runtime.js";import{normalizeServiceRequirements as de,normalizeSkipConfig as ue}from"./skip-config.js";import{normalizeArtifactArchiveConfig as pe}from"../../evidence/index.js";import{validateConfigCoverage as me,validateServiceConfig as ge}from"./validation.js";import{readProperty as n}from"./values.js";import{assertPortableServiceNameSet as we,requireServiceName as ye}from"../../domain/service-name.js";import{resolveEngineProfile as he}from"../../engines/catalog.js";const k=["65533","65534"],be=/\{(?:baseUrl|readyUrl|publicBaseUrl|privateBaseUrl|serviceContextUrl)(?::[^}]+)?\}/gu;export{se as parseDotenv,U as resolveProductDir,ae as resolveServiceCwd};export async function loadConfigContext(e={}){const r=U(process.cwd(),e.dir),t=e.configContext||await Z(r,{importCacheSalt:e.configImportCacheSalt??""}),{config:o,configFile:i}=xe(t),c=fe(ke(n(o,"execution"))),f=pe(n(o,"artifacts")),l=N(n(o,"toolchains")),a=te(n(o,"fingerprints")),p=I(n(o,"discovery"),{allowRoots:!0}),d=Ce(n(o,"services")),u=e.preparedDiscovery?.project??Y(r,je(d),{...e.discoveryOptions||{},discovery:p}),v=e.testSelection?J(u.suitesByService,e.testSelection):u.suitesByService,y=ee(r,v,e.preparedDiscovery?.fileMetadataByPath),s=Se(v,y),h=new Set([...Object.keys(d),...Object.keys(s)]),m=[];for(const g of[...h].sort((E,$)=>E.localeCompare($)))m.push(await $e({name:g,productDir:r,config:o,configFile:i,execution:c,discovery:p,artifacts:f,toolchains:l,fingerprints:a,explicitService:d[g],suites:s[g]||{},discoveredSuites:u.suitesByService[g]||{},fileMetadataByPath:y}));return me(m),{productDir:r,config:o,configFile:i,execution:c,toolchains:l,fingerprints:a,explicitServices:d,discovery:u,configs:m}}function Se(e,r){return Object.fromEntries(Object.entries(e).map(([t,o])=>[t,ve(t,o||{},r)]))}function ve(e,r,t){const o={};for(const[i,c]of Object.entries(r)){if(!X(i))throw new Error(`Discovered service "${e}" contains unknown test type "${i}"`);o[i]=c.map(f=>{const l=f.files[0];if(!l)throw new Error(`Discovered suite ${e}/${i}:${f.name} contains no files`);const a=P(t,l),p=he(i,a.engineId);if(p.id!==a.profileId)throw new Error(`Discovered file ${l} resolved conflicting engine profile ${a.profileId}; expected ${p.id}`);for(const d of f.files.slice(1)){const u=P(t,d);if(u.engineId!==a.engineId||u.profileId!==a.profileId)throw new Error(`Discovered suite ${e}/${i}:${f.name} mixes engine profiles ${a.engineId}/${a.profileId} and ${u.engineId}/${u.profileId}`)}return{...f,testType:i,engineId:a.engineId,profileId:a.profileId}})}return o}function P(e,r){const t=e.get(r);if(!t)throw new Error(`Missing validated testkit metadata for discovered file: ${r}`);return t}export async function loadConfigs(e={}){const r=await loadConfigContext(e),{configs:t}=r,o=e.service?t.filter(i=>i.name===e.service):t;if(e.service&&o.length===0){const i=t.map(c=>c.name).join(", ");throw new Error(`Service "${e.service}" not found. Available: ${i}`)}return o}async function $e({name:e,productDir:r,config:t,configFile:o,execution:i,discovery:c,artifacts:f,toolchains:l,fingerprints:a,explicitService:p,suites:d,discoveredSuites:u,fileMetadataByPath:v}){const y=await W(t,new Set(Object.values(d).flatMap(b=>b.map(C=>C.engineId)))),s=p??{},h=Object.hasOwn(s,"local")?M(n(s,"local"),e):void 0,m=p===void 0?[]:ie(r,s,h),g={...ne(r,m),...A(n(s,"env"),`Service "${e}" env`)},E=re(c,L(n(s,"discovery"),e));if(n(s,"migrate")||n(s,"seed"))throw new Error(`Service "${e}" uses removed migrate/seed hooks. Move template lifecycle to database.template.{migrate,seed,verify}.`);const $=Oe(s,e),x=le(n(s,"runtime"),e,l),O=Q(u),q=ue(n(s,"skip"),{name:e,suites:O}),_=de(n(s,"requirements"),{name:e,suites:O}),K=ce(n(s,"runtimeIsolation"),{name:e,suites:O}),G=new Set(Object.values(d).flatMap(b=>b.flatMap(C=>C.files))),H=new Map([...v.entries()].filter(([b])=>G.has(b))),z=ze(n(s,"dependsOn"),`Service "${e}" dependsOn`),T=S(n(s,"databaseFrom"),`Service "${e}" databaseFrom`);return ge({name:e,local:h,database:$,databaseFrom:T,runtime:x,dependsOn:z,suites:d,productDir:r}),{name:e,productDir:r,configFile:o,...y===void 0?{}:{engineConfigurations:y},stateDir:V.join(r,".testkit",e),artifacts:f,suites:d,testkit:{execution:i,dependsOn:z,discovery:E,database:$,databaseFrom:T,envFiles:m,requirements:_,serviceEnv:g,skip:q,runtime:x,runtimeIsolation:K,ui:n(t,"ui")||null,fingerprints:a,fileMetadataByPath:H,local:h}}}function M(e,r){if(e===!1)return;if(!w(e))throw new Error(`Service "${r}" local must be an object or false`);if(Object.prototype.hasOwnProperty.call(e,"port"))throw new Error(`Service "${r}" sets local.port. Testkit assigns every service a free port from the OS. Delete the line, or the port option of app.node or app.next, and use {port} in start, baseUrl, and readyUrl.`);const t=B(e.baseUrl,`Service "${r}" local.baseUrl`);F(t,`Service "${r}" local.baseUrl`);const o=new RegExp(`\\{port(?::${Ee(r)})?\\}`,"gu");if(!k.every(l=>D(t,o,l,!1)===l))throw new Error(`Service "${r}" local.baseUrl must use {port} for its port, for example http://127.0.0.1:{port}. Testkit assigns every service a free port from the OS.`);const i=B(e.start,`Service "${r}" local.start`),{shutdownTimeoutMs:c,...f}=e;return{...f,...Ie(c,r),baseUrl:t,start:i,cwd:S(e.cwd,`Service "${r}" local.cwd`)||".",env:A(e.env,`Service "${r}" local.env`),...Te(e.readyTimeoutMs,`Service "${r}" local.readyTimeoutMs`),...Ue(e.readyUrl,r)}}function j(e){return e.replace(/[\t\n\r]/gu,"").trim()}function R(e){return/^[a-z][a-z0-9+.-]*:[\\/]{2}(?![\\/])([^/\\?#]*)/iu.exec(j(e))?.[1]}function D(e,r,t,o){const i=j(e).replace(r,t).replace(be,o?`http://template.invalid:${t}`:"http://template.invalid").replace(/\{[^}]+\}/gu,"template");try{return new URL(i).port}catch{return}}function Ee(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}function F(e,r){if(/^[a-z][a-z0-9+.-]*:/iu.test(j(e))&&R(e)===void 0)throw new Error(`${r} must be an absolute URL with a host, for example http://127.0.0.1:{port}/health.`);const[t,o]=k.map(c=>D(e,/\{port(?::[^}]+)?\}/gu,c,!0)),i=/:(\d+)$/u.exec(R(e)??"")?.[1]??(t&&t===o?t:void 0);if(i!==void 0)throw new Error(`${r} has a literal port (${i}). Testkit assigns every service a free port from the OS. Replace the port with {port}.`)}function Oe(e,r){const t=oe(e,r);if(!t)return;const o=S(n(t,"image"),`Service "${r}" database.image`),i=S(n(t,"password"),`Service "${r}" database.password`),c=S(n(t,"user"),`Service "${r}" database.user`);return{...t,...Object.prototype.hasOwnProperty.call(t,"image")?{image:o}:{},...Object.prototype.hasOwnProperty.call(t,"password")?{password:i}:{},...Object.prototype.hasOwnProperty.call(t,"user")?{user:c}:{}}}function L(e,r){try{return I(e,{allowRoots:!0})}catch(t){const o=t instanceof Error?t.message:String(t);throw new Error(`Service "${r}" has invalid discovery config: ${o}`,{cause:t})}}function Ce(e){if(e==null)return{};if(!w(e))throw new Error("testkit.config.ts services must be an object");const r=Object.fromEntries(Object.entries(e).map(([t,o])=>{if(ye(t,`Service name "${t}"`),o==null)return[t,{}];if(!w(o))throw new Error(`Service "${t}" config must be an object`);return[t,o]}));return we(Object.keys(r)),r}function je(e){return Object.fromEntries(Object.entries(e).map(([r,t])=>{const o=t||{},i={discovery:L(n(o,"discovery"),r),local:Object.prototype.hasOwnProperty.call(o,"local")?M(n(o,"local"),r)||!1:void 0};return[r,i]}))}function xe(e){if(!w(e))throw new Error("Loaded Testkit config context must be an object");const r=e.config;if(typeof r!="object"||r===null)throw new Error("Loaded Testkit config must be an object");const t=e.configFile;if(t!==null&&typeof t!="string")throw new Error("Loaded Testkit config file must be a string or null");return{config:r,configFile:t}}function ze(e,r){if(e==null)return[];if(!Array.isArray(e))throw new Error(`${r} must be an array of strings`);return e.map((t,o)=>{if(typeof t!="string")throw new Error(`${r}[${String(o)}] must be a string`);return t})}function A(e,r){if(e==null)return{};if(!w(e))throw new Error(`${r} must be an object of strings`);return Object.fromEntries(Object.entries(e).map(([t,o])=>{if(typeof o!="string")throw new Error(`${r}.${t} must be a string`);return[t,o]}))}function Te(e,r){if(e===void 0)return{};if(typeof e!="number")throw new Error(`${r} must be a number`);return{readyTimeoutMs:e}}function Ie(e,r){if(e===void 0)return{};if(typeof e!="number"||!Number.isInteger(e)||e<=0)throw new Error(`Service "${r}" local.shutdownTimeoutMs must be a positive finite integer in milliseconds`);return{shutdownTimeoutMs:e}}function Ue(e,r){if(e===void 0)return{};if(typeof e=="string")return F(e,`Service "${r}" local.readyUrl`),{readyUrl:e};if(e===!1||e===null)return{readyUrl:e};throw new Error(`Service "${r}" local.readyUrl must be a string, false, or null`)}function S(e,r){if(e!==void 0){if(typeof e!="string")throw new Error(`${r} must be a string`);return e}}function B(e,r){if(typeof e!="string")throw new Error(`${r} must be a string`);return e}function ke(e){if(e){if(!w(e))throw new Error("testkit.config.ts execution must be an object");return e}}
1
+ import{selectDiscoveredSuites as D,selectsOnlyTypedFiles as A}from"./test-selection.js";import L from"path";import{isUnknownRecord as w,readDynamicProperty as i}from"../../kernel/unknown-values.js";import{suiteKey as C}from"../../domain/suite-selection.js";import{repoDiscoveryProblem as B}from"./groups.js";import{discoverOwnedTests as q}from"./owned-discovery.js";import{loadTestkitConfig as G}from"./config-loader.js";import{normalizeToolchainRegistry as K}from"../../toolchains/index.js";import{loadTestFileMetadataMap as _}from"./file-metadata.js";import{normalizeFingerprintPolicy as V}from"../../repo/fingerprint-policy.js";import{normalizeDatabaseConfig as H}from"./database.js";import{inferEnvFiles as J,parseDotenv as Q}from"./env.js";import{normalizeRuntimeIsolationConfig as W}from"./runtime-isolation.js";import{resolveProductDir as T,resolveServiceCwd as X}from"./paths.js";import{normalizeRepoExecution as Y,normalizeRuntimeConfig as Z}from"./runtime.js";import{normalizeServiceRequirements as N,normalizeSkipConfig as ee}from"./skip-config.js";import{normalizeArtifactArchiveConfig as re}from"../../evidence/index.js";import{validateConfigCoverage as te,validateServiceConfig as oe}from"./validation.js";import{assertPortableServiceNameSet as ne,requireServiceName as ie}from"../../domain/service-name.js";import{resolveExecutionProfile as se}from"../../engines/catalog.js";import{optionalStringValue as y}from"../../evidence/read-fields.js";const U=["65533","65534"],ae=/\{(?:baseUrl|readyUrl|publicBaseUrl|privateBaseUrl|serviceContextUrl)(?::[^}]+)?\}/gu;export{Q as parseDotenv,T as resolveProductDir,X as resolveServiceCwd};export async function loadConfigContext(e={}){const r=T(process.cwd(),e.dir),t=e.configContext||await G(r,{importCacheSalt:e.configImportCacheSalt??""}),{config:o,configFile:n}=be(t),s=Y(Oe(i(o,"execution"))),c=re(i(o,"artifacts")),m=K(i(o,"toolchains")),a=V(i(o,"fingerprints")),p=ye(i(o,"redact"));O(B(o));const l=he(i(o,"services"));e.preparedDiscovery||we(l);const d=e.plain??!A(e.testSelection??{}),u=e.preparedDiscovery?.owned??await q(r,o,{...e.discoveryOptions,plain:d,retired:e.retired,selection:e.vitest}),f=u.project,h=e.testSelection?D(f.suitesByService,e.testSelection):f.suitesByService,b=_(r,h,e.preparedDiscovery?.fileMetadataByPath),F=ce(h,b),S=[];for(const g of Object.keys(l).sort(($,E)=>$.localeCompare(E)))S.push(le({name:g,productDir:r,config:o,configFile:n,execution:s,artifacts:c,toolchains:m,fingerprints:a,explicitService:l[g]??{}}));O(u.problems[0]??null),e.allowUnmigratedServices||O(u.migration),te(S);const j=[];for(const g of[...u.groups].sort(($,E)=>$.name.localeCompare(E.name)))j.push(ue({declaration:g,productDir:r,configFile:n,execution:s,artifacts:c,policy:de(o,g),redact:p,suites:F[g.name]||[],discoveredSuites:f.suitesByService[g.name]||[],fileMetadataByPath:b,plainListed:d}));return{productDir:r,config:o,configFile:n,execution:s,toolchains:m,fingerprints:a,explicitServices:l,discovery:f,groups:j,plainFiles:u.plainFiles,services:S}}function ce(e,r){return Object.fromEntries(Object.entries(e).map(([t,o])=>[t,(o??[]).map(n=>fe(t,n,r))]))}function fe(e,r,t){const o=r.files[0];if(!o)throw new Error(`Discovered suite ${e}/${C(r)} contains no files`);const n=k(t,o);se({...r,...n});for(const s of r.files.slice(1)){const c=k(t,s);if(c.engineId!==n.engineId||c.profileId!==n.profileId)throw new Error(`Discovered suite ${e}/${C(r)} mixes engine profiles ${n.engineId}/${n.profileId} and ${c.engineId}/${c.profileId}`)}return{...r,engineId:n.engineId,profileId:n.profileId}}function k(e,r){const t=e.get(r);if(!t)throw new Error(`Missing validated testkit metadata for discovered file: ${r}`);return t}export async function loadConfigs(e={}){const{services:r}=await loadConfigContext(e),t=e.service?r.filter(o=>o.name===e.service):r;if(e.service&&t.length===0){const o=r.map(n=>n.name).join(", ");throw new Error(`Service "${e.service}" not found. Available: ${o}`)}return t}function le({name:e,productDir:r,config:t,configFile:o,execution:n,artifacts:s,toolchains:c,fingerprints:m,explicitService:a}){const p=Object.hasOwn(a,"local")?z(i(a,"local"),e):void 0,l=J(r,a,p),d=M(i(a,"env"),`Service "${e}" env`);if(i(a,"migrate")||i(a,"seed"))throw new Error(`Service "${e}" uses removed migrate/seed hooks. Move template lifecycle to database.template.{migrate,seed,verify}.`);const u=ge(a,e),f=Z(i(a,"runtime"),e,c),h=Se(i(a,"dependsOn"),`Service "${e}" dependsOn`),b=y(i(a,"databaseFrom"),`Service "${e}" databaseFrom`);return oe({name:e,local:p,database:u,databaseFrom:b,runtime:f,dependsOn:h,productDir:r}),{name:e,productDir:r,configFile:o,stateDir:L.join(r,".testkit",e),artifacts:s,testkit:{execution:n,dependsOn:h,database:u,databaseFrom:b,envFiles:l,serviceEnv:d,runtime:f,ui:i(t,"ui")||null,fingerprints:m,local:p}}}function ue({declaration:e,productDir:r,configFile:t,execution:o,artifacts:n,policy:s,redact:c,suites:m,discoveredSuites:a,fileMetadataByPath:p,plainListed:l}){const d=`Group "${e.name}"`,u=new Set(m.flatMap(f=>f.files));return{...e,roots:[...e.roots],uses:[...e.uses],artifacts:n,configFile:t,productDir:r,redact:c,suites:m,testkit:{execution:o,fileMetadataByPath:new Map([...p.entries()].filter(([f])=>u.has(f))),requirements:N(i(s,"requirements"),{owner:d,plainListed:l,suites:a}),runtimeIsolation:W(i(s,"runtimeIsolation"),{owner:d,plainListed:l,suites:a}),skip:ee(i(s,"skip"),{owner:d,plainListed:l,suites:a})}}}function de(e,r){if(r.source!=="implicit")return i(i(e,"groups"),r.name)}function z(e,r){if(e===!1)return;if(!w(e))throw new Error(`Service "${r}" local must be an object or false`);if(Object.prototype.hasOwnProperty.call(e,"port"))throw new Error(`Service "${r}" sets local.port. Testkit assigns every service a free port from the OS. Delete the line, or the port option of app.node or app.next, and use {port} in start, baseUrl, and readyUrl.`);const t=R(e.start,`Service "${r}" local.start`),{baseUrl:o,shutdownTimeoutMs:n,...s}=e;return{...s,...Ee(n,r),...me(o,r),start:t,cwd:y(e.cwd,`Service "${r}" local.cwd`)||".",env:M(e.env,`Service "${r}" local.env`),...$e(e.readyTimeoutMs,`Service "${r}" local.readyTimeoutMs`),...ve(e.readyUrl,r)}}function me(e,r){if(e==null)return{};const t=R(e,`Service "${r}" local.baseUrl`);x(t,`Service "${r}" local.baseUrl`);const o=new RegExp(`\\{port(?::${pe(r)})?\\}`,"gu");if(!U.every(n=>I(t,o,n,!1)===n))throw new Error(`Service "${r}" local.baseUrl must use {port} for its port, for example http://127.0.0.1:{port}. Testkit assigns every service a free port from the OS.`);return{baseUrl:t}}function v(e){return e.replace(/[\t\n\r]/gu,"").trim()}function P(e){return/^[a-z][a-z0-9+.-]*:[\\/]{2}(?![\\/])([^/\\?#]*)/iu.exec(v(e))?.[1]}function I(e,r,t,o){const n=v(e).replace(r,t).replace(ae,o?`http://template.invalid:${t}`:"http://template.invalid").replace(/\{[^}]+\}/gu,"template");try{return new URL(n).port}catch{return}}function pe(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}function x(e,r){if(/^[a-z][a-z0-9+.-]*:/iu.test(v(e))&&P(e)===void 0)throw new Error(`${r} must be an absolute URL with a host, for example http://127.0.0.1:{port}/health.`);const[t,o]=U.map(s=>I(e,/\{port(?::[^}]+)?\}/gu,s,!0)),n=/:(\d+)$/u.exec(P(e)??"")?.[1]??(t&&t===o?t:void 0);if(n!==void 0)throw new Error(`${r} has a literal port (${n}). Testkit assigns every service a free port from the OS. Replace the port with {port}.`)}function ge(e,r){const t=H(e,r);if(!t)return;const o=y(i(t,"image"),`Service "${r}" database.image`),n=y(i(t,"password"),`Service "${r}" database.password`),s=y(i(t,"user"),`Service "${r}" database.user`);return{...t,...Object.prototype.hasOwnProperty.call(t,"image")?{image:o}:{},...Object.prototype.hasOwnProperty.call(t,"password")?{password:n}:{},...Object.prototype.hasOwnProperty.call(t,"user")?{user:s}:{}}}function we(e){for(const[r,t]of Object.entries(e))t&&Object.hasOwn(t,"local")&&z(i(t,"local"),r)}function O(e){if(e!==null)throw new Error(e)}function he(e){if(e==null)return{};if(!w(e))throw new Error("testkit.config.ts services must be an object");const r=Object.fromEntries(Object.entries(e).map(([t,o])=>{if(ie(t,`Service name "${t}"`),o==null)return[t,{}];if(!w(o))throw new Error(`Service "${t}" config must be an object`);return[t,o]}));return ne(Object.keys(r)),r}function be(e){if(!w(e))throw new Error("Loaded Testkit config context must be an object");const r=e.config;if(typeof r!="object"||r===null)throw new Error("Loaded Testkit config must be an object");const t=e.configFile;if(t!==null&&typeof t!="string")throw new Error("Loaded Testkit config file must be a string or null");return{config:r,configFile:t}}function ye(e){if(e==null)return[];if(!Array.isArray(e))throw new Error("testkit.config.ts redact must be an array of env key names");return e.map((r,t)=>{if(typeof r!="string")throw new Error(`testkit.config.ts redact[${String(t)}] must be a string`);if(r.trim().length===0)throw new Error(`testkit.config.ts redact[${String(t)}] must not be empty`);return r.trim()})}function Se(e,r){if(e==null)return[];if(!Array.isArray(e))throw new Error(`${r} must be an array of strings`);return e.map((t,o)=>{if(typeof t!="string")throw new Error(`${r}[${String(o)}] must be a string`);return t})}function M(e,r){if(e==null)return{};if(!w(e))throw new Error(`${r} must be an object of strings`);return Object.fromEntries(Object.entries(e).map(([t,o])=>{if(typeof o!="string")throw new Error(`${r}.${t} must be a string`);return[t,o]}))}function $e(e,r){if(e===void 0)return{};if(typeof e!="number")throw new Error(`${r} must be a number`);return{readyTimeoutMs:e}}function Ee(e,r){if(e===void 0)return{};if(typeof e!="number"||!Number.isInteger(e)||e<=0)throw new Error(`Service "${r}" local.shutdownTimeoutMs must be a positive finite integer in milliseconds`);return{shutdownTimeoutMs:e}}function ve(e,r){if(e===void 0)return{};if(typeof e=="string")return x(e,`Service "${r}" local.readyUrl`),{readyUrl:e};if(e===!1||e===null)return{readyUrl:e};throw new Error(`Service "${r}" local.readyUrl must be a string, false, or null`)}function R(e,r){if(typeof e!="string")throw new Error(`${r} must be a string`);return e}function Oe(e){if(e){if(!w(e))throw new Error("testkit.config.ts execution must be an object");return e}}
@@ -1 +1 @@
1
- import{loadConfigs as d}from"./load.js";export async function loadManagedConfigs(e={}){const o=await d({dir:e.dir,testSelection:e.testSelection}),a=filterConfigsByService(o,e.service||null);return{allConfigs:o,configs:a}}export function filterConfigsByService(e,o){if(!o)return e;const a=e.filter(n=>n.name===o);if(a.length>0)return a;const i=e.map(n=>n.name).join(", ");throw new Error(`Service "${o}" not found. Available: ${i}`)}export function resolveTargetConfig(e,o=null){if(o){const n=e.find(r=>r.name===o);if(!n){const r=e.map(t=>t.name).join(", ");throw new Error(`Service "${o}" not found. Available: ${r}`)}return n}if(e.length===1)return e[0];const a=e.filter(n=>n.testkit.database);if(a.length===1)return a[0];const i=e.map(n=>n.name).join(", ");throw new Error(`Multiple services available. Pass --service. Available: ${i}`)}export function collectRequiredConfigs(e,o){const a=new Map(e.map(r=>[r.name,r])),i=new Set,n=r=>{if(i.has(r))return;const t=a.get(r);if(!t)throw new Error(`Missing config for dependency "${r}"`);i.add(r);for(const s of t.testkit.dependsOn)n(s)};return n(o),e.filter(r=>i.has(r.name))}export function topologicallySortConfigs(e){const o=new Map(e.map(t=>[t.name,t])),a=new Set,i=new Set,n=[],r=t=>{if(!a.has(t.name)){if(i.has(t.name))throw new Error(`Dependency cycle while resolving configs for "${t.name}"`);i.add(t.name);for(const s of t.testkit.dependsOn){const l=o.get(s);l&&r(l)}i.delete(t.name),a.add(t.name),n.push(t)}};for(const t of e)r(t);return n}
1
+ import{loadConfigContext as c,loadConfigs as d}from"./load.js";export async function loadManagedConfigs(e={}){const n=await d({dir:e.dir,allowUnmigratedServices:!0,plain:!1,retired:[]}),i=filterConfigsByService(n,e.service||null);return{allConfigs:n,configs:i}}export async function loadRunConfigs(e={}){const n=await c(e),i=e.group?n.groups.filter(t=>t.name===e.group):n.groups.filter(t=>t.source!=="implicit"||Object.hasOwn(n.discovery.suitesByService,t.name));if(e.group&&i.length===0){const t=n.groups.map(r=>r.name).join(", ");throw new Error(`Group "${e.group}" not found. Available: ${t}`)}return{groups:i,services:n.services}}export function filterConfigsByService(e,n){if(!n)return e;const i=e.filter(r=>r.name===n);if(i.length>0)return i;const t=e.map(r=>r.name).join(", ");throw new Error(`Service "${n}" not found. Available: ${t}`)}export function resolveTargetConfig(e,n=null){if(n){const r=e.find(a=>a.name===n);if(!r){const a=e.map(o=>o.name).join(", ");throw new Error(`Service "${n}" not found. Available: ${a}`)}return r}if(e.length===1)return e[0];const i=e.filter(r=>r.testkit.database);if(i.length===1)return i[0];const t=e.map(r=>r.name).join(", ");throw new Error(`Multiple services available. Pass --service. Available: ${t}`)}export function collectRequiredConfigs(e,n){const i=new Map(e.map(a=>[a.name,a])),t=new Set,r=a=>{if(t.has(a))return;const o=i.get(a);if(!o)throw new Error(`Missing config for dependency "${a}"`);t.add(a);for(const s of o.testkit.dependsOn)r(s)};return r(n),e.filter(a=>t.has(a.name))}export function topologicallySortConfigs(e){const n=new Map(e.map(o=>[o.name,o])),i=new Set,t=new Set,r=[],a=o=>{if(!i.has(o.name)){if(t.has(o.name))throw new Error(`Dependency cycle while resolving configs for "${o.name}"`);t.add(o.name);for(const s of o.testkit.dependsOn){const l=n.get(s);l&&a(l)}t.delete(o.name),i.add(o.name),r.push(o)}};for(const o of e)a(o);return r}
@@ -0,0 +1 @@
1
+ import{rejectRetiredTestFile as f}from"../../domain/retired-test-types.js";import{listPlainVitestFiles as m,resolveVitestSelection as h}from"../../engines/catalog.js";import{buildDiscoveryProject as v,scanTestFiles as F}from"./discovery.js";import{readDiscoveryScan as w,resolveGroups as u}from"./groups.js";export async function discoverOwnedTests(e,i,{plain:p=!0,selection:c=h({},e),...n}={}){const s=F(e,w(i)),{assignments:d,migration:o}=u(i,[...s.untypedFiles,...s.suiteFiles].map(t=>({kind:"typed",path:t})));if(o===null)for(const t of d)t.status!=="excluded"&&f(t.path,n.retired);const r=new Map;if(o===null)for(const t of s.suiteFiles)r.set(t,{kind:"typed",path:t});const a=p?await m(e,c):[];for(const{file:t}of a)r.set(t,{kind:"plain",path:t});const l=u(i,[...r.values()]);return{groups:l.groups,migration:o,plainFiles:a,problems:l.problems,project:v(s.legacyFiles,l.assignments.flatMap(y),n)}}function y(e){return e.status==="excluded"?[]:e.status==="ambiguous"?[{filePath:e.path,kind:"ambiguous",owners:e.groups}]:[{filePath:e.path,kind:"owned",owner:e.group,relativePath:e.relativePath}]}
@@ -1 +1 @@
1
- import u from"fs";import l from"path";const f=String;export const DEFAULT_DISCOVERY_EXCLUDES=Object.freeze([".cache",".git",".hg",".next",".nuxt",".playwright-browsers",".svn",".testkit",".turbo","build","coverage","dist","node_modules","playwright-report","test-results"]);export function mergeDiscoveryConfigs(...o){const e={};for(const t of o)t&&(Array.isArray(t.roots)&&(e.roots=[...t.roots]),Array.isArray(t.exclude)&&t.exclude.length>0&&(e.exclude=[...new Set([...e.exclude||[],...t.exclude])]));return e}export function resolveDiscoveryRoots(o,e,t="."){const s=Array.isArray(e)&&e.length>0?e:[t],c=new Set,a=[];for(const i of s){const r=normalizeDiscoveryPath(i);if(!r)continue;const n=l.resolve(o,r==="."?".":r);!u.existsSync(n)||!u.statSync(n).isDirectory()||c.has(n)||(c.add(n),a.push(n))}return a.sort((i,r)=>i.localeCompare(r))}export function shouldExcludeDiscoveryPath(o,e=[]){const t=normalizeDiscoveryPath(o);return!t||t==="."?!1:e.some(s=>d(t,s))}export function normalizeDiscoveryPath(o){return f(o||"").trim().split(l.sep).join("/").replace(/^\.\/+/u,"").replace(/\/+/gu,"/").replace(/\/+$/u,"")||"."}function d(o,e){return o===e||o.startsWith(`${e}/`)}
1
+ import l from"fs";import u from"path";const f=String;export const DEFAULT_DISCOVERY_EXCLUDES=Object.freeze([".cache",".git",".hg",".next",".nuxt",".playwright-browsers",".svn",".testkit",".turbo","build","coverage","dist","node_modules","playwright-report","test-results"]);export function resolveDiscoveryRoots(e,t,o="."){const s=Array.isArray(t)&&t.length>0?t:[o],c=new Set,a=[];for(const i of s){const r=normalizeDiscoveryPath(i);if(!r)continue;const n=u.resolve(e,r==="."?".":r);!l.existsSync(n)||!l.statSync(n).isDirectory()||c.has(n)||(c.add(n),a.push(n))}return a.sort((i,r)=>i.localeCompare(r))}export function shouldExcludeDiscoveryPath(e,t=[]){const o=normalizeDiscoveryPath(e);return!o||o==="."?!1:t.some(s=>h(o,s))}export function normalizeDiscoveryPath(e){return f(e||"").trim().split(u.sep).join("/").replace(/^\.\/+/u,"").replace(/\/+/gu,"/").replace(/\/+$/u,"")||"."}function h(e,t){return e===t||e.startsWith(`${t}/`)}