@gfdelarue/testkit 0.4.4 → 0.5.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 (817) hide show
  1. package/README.md +752 -462
  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/categories.js +1 -1
  5. package/dist/app/bugs/ci-report.js +2 -2
  6. package/dist/app/bugs/ci-summary.js +3 -3
  7. package/dist/app/bugs/draft.js +4 -4
  8. package/dist/app/bugs/facts.js +2 -2
  9. package/dist/app/bugs/file.js +1 -1
  10. package/dist/app/bugs/gate.js +1 -1
  11. package/dist/app/bugs/guide.js +3 -3
  12. package/dist/app/bugs/issue.js +4 -4
  13. package/dist/app/bugs/known-failures.js +1 -1
  14. package/dist/app/bugs/record.js +2 -2
  15. package/dist/app/bugs/run-reading.js +1 -1
  16. package/dist/app/bugs/supplied-reproduce.js +1 -0
  17. package/dist/app/campaigns/campaign.js +1 -1
  18. package/dist/app/cleanup/index.js +1 -1
  19. package/dist/app/db-schema/prepare.js +1 -1
  20. package/dist/app/destroy/index.js +1 -1
  21. package/dist/app/discover/index.js +2 -2
  22. package/dist/app/doctor/index.js +1 -1
  23. package/dist/app/environments/config-driven.js +1 -0
  24. package/dist/app/environments/environment-file.js +1 -0
  25. package/dist/app/environments/file-setup.js +1 -0
  26. package/dist/app/environments/routing.js +1 -0
  27. package/dist/app/environments/static-values.js +1 -0
  28. package/dist/app/environments/supplied-input.js +1 -0
  29. package/dist/app/environments/supplied.js +1 -0
  30. package/dist/app/environments/task-databases.js +2 -0
  31. package/dist/app/file-selection.js +1 -1
  32. package/dist/app/inspect/artifacts.js +1 -1
  33. package/dist/app/inspect/index.js +1 -1
  34. package/dist/app/lint/index.js +1 -1
  35. package/dist/app/lint/native.js +1 -1
  36. package/dist/app/lint/options.js +1 -1
  37. package/dist/app/lint/rules/data.js +1 -1
  38. package/dist/app/lint/rules/engine-imports.js +1 -1
  39. package/dist/app/lint/rules/syntax.js +1 -1
  40. package/dist/app/lint/rules/unit.js +1 -1
  41. package/dist/app/lint/shared.js +1 -1
  42. package/dist/app/package-inspection.js +1 -1
  43. package/dist/app/reports/files.js +1 -0
  44. package/dist/app/reports/prepare.js +2 -0
  45. package/dist/app/reports/publish.js +1 -0
  46. package/dist/app/run/caller-redaction.js +1 -0
  47. package/dist/app/run/engine-evidence-persistence.js +1 -1
  48. package/dist/app/run/engine-execution-failures.js +1 -1
  49. package/dist/app/run/engine-execution-reporting.js +1 -1
  50. package/dist/app/run/engine-execution.js +1 -1
  51. package/dist/app/run/engine-orchestration.js +1 -1
  52. package/dist/app/run/environment.js +1 -0
  53. package/dist/app/run/failure-details.js +1 -1
  54. package/dist/app/run/live-run.js +1 -1
  55. package/dist/app/run/orchestrator.js +1 -1
  56. package/dist/app/run/planning.js +1 -1
  57. package/dist/app/run/request.js +1 -1
  58. package/dist/app/run/results.js +1 -1
  59. package/dist/app/run/run-events.js +1 -1
  60. package/dist/app/run/run-finalization.js +1 -1
  61. package/dist/app/run/runtime-fixtures.js +1 -1
  62. package/dist/app/run/scheduler/estimates.js +1 -1
  63. package/dist/app/run/scheduler/identity.js +1 -1
  64. package/dist/app/run/scheduler/index.js +1 -1
  65. package/dist/app/run/scheduler/locks.js +1 -0
  66. package/dist/app/run/selection.js +1 -1
  67. package/dist/app/run/setup/runtime-node-setup-protocol.js +1 -1
  68. package/dist/app/run/setup/runtime-node-setup-worker.js +1 -1
  69. package/dist/app/run/setup/runtime-node-setup.js +2 -2
  70. package/dist/app/run/task-batches.js +1 -1
  71. package/dist/app/run/task-leases.js +1 -0
  72. package/dist/app/run/worker-loop.js +1 -1
  73. package/dist/app/status/runs.js +1 -1
  74. package/dist/app/tracker/index.js +1 -1
  75. package/dist/app/typecheck/index.js +4 -4
  76. package/dist/cli/command-catalog.js +1 -1
  77. package/dist/cli/command-flags.js +1 -1
  78. package/dist/cli/command-registry.js +1 -1
  79. package/dist/cli/commands/artifacts.js +2 -2
  80. package/dist/cli/commands/bug/file.js +2 -2
  81. package/dist/cli/commands/bug/record.js +2 -2
  82. package/dist/cli/commands/discover.js +1 -1
  83. package/dist/cli/commands/report/prepare.js +5 -0
  84. package/dist/cli/commands/report/publish.js +2 -0
  85. package/dist/cli/commands/run.js +2 -2
  86. package/dist/cli/commands/typecheck.js +1 -1
  87. package/dist/cli/commands/workspace.js +1 -1
  88. package/dist/cli/framework/errors.js +1 -1
  89. package/dist/cli/framework/execute.js +7 -6
  90. package/dist/cli/framework/parser.js +1 -1
  91. package/dist/cli/json-errors.js +1 -1
  92. package/dist/cli/operations/run/operation.js +2 -2
  93. package/dist/cli/renderers/bug/text.js +1 -1
  94. package/dist/cli/renderers/discover/report.js +1 -1
  95. package/dist/cli/renderers/doctor/text.js +1 -1
  96. package/dist/cli/renderers/run/events.js +2 -2
  97. package/dist/cli/renderers/run/formatting.js +1 -1
  98. package/dist/cli/renderers/run/status.js +1 -1
  99. package/dist/cli/renderers/run/text-reporter.js +24 -22
  100. package/dist/cli/terminal/colors.js +1 -1
  101. package/dist/cli/terminal/layout.js +2 -2
  102. package/dist/config/authoring/http-methods.js +1 -1
  103. package/dist/config/authoring/index.js +1 -1
  104. package/dist/config/authoring/preset-env.js +1 -1
  105. package/dist/config/loader/config-loader.js +1 -1
  106. package/dist/config/loader/database.js +1 -1
  107. package/dist/config/loader/decode-execution.js +1 -1
  108. package/dist/config/loader/dependencies.js +1 -1
  109. package/dist/config/loader/discover-tests.js +1 -1
  110. package/dist/config/loader/discovery-summary.js +1 -1
  111. package/dist/config/loader/discovery.js +2 -2
  112. package/dist/config/loader/env.js +1 -1
  113. package/dist/config/loader/execution-model.js +1 -1
  114. package/dist/config/loader/file-metadata.js +1 -1
  115. package/dist/config/loader/groups.js +1 -0
  116. package/dist/config/loader/index.js +1 -1
  117. package/dist/config/loader/load.js +1 -1
  118. package/dist/config/loader/managed-configs.js +1 -1
  119. package/dist/config/loader/owned-discovery.js +1 -0
  120. package/dist/config/loader/path-policy.js +1 -1
  121. package/dist/config/loader/runtime-isolation.js +1 -1
  122. package/dist/config/loader/runtime.js +1 -1
  123. package/dist/config/loader/skip-config.js +1 -1
  124. package/dist/config/loader/task-policy.js +1 -0
  125. package/dist/config/loader/test-selection.js +1 -1
  126. package/dist/config/loader/validation.js +1 -1
  127. package/dist/database/activity-gate.js +1 -1
  128. package/dist/database/admin.js +2 -2
  129. package/dist/database/bindings.js +1 -0
  130. package/dist/database/cleanup.js +1 -1
  131. package/dist/database/docker-metadata.js +3 -3
  132. package/dist/database/docker.js +3 -3
  133. package/dist/database/index.js +1 -1
  134. package/dist/database/lifecycle-cleanup.js +1 -1
  135. package/dist/database/local-postgres.js +1 -1
  136. package/dist/database/naming.js +1 -1
  137. package/dist/database/postgres/connection-check.js +1 -0
  138. package/dist/database/postgres/protocol.js +2 -0
  139. package/dist/database/schema-operations.js +1 -1
  140. package/dist/database/schema-source.js +3 -3
  141. package/dist/database/source-schema-env.js +1 -0
  142. package/dist/database/source-url.js +2 -2
  143. package/dist/database/state-files.js +1 -1
  144. package/dist/database/state.js +1 -1
  145. package/dist/database/steps.js +3 -3
  146. package/dist/domain/file-timeout.js +1 -1
  147. package/dist/domain/identifiers.js +1 -1
  148. package/dist/domain/operation-display.js +1 -1
  149. package/dist/domain/retired-test-types.js +1 -0
  150. package/dist/domain/runtime-isolation-contract.js +1 -1
  151. package/dist/domain/suite-selection.js +1 -1
  152. package/dist/domain/test-outcomes.js +1 -1
  153. package/dist/domain/test-types.js +1 -1
  154. package/dist/engines/adapters/evidence-files.js +1 -1
  155. package/dist/engines/adapters/evidence-identity.js +1 -1
  156. package/dist/engines/adapters/execution.js +1 -1
  157. package/dist/engines/adapters/json-bounds.js +2 -0
  158. package/dist/engines/adapters/native-report.js +1 -1
  159. package/dist/engines/api/execution-scope.js +1 -1
  160. package/dist/engines/api/execution.js +1 -1
  161. package/dist/engines/api/index.js +1 -1
  162. package/dist/engines/api/runtime-artifact.js +1 -1
  163. package/dist/engines/bundle-cache.js +1 -1
  164. package/dist/engines/catalog.js +1 -1
  165. package/dist/engines/contracts/environment-values.js +1 -0
  166. package/dist/engines/contracts/fixture-manifest.js +1 -1
  167. package/dist/engines/definitions.js +1 -1
  168. package/dist/engines/environment/handles.js +1 -0
  169. package/dist/engines/environment/index.js +1 -0
  170. package/dist/engines/factory.js +1 -1
  171. package/dist/engines/installations/node-vitest.js +1 -1
  172. package/dist/engines/installations/package-resolution.js +1 -1
  173. package/dist/engines/installations/playwright-resolution-child.js +1 -1
  174. package/dist/engines/installations/playwright.js +1 -1
  175. package/dist/engines/managed-module-resolution-policy-input.js +1 -1
  176. package/dist/engines/managed-module-resolution-policy.js +1 -1
  177. package/dist/engines/managed-module-resolution.js +2 -2
  178. package/dist/engines/manager.js +1 -1
  179. package/dist/engines/node-vitest/adapter/adapter.js +1 -1
  180. package/dist/engines/node-vitest/adapter/driver.js +2 -0
  181. package/dist/engines/node-vitest/adapter/evidence.js +2 -2
  182. package/dist/engines/node-vitest/adapter/failure-details.js +4 -2
  183. package/dist/engines/node-vitest/adapter/reporter.js +1 -1
  184. package/dist/engines/node-vitest/adapter/workspace.js +31 -192
  185. package/dist/engines/node-vitest/inventory/index.js +2 -0
  186. package/dist/engines/node-vitest/inventory/list-files.js +3 -0
  187. package/dist/engines/node-vitest/runtime/contract/index.js +1 -1
  188. package/dist/engines/node-vitest/runtime/data/http.js +1 -1
  189. package/dist/engines/node-vitest/runtime/data/index.js +1 -1
  190. package/dist/engines/node-vitest/runtime/data/report.js +5 -6
  191. package/dist/engines/node-vitest/runtime/data/scenario.js +2 -2
  192. package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
  193. package/dist/engines/node-vitest/selection.js +1 -0
  194. package/dist/engines/playwright/adapter/adapter.js +1 -1
  195. package/dist/engines/playwright/adapter/config.js +4 -4
  196. package/dist/engines/playwright/adapter/evidence-validation.js +1 -1
  197. package/dist/engines/playwright/adapter/evidence.js +1 -1
  198. package/dist/engines/playwright/adapter/reporter.js +1 -1
  199. package/dist/engines/playwright/runtime/config-file.js +1 -1
  200. package/dist/engines/playwright/runtime/config.js +1 -1
  201. package/dist/engines/playwright/runtime/runtime-input.js +43 -20
  202. package/dist/engines/runtime-input-file.js +1 -1
  203. package/dist/environment/lifecycle-artifacts.js +1 -1
  204. package/dist/environment/lifecycle-controller.js +1 -1
  205. package/dist/environment/lifecycle.js +1 -1
  206. package/dist/environment/ports.js +1 -0
  207. package/dist/environment/ready-environment.js +1 -1
  208. package/dist/environment/run-environment.js +1 -1
  209. package/dist/environment/run-stopping.js +1 -1
  210. package/dist/environment/runtime-contexts.js +1 -1
  211. package/dist/environment/runtime-manager.js +1 -1
  212. package/dist/environment/runtime-planning.js +1 -1
  213. package/dist/environment/runtime-preparation.js +1 -1
  214. package/dist/environment/services.js +3 -1
  215. package/dist/environment/state.js +1 -1
  216. package/dist/environment/template.js +1 -1
  217. package/dist/evidence/artifact-config.js +1 -1
  218. package/dist/evidence/artifact-validation.js +1 -1
  219. package/dist/evidence/artifacts.js +2 -2
  220. package/dist/evidence/bundles.js +1 -1
  221. package/dist/evidence/environment-record.js +1 -0
  222. package/dist/evidence/index.js +1 -1
  223. package/dist/evidence/logs.js +2 -2
  224. package/dist/evidence/operation-timings.js +1 -1
  225. package/dist/evidence/read-fields.js +1 -1
  226. package/dist/evidence/read-run.js +1 -1
  227. package/dist/evidence/reading.js +1 -1
  228. package/dist/evidence/redaction.js +4 -0
  229. package/dist/evidence/reporting.js +1 -1
  230. package/dist/evidence/run-model.js +1 -0
  231. package/dist/evidence/storage.js +2 -2
  232. package/dist/evidence/timing.js +1 -1
  233. package/dist/kernel/error-serialization.js +1 -1
  234. package/dist/kernel/redaction-targets.js +1 -0
  235. package/dist/kernel/redaction.js +4 -1
  236. package/dist/kernel/unknown-values.js +1 -1
  237. package/dist/process/environment.js +1 -1
  238. package/dist/process/execa-bundle.json +3 -3
  239. package/dist/process/files/json-file.js +1 -1
  240. package/dist/process/files/paths.js +1 -1
  241. package/dist/process/host/metadata.js +1 -1
  242. package/dist/process/host/platform.js +1 -1
  243. package/dist/process/host-process.js +1 -1
  244. package/dist/process/index.js +1 -1
  245. package/dist/process/lifecycle-fence.js +1 -1
  246. package/dist/process/locks.js +4 -4
  247. package/dist/process/port-listener.js +2 -0
  248. package/dist/process/process-group.js +1 -1
  249. package/dist/process/process-identity.js +1 -1
  250. package/dist/process/process.js +33 -33
  251. package/dist/process/readiness.js +1 -1
  252. package/dist/process/ready-deadline.js +1 -0
  253. package/dist/process/recovery.js +1 -1
  254. package/dist/process/runs/manifest.js +1 -1
  255. package/dist/process/runs/ownership.js +1 -1
  256. package/dist/process/runs/product-state.js +1 -1
  257. package/dist/process/runs/stop.js +1 -1
  258. package/dist/process/service-processes.js +1 -1
  259. package/dist/process/stoppable-settlement.js +1 -0
  260. package/dist/process/url-redaction.js +1 -0
  261. package/dist/process/windows-cli-owner.js +3 -3
  262. package/dist/process/windows-native.js +1 -1
  263. package/dist/repo/ci-environment.js +1 -1
  264. package/dist/repo/fingerprint-policy.js +1 -1
  265. package/dist/repo/managed-git.js +1 -1
  266. package/dist/repo/physical-tree.js +1 -1
  267. package/dist/repo/publish-directory.js +3 -0
  268. package/dist/repo/state.js +4 -4
  269. package/dist/steps/build-config.js +1 -1
  270. package/dist/steps/configured-step-testkit-modules.js +1 -1
  271. package/dist/steps/configured-steps.js +1 -1
  272. package/dist/steps/environment.js +1 -1
  273. package/dist/steps/index.js +1 -1
  274. package/dist/steps/run.js +2 -2
  275. package/dist/toolchains/archive.js +1 -1
  276. package/dist/toolchains/index.js +3 -3
  277. package/dist/toolchains/node-provisioning.js +2 -2
  278. package/dist/toolchains/semver.js +1 -1
  279. package/dist/toolchains/vitest/index.js +1 -1
  280. package/dist/tracker/redaction.js +1 -2
  281. package/dist/{config/runtime/build-assets.d.ts → types/config-build-assets.d.ts} +5 -3
  282. package/dist/{database/steps.d.ts → types/config-database-steps.d.ts} +7 -7
  283. package/dist/{config/runtime/next-runtime-tsconfig.d.ts → types/config-next-runtime-tsconfig.d.ts} +5 -3
  284. package/dist/types/config.d.ts +501 -0
  285. package/dist/types/drizzle.d.ts +13 -0
  286. package/dist/{config/runtime/env/index.d.ts → types/env.d.ts} +22 -20
  287. package/dist/types/environment.d.ts +40 -0
  288. package/dist/types/index.d.ts +21 -0
  289. package/dist/types/node-vitest-contract.d.ts +75 -0
  290. package/dist/types/node-vitest-data.d.ts +407 -0
  291. package/dist/types/playwright.d.ts +130 -0
  292. package/dist/types/tooling-vitest.d.ts +13 -0
  293. package/dist/types/workspace.d.ts +617 -0
  294. package/docs/bug-records.md +83 -81
  295. package/docs/engines.md +213 -0
  296. package/docs/test-types.md +35 -33
  297. package/package.json +22 -29
  298. package/testkit-config-schema.md +403 -171
  299. package/dist/app/bugs/areas.d.ts +0 -38
  300. package/dist/app/bugs/assessment.d.ts +0 -9
  301. package/dist/app/bugs/categories.d.ts +0 -41
  302. package/dist/app/bugs/ci-report.d.ts +0 -21
  303. package/dist/app/bugs/ci-summary.d.ts +0 -13
  304. package/dist/app/bugs/draft.d.ts +0 -70
  305. package/dist/app/bugs/facts.d.ts +0 -48
  306. package/dist/app/bugs/file.d.ts +0 -45
  307. package/dist/app/bugs/gate.d.ts +0 -22
  308. package/dist/app/bugs/guide.d.ts +0 -20
  309. package/dist/app/bugs/issue.d.ts +0 -18
  310. package/dist/app/bugs/known-failures.d.ts +0 -49
  311. package/dist/app/bugs/record.d.ts +0 -14
  312. package/dist/app/bugs/run-reading.d.ts +0 -51
  313. package/dist/app/bugs/store.d.ts +0 -34
  314. package/dist/app/campaigns/brief.d.ts +0 -7
  315. package/dist/app/campaigns/campaign.d.ts +0 -14
  316. package/dist/app/campaigns/index.d.ts +0 -38
  317. package/dist/app/campaigns/store.d.ts +0 -5
  318. package/dist/app/campaigns/summary.d.ts +0 -13
  319. package/dist/app/cleanup/index.d.ts +0 -52
  320. package/dist/app/db-schema/prepare.d.ts +0 -11
  321. package/dist/app/db-schema/refresh.d.ts +0 -17
  322. package/dist/app/db-schema/verify.d.ts +0 -11
  323. package/dist/app/destroy/index.d.ts +0 -16
  324. package/dist/app/discover/index.d.ts +0 -8
  325. package/dist/app/doctor/index.d.ts +0 -17
  326. package/dist/app/file-selection.d.ts +0 -1
  327. package/dist/app/inspect/artifacts.d.ts +0 -30
  328. package/dist/app/inspect/index.d.ts +0 -112
  329. package/dist/app/lint/index.d.ts +0 -28
  330. package/dist/app/lint/native.d.ts +0 -10
  331. package/dist/app/lint/options.d.ts +0 -67
  332. package/dist/app/lint/policy.d.ts +0 -21
  333. package/dist/app/lint/rules/data.d.ts +0 -3
  334. package/dist/app/lint/rules/engine-imports.d.ts +0 -3
  335. package/dist/app/lint/rules/syntax.d.ts +0 -4
  336. package/dist/app/lint/rules/unit.d.ts +0 -3
  337. package/dist/app/lint/shared.d.ts +0 -36
  338. package/dist/app/package-inspection.d.ts +0 -20
  339. package/dist/app/run/endpoint-readiness.d.ts +0 -43
  340. package/dist/app/run/endpoint-readiness.js +0 -1
  341. package/dist/app/run/engine-evidence-persistence.d.ts +0 -39
  342. package/dist/app/run/engine-execution-cleanup.d.ts +0 -8
  343. package/dist/app/run/engine-execution-cleanup.js +0 -1
  344. package/dist/app/run/engine-execution-failures.d.ts +0 -41
  345. package/dist/app/run/engine-execution-observer.d.ts +0 -21
  346. package/dist/app/run/engine-execution-reporting.d.ts +0 -17
  347. package/dist/app/run/engine-execution.d.ts +0 -63
  348. package/dist/app/run/engine-failure-stack.d.ts +0 -1
  349. package/dist/app/run/engine-orchestration.d.ts +0 -49
  350. package/dist/app/run/failure-details.d.ts +0 -37
  351. package/dist/app/run/live-run.d.ts +0 -27
  352. package/dist/app/run/operation-progress.d.ts +0 -13
  353. package/dist/app/run/orchestrator.d.ts +0 -68
  354. package/dist/app/run/planning-types.d.ts +0 -68
  355. package/dist/app/run/planning.d.ts +0 -15
  356. package/dist/app/run/playwright-configuration.d.ts +0 -2
  357. package/dist/app/run/playwright-configuration.js +0 -1
  358. package/dist/app/run/request.d.ts +0 -30
  359. package/dist/app/run/results.d.ts +0 -161
  360. package/dist/app/run/run-events.d.ts +0 -144
  361. package/dist/app/run/run-finalization.d.ts +0 -52
  362. package/dist/app/run/run-guards.d.ts +0 -3
  363. package/dist/app/run/runtime-failures.d.ts +0 -18
  364. package/dist/app/run/runtime-fixtures.d.ts +0 -2
  365. package/dist/app/run/runtime-task-types.d.ts +0 -20
  366. package/dist/app/run/scheduler/estimates.d.ts +0 -32
  367. package/dist/app/run/scheduler/identity.d.ts +0 -9
  368. package/dist/app/run/scheduler/index.d.ts +0 -124
  369. package/dist/app/run/scheduler/observations.d.ts +0 -20
  370. package/dist/app/run/selection.d.ts +0 -10
  371. package/dist/app/run/setup/runtime-node-setup-errors.d.ts +0 -13
  372. package/dist/app/run/setup/runtime-node-setup-protocol.d.ts +0 -85
  373. package/dist/app/run/setup/runtime-node-setup-worker.d.ts +0 -1
  374. package/dist/app/run/setup/runtime-node-setup.d.ts +0 -48
  375. package/dist/app/run/task-batches.d.ts +0 -23
  376. package/dist/app/run/worker-loop.d.ts +0 -57
  377. package/dist/app/setup/playwright.d.ts +0 -22
  378. package/dist/app/status/index.d.ts +0 -9
  379. package/dist/app/status/model.d.ts +0 -29
  380. package/dist/app/status/runs.d.ts +0 -99
  381. package/dist/app/stop/index.d.ts +0 -14
  382. package/dist/app/tracker/index.d.ts +0 -8
  383. package/dist/app/tracker/remote.d.ts +0 -13
  384. package/dist/app/tracker/token.d.ts +0 -7
  385. package/dist/app/typecheck/index.d.ts +0 -63
  386. package/dist/cli/command-catalog.d.ts +0 -137
  387. package/dist/cli/command-flags.d.ts +0 -19
  388. package/dist/cli/command-registry.d.ts +0 -3
  389. package/dist/cli/commands/artifacts.d.ts +0 -48
  390. package/dist/cli/commands/bug/file.d.ts +0 -16
  391. package/dist/cli/commands/bug/guide.d.ts +0 -5
  392. package/dist/cli/commands/bug/record.d.ts +0 -9
  393. package/dist/cli/commands/campaign/finish.d.ts +0 -10
  394. package/dist/cli/commands/campaign/start.d.ts +0 -7
  395. package/dist/cli/commands/campaign/status.d.ts +0 -13
  396. package/dist/cli/commands/ci/report.d.ts +0 -15
  397. package/dist/cli/commands/cleanup.d.ts +0 -13
  398. package/dist/cli/commands/db/schema/refresh.d.ts +0 -2
  399. package/dist/cli/commands/db/schema/verify.d.ts +0 -2
  400. package/dist/cli/commands/destroy.d.ts +0 -9
  401. package/dist/cli/commands/discover.d.ts +0 -2
  402. package/dist/cli/commands/doctor.d.ts +0 -2
  403. package/dist/cli/commands/guard/unsafe-entrypoint.d.ts +0 -2
  404. package/dist/cli/commands/lint.d.ts +0 -2
  405. package/dist/cli/commands/run/status.d.ts +0 -5
  406. package/dist/cli/commands/run/stop.d.ts +0 -7
  407. package/dist/cli/commands/run.d.ts +0 -9
  408. package/dist/cli/commands/setup/playwright.d.ts +0 -2
  409. package/dist/cli/commands/status.d.ts +0 -5
  410. package/dist/cli/commands/stop.d.ts +0 -12
  411. package/dist/cli/commands/typecheck.d.ts +0 -2
  412. package/dist/cli/commands/workspace.d.ts +0 -2
  413. package/dist/cli/entrypoint.d.ts +0 -1
  414. package/dist/cli/framework/command.d.ts +0 -21
  415. package/dist/cli/framework/definitions.d.ts +0 -100
  416. package/dist/cli/framework/errors.d.ts +0 -6
  417. package/dist/cli/framework/execute.d.ts +0 -14
  418. package/dist/cli/framework/help.d.ts +0 -11
  419. package/dist/cli/framework/index.d.ts +0 -3
  420. package/dist/cli/framework/parser.d.ts +0 -6
  421. package/dist/cli/index.d.ts +0 -4
  422. package/dist/cli/json-errors.d.ts +0 -3
  423. package/dist/cli/operations/db/schema/refresh/operation.d.ts +0 -7
  424. package/dist/cli/operations/db/schema/verify/operation.d.ts +0 -7
  425. package/dist/cli/operations/run/operation.d.ts +0 -24
  426. package/dist/cli/process-signal.d.ts +0 -1
  427. package/dist/cli/renderers/bug/text.d.ts +0 -8
  428. package/dist/cli/renderers/campaign/text.d.ts +0 -2
  429. package/dist/cli/renderers/ci/text.d.ts +0 -2
  430. package/dist/cli/renderers/cleanup/format.d.ts +0 -14
  431. package/dist/cli/renderers/db-schema/text.d.ts +0 -4
  432. package/dist/cli/renderers/destroy/text.d.ts +0 -4
  433. package/dist/cli/renderers/discover/report.d.ts +0 -7
  434. package/dist/cli/renderers/discover/text.d.ts +0 -3
  435. package/dist/cli/renderers/doctor/text.d.ts +0 -2
  436. package/dist/cli/renderers/lint/text.d.ts +0 -2
  437. package/dist/cli/renderers/run/events.d.ts +0 -8
  438. package/dist/cli/renderers/run/failure.d.ts +0 -8
  439. package/dist/cli/renderers/run/formatting.d.ts +0 -79
  440. package/dist/cli/renderers/run/status.d.ts +0 -6
  441. package/dist/cli/renderers/run/text-reporter.d.ts +0 -19
  442. package/dist/cli/renderers/status/text.d.ts +0 -2
  443. package/dist/cli/renderers/stop/text.d.ts +0 -7
  444. package/dist/cli/renderers/typecheck/text.d.ts +0 -2
  445. package/dist/cli/terminal/colors.d.ts +0 -10
  446. package/dist/cli/terminal/layout.d.ts +0 -11
  447. package/dist/cli/version-drift.d.ts +0 -25
  448. package/dist/config/authoring/build-config-contract.d.ts +0 -27
  449. package/dist/config/authoring/configured-step-contract.d.ts +0 -18
  450. package/dist/config/authoring/http-execution-contract.d.ts +0 -70
  451. package/dist/config/authoring/http-methods.d.ts +0 -18
  452. package/dist/config/authoring/index.d.ts +0 -381
  453. package/dist/config/authoring/preset-env.d.ts +0 -19
  454. package/dist/config/authoring/runtime.d.ts +0 -64
  455. package/dist/config/loader/bugs.d.ts +0 -15
  456. package/dist/config/loader/config-loader.d.ts +0 -9
  457. package/dist/config/loader/database-materialization.d.ts +0 -19
  458. package/dist/config/loader/database-roles.d.ts +0 -2
  459. package/dist/config/loader/database.d.ts +0 -55
  460. package/dist/config/loader/decode-discovery.d.ts +0 -5
  461. package/dist/config/loader/decode-execution.d.ts +0 -9
  462. package/dist/config/loader/dependencies.d.ts +0 -7
  463. package/dist/config/loader/discover-tests.d.ts +0 -111
  464. package/dist/config/loader/discovery-summary.d.ts +0 -29
  465. package/dist/config/loader/discovery.d.ts +0 -54
  466. package/dist/config/loader/env.d.ts +0 -4
  467. package/dist/config/loader/execution-model.d.ts +0 -16
  468. package/dist/config/loader/file-metadata.d.ts +0 -19
  469. package/dist/config/loader/index.d.ts +0 -10
  470. package/dist/config/loader/load.d.ts +0 -91
  471. package/dist/config/loader/managed-configs.d.ts +0 -23
  472. package/dist/config/loader/path-policy.d.ts +0 -9
  473. package/dist/config/loader/paths.d.ts +0 -5
  474. package/dist/config/loader/runtime-isolation.d.ts +0 -44
  475. package/dist/config/loader/runtime.d.ts +0 -25
  476. package/dist/config/loader/skip-config.d.ts +0 -44
  477. package/dist/config/loader/test-selection.d.ts +0 -15
  478. package/dist/config/loader/validation.d.ts +0 -16
  479. package/dist/config/loader/values.d.ts +0 -4
  480. package/dist/config/loader/values.js +0 -1
  481. package/dist/database/activity-gate.d.ts +0 -22
  482. package/dist/database/admin.d.ts +0 -31
  483. package/dist/database/cleanup.d.ts +0 -36
  484. package/dist/database/configured-steps.d.ts +0 -27
  485. package/dist/database/constants.d.ts +0 -11
  486. package/dist/database/docker-metadata.d.ts +0 -3
  487. package/dist/database/docker.d.ts +0 -65
  488. package/dist/database/drizzle/index.d.ts +0 -13
  489. package/dist/database/fingerprint.d.ts +0 -12
  490. package/dist/database/index.d.ts +0 -39
  491. package/dist/database/lifecycle-cleanup.d.ts +0 -7
  492. package/dist/database/local-postgres.d.ts +0 -71
  493. package/dist/database/naming.d.ts +0 -17
  494. package/dist/database/postgres/index.d.ts +0 -71
  495. package/dist/database/progress.d.ts +0 -6
  496. package/dist/database/roles.d.ts +0 -19
  497. package/dist/database/runtime-config.d.ts +0 -16
  498. package/dist/database/runtime-reservations.d.ts +0 -19
  499. package/dist/database/schema-operations.d.ts +0 -18
  500. package/dist/database/schema-source.d.ts +0 -96
  501. package/dist/database/source-refresh-lock.d.ts +0 -8
  502. package/dist/database/source-url.d.ts +0 -22
  503. package/dist/database/state-files.d.ts +0 -13
  504. package/dist/database/state.d.ts +0 -26
  505. package/dist/database/template-steps.d.ts +0 -39
  506. package/dist/domain/file-timeout.d.ts +0 -28
  507. package/dist/domain/identifiers.d.ts +0 -9
  508. package/dist/domain/operation-display.d.ts +0 -10
  509. package/dist/domain/operation-reason.d.ts +0 -5
  510. package/dist/domain/postgres-route.d.ts +0 -4
  511. package/dist/domain/runtime-identity.d.ts +0 -1
  512. package/dist/domain/runtime-isolation-contract.d.ts +0 -5
  513. package/dist/domain/service-name.d.ts +0 -2
  514. package/dist/domain/suite-selection.d.ts +0 -20
  515. package/dist/domain/test-outcomes.d.ts +0 -3
  516. package/dist/domain/test-types.d.ts +0 -16
  517. package/dist/engines/adapters/evidence-files.d.ts +0 -32
  518. package/dist/engines/adapters/evidence-identity.d.ts +0 -12
  519. package/dist/engines/adapters/execution.d.ts +0 -42
  520. package/dist/engines/adapters/native-report.d.ts +0 -25
  521. package/dist/engines/adapters/node-startup-cache.d.ts +0 -8
  522. package/dist/engines/adapters/workspace.d.ts +0 -4
  523. package/dist/engines/api/capabilities.d.ts +0 -31
  524. package/dist/engines/api/capabilities.js +0 -1
  525. package/dist/engines/api/evidence.d.ts +0 -38
  526. package/dist/engines/api/execution-observer.d.ts +0 -8
  527. package/dist/engines/api/execution-scope.d.ts +0 -17
  528. package/dist/engines/api/execution.d.ts +0 -101
  529. package/dist/engines/api/index.d.ts +0 -5
  530. package/dist/engines/api/k6-runtime-input.d.ts +0 -26
  531. package/dist/engines/api/k6-runtime-input.js +0 -1
  532. package/dist/engines/api/runtime-artifact.d.ts +0 -19
  533. package/dist/engines/bundle-cache.d.ts +0 -32
  534. package/dist/engines/catalog.d.ts +0 -27
  535. package/dist/engines/contracts/fixture-manifest.d.ts +0 -34
  536. package/dist/engines/contracts/json-bounds.d.ts +0 -36
  537. package/dist/engines/contracts/json-bounds.js +0 -2
  538. package/dist/engines/contracts/k6-repository-configuration.d.ts +0 -12
  539. package/dist/engines/contracts/k6-repository-configuration.js +0 -1
  540. package/dist/engines/contracts/test-context.d.ts +0 -15
  541. package/dist/engines/contracts/test-context.js +0 -1
  542. package/dist/engines/definitions.d.ts +0 -22
  543. package/dist/engines/factory.d.ts +0 -6
  544. package/dist/engines/generated-performance.d.ts +0 -1
  545. package/dist/engines/installation-catalog.d.ts +0 -27
  546. package/dist/engines/installation-catalog.js +0 -1
  547. package/dist/engines/installations/k6.d.ts +0 -98
  548. package/dist/engines/installations/k6.js +0 -1
  549. package/dist/engines/installations/node-vitest.d.ts +0 -33
  550. package/dist/engines/installations/package-requirements.d.ts +0 -28
  551. package/dist/engines/installations/package-resolution.d.ts +0 -51
  552. package/dist/engines/installations/playwright-resolution-child.d.ts +0 -1
  553. package/dist/engines/installations/playwright.d.ts +0 -75
  554. package/dist/engines/installations/types.d.ts +0 -10
  555. package/dist/engines/k6/adapter/bundle.d.ts +0 -25
  556. package/dist/engines/k6/adapter/bundle.js +0 -112
  557. package/dist/engines/k6/adapter/evidence.d.ts +0 -15
  558. package/dist/engines/k6/adapter/evidence.js +0 -4
  559. package/dist/engines/k6/adapter/executor.d.ts +0 -13
  560. package/dist/engines/k6/adapter/executor.js +0 -1
  561. package/dist/engines/k6/adapter/index.d.ts +0 -1
  562. package/dist/engines/k6/adapter/index.js +0 -1
  563. package/dist/engines/k6/adapter/input.d.ts +0 -21
  564. package/dist/engines/k6/adapter/input.js +0 -1
  565. package/dist/engines/k6/adapter/native-summary.d.ts +0 -11
  566. package/dist/engines/k6/adapter/native-summary.js +0 -1
  567. package/dist/engines/k6/adapter/repository-configuration.d.ts +0 -2
  568. package/dist/engines/k6/adapter/repository-configuration.js +0 -1
  569. package/dist/engines/k6/authoring-type-paths.d.ts +0 -3
  570. package/dist/engines/k6/authoring-type-paths.js +0 -1
  571. package/dist/engines/k6/runtime/ambient-types/bundle-manifest.json +0 -146
  572. package/dist/engines/k6/runtime/ambient-types/k6/LICENSE +0 -21
  573. package/dist/engines/k6/runtime/ambient-types/k6/browser/index.d.ts +0 -6332
  574. package/dist/engines/k6/runtime/ambient-types/k6/crypto/index.d.ts +0 -218
  575. package/dist/engines/k6/runtime/ambient-types/k6/data/index.d.ts +0 -16
  576. package/dist/engines/k6/runtime/ambient-types/k6/encoding/index.d.ts +0 -46
  577. package/dist/engines/k6/runtime/ambient-types/k6/execution/index.d.ts +0 -127
  578. package/dist/engines/k6/runtime/ambient-types/k6/experimental/csv/index.d.ts +0 -96
  579. package/dist/engines/k6/runtime/ambient-types/k6/experimental/fs/index.d.ts +0 -104
  580. package/dist/engines/k6/runtime/ambient-types/k6/experimental/redis/index.d.ts +0 -821
  581. package/dist/engines/k6/runtime/ambient-types/k6/experimental/streams/index.d.ts +0 -198
  582. package/dist/engines/k6/runtime/ambient-types/k6/global.d.ts +0 -83
  583. package/dist/engines/k6/runtime/ambient-types/k6/html/index.d.ts +0 -1325
  584. package/dist/engines/k6/runtime/ambient-types/k6/http/index.d.ts +0 -806
  585. package/dist/engines/k6/runtime/ambient-types/k6/index.d.ts +0 -126
  586. package/dist/engines/k6/runtime/ambient-types/k6/metrics/index.d.ts +0 -66
  587. package/dist/engines/k6/runtime/ambient-types/k6/net/grpc/index.d.ts +0 -247
  588. package/dist/engines/k6/runtime/ambient-types/k6/options/index.d.ts +0 -459
  589. package/dist/engines/k6/runtime/ambient-types/k6/package.json +0 -79
  590. package/dist/engines/k6/runtime/ambient-types/k6/secrets/index.d.ts +0 -36
  591. package/dist/engines/k6/runtime/ambient-types/k6/timers/index.d.ts +0 -47
  592. package/dist/engines/k6/runtime/ambient-types/k6/websockets/index.d.ts +0 -324
  593. package/dist/engines/k6/runtime/ambient-types/k6/ws/index.d.ts +0 -283
  594. package/dist/engines/k6/runtime/ambient-types/xk6-sql/LICENSE +0 -201
  595. package/dist/engines/k6/runtime/ambient-types/xk6-sql/index.d.ts +0 -397
  596. package/dist/engines/k6/runtime/ambient-types/xk6-sql/package.json +0 -15
  597. package/dist/engines/k6/runtime/artifacts.d.ts +0 -2
  598. package/dist/engines/k6/runtime/artifacts.js +0 -1
  599. package/dist/engines/k6/runtime/checks.d.ts +0 -17
  600. package/dist/engines/k6/runtime/checks.js +0 -1
  601. package/dist/engines/k6/runtime/dal-fixtures.d.ts +0 -24
  602. package/dist/engines/k6/runtime/dal-fixtures.js +0 -1
  603. package/dist/engines/k6/runtime/dal-suite.d.ts +0 -24
  604. package/dist/engines/k6/runtime/dal-suite.js +0 -1
  605. package/dist/engines/k6/runtime/dal.d.ts +0 -10
  606. package/dist/engines/k6/runtime/dal.js +0 -1
  607. package/dist/engines/k6/runtime/fixtures.d.ts +0 -3
  608. package/dist/engines/k6/runtime/fixtures.js +0 -1
  609. package/dist/engines/k6/runtime/http-assertions.d.ts +0 -19
  610. package/dist/engines/k6/runtime/http-assertions.js +0 -1
  611. package/dist/engines/k6/runtime/http-checks.d.ts +0 -19
  612. package/dist/engines/k6/runtime/http-checks.js +0 -1
  613. package/dist/engines/k6/runtime/http-suite-runtime.d.ts +0 -103
  614. package/dist/engines/k6/runtime/http-suite-runtime.js +0 -1
  615. package/dist/engines/k6/runtime/http.d.ts +0 -15
  616. package/dist/engines/k6/runtime/http.js +0 -1
  617. package/dist/engines/k6/runtime/index.d.ts +0 -11
  618. package/dist/engines/k6/runtime/index.js +0 -1
  619. package/dist/engines/k6/runtime/input.d.ts +0 -3
  620. package/dist/engines/k6/runtime/input.js +0 -1
  621. package/dist/engines/k6/runtime/k6-repository-configuration.d.ts +0 -9
  622. package/dist/engines/k6/runtime/k6-repository-configuration.js +0 -1
  623. package/dist/engines/k6/runtime/node-setup.d.ts +0 -13
  624. package/dist/engines/k6/runtime/node-setup.js +0 -1
  625. package/dist/engines/k6/runtime/runtime-globals.d.ts +0 -10
  626. package/dist/engines/k6/runtime/runtime.d.ts +0 -54
  627. package/dist/engines/k6/runtime/runtime.js +0 -1
  628. package/dist/engines/k6/runtime/shared/assertion-details.d.ts +0 -19
  629. package/dist/engines/k6/runtime/shared/assertion-details.js +0 -2
  630. package/dist/engines/k6/runtime/shared/db-normalization.d.ts +0 -19
  631. package/dist/engines/k6/runtime/shared/db-normalization.js +0 -1
  632. package/dist/engines/k6/runtime/shared/error-body.d.ts +0 -3
  633. package/dist/engines/k6/runtime/shared/error-body.js +0 -1
  634. package/dist/engines/k6/runtime/shared/file-data.d.ts +0 -1
  635. package/dist/engines/k6/runtime/shared/file-data.js +0 -1
  636. package/dist/engines/k6/runtime/shared/fixture-engine.d.ts +0 -8
  637. package/dist/engines/k6/runtime/shared/fixture-engine.js +0 -2
  638. package/dist/engines/k6/runtime/shared/http-check-plan.d.ts +0 -29
  639. package/dist/engines/k6/runtime/shared/http-check-plan.js +0 -1
  640. package/dist/engines/k6/runtime/shared/http-parsing.d.ts +0 -10
  641. package/dist/engines/k6/runtime/shared/http-parsing.js +0 -3
  642. package/dist/engines/k6/runtime/shared/ordering.d.ts +0 -2
  643. package/dist/engines/k6/runtime/shared/ordering.js +0 -1
  644. package/dist/engines/k6/runtime/shared/properties.d.ts +0 -1
  645. package/dist/engines/k6/runtime/shared/properties.js +0 -1
  646. package/dist/engines/k6/runtime/suite.d.ts +0 -4
  647. package/dist/engines/k6/runtime/suite.js +0 -1
  648. package/dist/engines/k6/runtime/types.d.ts +0 -244
  649. package/dist/engines/k6/runtime/types.js +0 -1
  650. package/dist/engines/k6/runtime/xk6-sql-driver-postgres.d.ts +0 -7
  651. package/dist/engines/k6/runtime/xk6-sql-driver-postgres.js +0 -1
  652. package/dist/engines/managed-module-resolution-policy-input.d.ts +0 -9
  653. package/dist/engines/managed-module-resolution-policy.d.ts +0 -25
  654. package/dist/engines/managed-module-resolution.d.ts +0 -13
  655. package/dist/engines/manager.d.ts +0 -25
  656. package/dist/engines/node-vitest/adapter/adapter.d.ts +0 -16
  657. package/dist/engines/node-vitest/adapter/consumer-typescript-paths.d.ts +0 -17
  658. package/dist/engines/node-vitest/adapter/consumer-typescript-paths.js +0 -3
  659. package/dist/engines/node-vitest/adapter/evidence.d.ts +0 -33
  660. package/dist/engines/node-vitest/adapter/failure-details.d.ts +0 -3
  661. package/dist/engines/node-vitest/adapter/index.d.ts +0 -1
  662. package/dist/engines/node-vitest/adapter/reporter.d.ts +0 -7
  663. package/dist/engines/node-vitest/adapter/resolution.d.ts +0 -12
  664. package/dist/engines/node-vitest/adapter/resolution.js +0 -1
  665. package/dist/engines/node-vitest/adapter/workspace.d.ts +0 -19
  666. package/dist/engines/node-vitest/runtime/contract/index.d.ts +0 -64
  667. package/dist/engines/node-vitest/runtime/data/http.d.ts +0 -4
  668. package/dist/engines/node-vitest/runtime/data/index.d.ts +0 -8
  669. package/dist/engines/node-vitest/runtime/data/primitives.d.ts +0 -1
  670. package/dist/engines/node-vitest/runtime/data/report.d.ts +0 -3
  671. package/dist/engines/node-vitest/runtime/data/runner.d.ts +0 -4
  672. package/dist/engines/node-vitest/runtime/data/scenario.d.ts +0 -12
  673. package/dist/engines/node-vitest/runtime/data/types.d.ts +0 -412
  674. package/dist/engines/node-vitest/runtime/runtime-input.d.ts +0 -64
  675. package/dist/engines/playwright/adapter/adapter.d.ts +0 -18
  676. package/dist/engines/playwright/adapter/attachments.d.ts +0 -26
  677. package/dist/engines/playwright/adapter/config.d.ts +0 -45
  678. package/dist/engines/playwright/adapter/evidence-validation.d.ts +0 -12
  679. package/dist/engines/playwright/adapter/evidence.d.ts +0 -32
  680. package/dist/engines/playwright/adapter/failure-details.d.ts +0 -2
  681. package/dist/engines/playwright/adapter/index.d.ts +0 -3
  682. package/dist/engines/playwright/adapter/reporter.d.ts +0 -12
  683. package/dist/engines/playwright/runtime/config-file.d.ts +0 -2
  684. package/dist/engines/playwright/runtime/config.d.ts +0 -24
  685. package/dist/engines/playwright/runtime/index.d.ts +0 -4
  686. package/dist/engines/playwright/runtime/runtime-input.d.ts +0 -36
  687. package/dist/engines/playwright/runtime/sandbox.d.ts +0 -84
  688. package/dist/engines/runtime-input-file.d.ts +0 -27
  689. package/dist/environment/lifecycle-artifacts.d.ts +0 -7
  690. package/dist/environment/lifecycle-controller.d.ts +0 -70
  691. package/dist/environment/lifecycle.d.ts +0 -29
  692. package/dist/environment/maintenance.d.ts +0 -68
  693. package/dist/environment/planning-types.d.ts +0 -35
  694. package/dist/environment/readiness.d.ts +0 -12
  695. package/dist/environment/readiness.js +0 -1
  696. package/dist/environment/ready-environment.d.ts +0 -19
  697. package/dist/environment/run-environment.d.ts +0 -38
  698. package/dist/environment/run-stopping.d.ts +0 -13
  699. package/dist/environment/runtime-contexts.d.ts +0 -33
  700. package/dist/environment/runtime-manager.d.ts +0 -95
  701. package/dist/environment/runtime-planning.d.ts +0 -16
  702. package/dist/environment/runtime-preparation.d.ts +0 -30
  703. package/dist/environment/runtime-service.d.ts +0 -18
  704. package/dist/environment/services.d.ts +0 -48
  705. package/dist/environment/state.d.ts +0 -18
  706. package/dist/environment/status-runtime.d.ts +0 -53
  707. package/dist/environment/template.d.ts +0 -180
  708. package/dist/evidence/artifact-config.d.ts +0 -14
  709. package/dist/evidence/artifact-validation.d.ts +0 -5
  710. package/dist/evidence/artifacts.d.ts +0 -75
  711. package/dist/evidence/bundles.d.ts +0 -27
  712. package/dist/evidence/ci-provenance.d.ts +0 -9
  713. package/dist/evidence/contracts.d.ts +0 -154
  714. package/dist/evidence/file-evidence.d.ts +0 -23
  715. package/dist/evidence/finalization.d.ts +0 -9
  716. package/dist/evidence/index.d.ts +0 -8
  717. package/dist/evidence/logs.d.ts +0 -31
  718. package/dist/evidence/operation-timings.d.ts +0 -60
  719. package/dist/evidence/read-bundle.d.ts +0 -4
  720. package/dist/evidence/read-fields.d.ts +0 -22
  721. package/dist/evidence/read-provenance.d.ts +0 -2
  722. package/dist/evidence/read-redaction.d.ts +0 -2
  723. package/dist/evidence/read-retention.d.ts +0 -2
  724. package/dist/evidence/read-run.d.ts +0 -2
  725. package/dist/evidence/reading.d.ts +0 -28
  726. package/dist/evidence/reporting-types.d.ts +0 -330
  727. package/dist/evidence/reporting.d.ts +0 -3
  728. package/dist/evidence/secure-file-copy.d.ts +0 -24
  729. package/dist/evidence/setup-progress.d.ts +0 -63
  730. package/dist/evidence/step-output.d.ts +0 -16
  731. package/dist/evidence/storage-inventory.d.ts +0 -27
  732. package/dist/evidence/storage.d.ts +0 -27
  733. package/dist/evidence/timing.d.ts +0 -23
  734. package/dist/file.d.ts +0 -11
  735. package/dist/index.d.ts +0 -4
  736. package/dist/kernel/error-serialization.d.ts +0 -38
  737. package/dist/kernel/redaction.d.ts +0 -2
  738. package/dist/kernel/unknown-values.d.ts +0 -6
  739. package/dist/kernel/work-metrics.d.ts +0 -6
  740. package/dist/process/capture-output.d.ts +0 -7
  741. package/dist/process/command-shell.d.ts +0 -1
  742. package/dist/process/environment-overlay.d.ts +0 -17
  743. package/dist/process/environment.d.ts +0 -33
  744. package/dist/process/files/contained-path.d.ts +0 -8
  745. package/dist/process/files/directory-status.d.ts +0 -14
  746. package/dist/process/files/dotenv.d.ts +0 -2
  747. package/dist/process/files/file-snapshot.d.ts +0 -34
  748. package/dist/process/files/json-file.d.ts +0 -12
  749. package/dist/process/files/paths.d.ts +0 -1
  750. package/dist/process/files/product-dir.d.ts +0 -1
  751. package/dist/process/files/temp-dir.d.ts +0 -11
  752. package/dist/process/host/metadata.d.ts +0 -6
  753. package/dist/process/host/platform.d.ts +0 -57
  754. package/dist/process/host-command.d.ts +0 -4
  755. package/dist/process/host-inspection-command.d.ts +0 -13
  756. package/dist/process/host-process.d.ts +0 -19
  757. package/dist/process/index.d.ts +0 -9
  758. package/dist/process/lifecycle-fence.d.ts +0 -11
  759. package/dist/process/locks.d.ts +0 -28
  760. package/dist/process/process-contracts.d.ts +0 -78
  761. package/dist/process/process-group.d.ts +0 -12
  762. package/dist/process/process-identity.d.ts +0 -27
  763. package/dist/process/process-limits.d.ts +0 -6
  764. package/dist/process/process.d.ts +0 -12
  765. package/dist/process/readiness.d.ts +0 -37
  766. package/dist/process/recovery.d.ts +0 -3
  767. package/dist/process/runs/inspection.d.ts +0 -5
  768. package/dist/process/runs/manifest.d.ts +0 -86
  769. package/dist/process/runs/ownership.d.ts +0 -11
  770. package/dist/process/runs/product-state.d.ts +0 -2
  771. package/dist/process/runs/schema.d.ts +0 -3
  772. package/dist/process/runs/stop.d.ts +0 -19
  773. package/dist/process/runtime-socket.d.ts +0 -4
  774. package/dist/process/service-processes.d.ts +0 -13
  775. package/dist/process/shutdown.d.ts +0 -10
  776. package/dist/process/windows-cli-owner.d.ts +0 -2
  777. package/dist/process/windows-native.d.ts +0 -6
  778. package/dist/process/windows-process-identity.d.ts +0 -4
  779. package/dist/repo/ci-environment.d.ts +0 -7
  780. package/dist/repo/fingerprint-policy.d.ts +0 -15
  781. package/dist/repo/git-path.d.ts +0 -2
  782. package/dist/repo/history.d.ts +0 -17
  783. package/dist/repo/managed-git.d.ts +0 -10
  784. package/dist/repo/metadata.d.ts +0 -3
  785. package/dist/repo/physical-tree.d.ts +0 -37
  786. package/dist/repo/remote.d.ts +0 -6
  787. package/dist/repo/state.d.ts +0 -26
  788. package/dist/repo/tree-listing.d.ts +0 -10
  789. package/dist/steps/build-config.d.ts +0 -35
  790. package/dist/steps/configured-step-testkit-modules.d.ts +0 -19
  791. package/dist/steps/configured-steps.d.ts +0 -51
  792. package/dist/steps/environment.d.ts +0 -84
  793. package/dist/steps/index.d.ts +0 -2
  794. package/dist/steps/module-runner.d.ts +0 -1
  795. package/dist/steps/run.d.ts +0 -36
  796. package/dist/toolchains/archive.d.ts +0 -53
  797. package/dist/toolchains/esbuild.d.ts +0 -9
  798. package/dist/toolchains/host-node-support.d.ts +0 -3
  799. package/dist/toolchains/index.d.ts +0 -114
  800. package/dist/toolchains/managed-node-releases.d.ts +0 -28
  801. package/dist/toolchains/node-cache.d.ts +0 -20
  802. package/dist/toolchains/node-integrity.d.ts +0 -18
  803. package/dist/toolchains/node-provisioning.d.ts +0 -29
  804. package/dist/toolchains/semver.d.ts +0 -13
  805. package/dist/toolchains/shared-operation.d.ts +0 -11
  806. package/dist/toolchains/timeouts.d.ts +0 -1
  807. package/dist/toolchains/vitest/index.d.ts +0 -13
  808. package/dist/tracker/gitea.d.ts +0 -14
  809. package/dist/tracker/github.d.ts +0 -14
  810. package/dist/tracker/http.d.ts +0 -33
  811. package/dist/tracker/index.d.ts +0 -4
  812. package/dist/tracker/redaction.d.ts +0 -4
  813. package/dist/tracker/requests.d.ts +0 -17
  814. package/dist/tracker/responses.d.ts +0 -24
  815. package/dist/tracker/types.d.ts +0 -51
  816. package/docs/engine-architecture.md +0 -654
  817. /package/dist/engines/{k6/runtime/runtime-globals.js → api/profiles.js} +0 -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={},n={}){const r=n.strict!==!1,o=C(n.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=B(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(r&&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=M(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 discoverSuites(t,e={},n={}){return discoverProject(t,e,n).suitesByService}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."],n=t.filter(s=>s.code==="legacy_path").map(s=>s.path),r=t.filter(s=>s.code==="unowned_test").map(s=>s.path),o=t.filter(s=>s.code==="ambiguous_test");if(n.length>0){e.push(""),e.push("Legacy test files outside __testkit__:");for(const s of n)e.push(`- ${s}`)}if(r.length>0){e.push(""),e.push("Unowned test files:");for(const s of r)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 n=[],r=[],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)?n.push(u):r.push(u))}}}return{suiteFiles:n.sort((a,i)=>a.localeCompare(i)),legacyFiles:r.sort((a,i)=>a.localeCompare(i))}}function B(t,e,n={}){const r=Object.entries(e).flatMap(([i,p])=>U(i,p,n));if(r.length===0)return[{name:"app",source:"implicit-root",cwdPrefix:"."}];const o=r.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 M(t){const e=new Map,n=new Map;for(const r of t){const o=r._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,r._suiteKey);break}if(i===r._suiteKey)break;s=""}s||(s=o.join("-")),n.set(r._suiteKey,s)}if(n.size!==t.length)for(const r of t)n.has(r._suiteKey)||n.set(r._suiteKey,r._suitePath.join("-"));if(new Set(n.values()).size!==t.length){const r=new Map;for(const o of t){const s=o._suitePath.join("-"),a=r.get(s)||0;r.set(s,a+1),n.set(o._suiteKey,a===0?s:`${s}-${E(a+1)}`)}}return n}function I(t,e){const n=t.get(e);if(n===void 0)throw new Error(`Discovery suite name was not resolved for "${e}"`);return n}function U(t,e,n={}){const r=e?.local,o=x(r&&r.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,...(n.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 n=t.split("/").filter(Boolean),r=n.indexOf(j);if(r===-1)return{suitePath:[h.posix.basename(t,e)]};const o=n.slice(0,r),s=n.slice(r+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 k from"fs";import y from"path";import{recordWork as v}from"../../kernel/work-metrics.js";import{DEFAULT_DISCOVERY_EXCLUDES as F,normalizeDiscoveryPath as C,resolveDiscoveryRoots as D,shouldExcludeDiscoveryPath as E}from"./path-policy.js";const P=String,w="__testkit__",N=/\.(?:test|spec)\.[cm]?[jt]sx?$/u,$=[{suffix:".contract.testkit.ts",testType:"contract"},{suffix:".data.testkit.ts",testType:"data"},{suffix:".ui.testkit.ts",testType:"ui"}];export function scanTestFiles(o,e={}){const i=[],n=[],t=[],u=[...new Set([...F,...(e.exclude||[]).map(b)])],l=D(o,e.roots,".");for(;l.length>0;){const c=l.pop();if(c!==void 0){v("discovery.directoriesRead");for(const s of k.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=b(y.relative(o,r));if(!x(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=I(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,T)=>S.localeCompare(T));t.push({code:"ambiguous_test",severity:"error",message:`Ambiguous test file: ${r} -> ${g.join(", ")}`,path:r,groupNames:g});continue}const a=x(r),p=`${s.owner}|${a?.testType??""}`,m=u.get(p)??new Map;u.set(p,m);const f=L(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=j([...s.values()]);for(const{_suiteKey:a,_suitePath:p,serviceName:m,suite:f,type:d}of s.values()){f.name=K(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 j(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 K(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 L(o,e){const i=o.split("/").slice(0,-1);if(e===null)return i.length>0?i:[y.posix.basename(o).replace(N,"")];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 x(o){return $.find(e=>o.endsWith(e.suffix))||null}function b(o){const e=P(o).split(y.sep).join("/");return e==="."||e==="./"?".":e.replace(/^\.\/+/,"").replace(/\/+$/,"")||"."}function I(o){return o.map(e=>({code:"legacy_path",severity:"error",message:`Legacy test file outside __testkit__: ${e}`,path:e}))}
@@ -1 +1 @@
1
- import h from"fs";import p from"path";import{parseDotenv as u}from"../../process/files/dotenv.js";import{resolveServiceCwd as l}from"./paths.js";export{u as parseDotenv};export function inferEnvFiles(n,r,e){const o=m(r,"service config"),d=m(e,"local config"),s=a(o?.envFile,"service.envFile"),f=v(o?.envFiles,"service.envFiles");if(s||f){const t=[];return s&&t.push(s),f&&t.push(...f),t}const i=[],c=a(d?.cwd,"service.local.cwd")??".";return c!=="."&&(i.push(p.posix.join(c,".env.testkit")),i.push(p.posix.join(c,".env"))),i.push(".env.testkit"),i.push(".env"),[...new Set(i)].map(t=>t.split(p.sep).join("/")).filter(t=>h.existsSync(l(n,t)))}export function loadServiceEnv(n,r){const e={};for(const o of r)Object.assign(e,u(l(n,o)));return e}function m(n,r){if(n!=null){if(!w(n))throw new Error(`${r} must be an object`);return n}}function a(n,r){if(n!=null){if(typeof n!="string"||n.trim().length===0)throw new Error(`${r} must be a non-empty string`);return n.trim()}}function v(n,r){if(n!=null){if(!g(n))throw new Error(`${r} must be an array of non-empty strings`);return n.map(e=>{if(typeof e!="string"||e.trim().length===0)throw new Error(`${r} must be an array of non-empty strings`);return e.trim()})}}function w(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function g(n){return Array.isArray(n)}
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
- export const DATABASE_BINDINGS=new Set(["shared","per-runtime"]);
1
+ export{};
@@ -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"./runtime-isolation.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{retiredEngineMessage as A}from"../../domain/retired-test-types.js";import{isPathWithin as h}from"../../process/files/paths.js";import g from"fs";import S from"path";import{createRequire as B}from"node:module";import{fileURLToPath as O}from"node:url";import{ENGINE_IDS as j,PUBLIC_TEST_TYPES as K,isEngineId as V}from"../../domain/identifiers.js";import{normalizeRuntimeIsolationPolicy as W}from"../../domain/runtime-isolation-contract.js";import{resolveEngineProfile as _,allowsEngineAuthoringImport as z,expectedEngineAuthoringModule as U,invalidEngineAuthoringImport as G,requireMatchingEngineImport as J}from"../../engines/catalog.js";const Y=B(import.meta.url),H=O(import.meta.resolve("typescript"));let Q;function a(){return Q??=Y(H)}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=K.find(f=>t.endsWith(`.${f}.testkit.ts`));if(i===void 0)return{engineId:"node-vitest",locks:[],profileId:"node-vitest",runtimeIsolation:null,skipReason:null};const r=a(),s=ke(e,t);let n;if($()){const f=g.readFileSync(s);L("metadata.filesRead",1),L("metadata.bytesRead",f.byteLength),n=f.toString("utf8")}else n=g.readFileSync(s,"utf8");const o=r.createSourceFile(s,n,r.ScriptTarget.Latest,!0,r.ScriptKind.TS),l=Ee(o);if(l.length>0){const f=l.map(d=>r.flattenDiagnosticMessageText(d.messageText," ")).join("; ");throw c(t,`TypeScript syntax is invalid: ${f}`)}let p=null,u=null;for(const f of o.statements)if(!(!r.isVariableStatement(f)||!re(f))){for(const d of f.declarationList.declarations)if(!(!r.isIdentifier(d.name)||d.name.text!=="testkit")){if(p)throw c(t,'exported "testkit" metadata must be declared exactly once');if(!ne(f))throw c(t,'exported "testkit" metadata must be const');p=d,u=f}}if(!p||!u)throw c(t,'export const testkit = defineFile({ engine: "..." }) is required');oe(o,u,t);const m=X(p.initializer,t,i);return requireMatchingEngineAuthoringImports(o,t,m),m}function X(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(ie(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 Z(s,t,i)}function Z(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 m=b(u.name,t,"testkit metadata");if(!se(m))throw c(t,`unknown metadata property "${m}"`);if(o.has(m))throw c(t,`duplicate metadata property "${m}"`);if(o.add(m),m==="engine"){n=k(u.initializer,t,'metadata property "engine"');continue}if(m==="locks"){s.locks=P(u.initializer,t);continue}if(m==="skip"){s.skipReason=ee(u.initializer,t);continue}s.runtimeIsolation=te(u.initializer,t)}if(!n)throw c(t,'a literal "engine" property is required');const l=A(n);if(l!==null)throw c(t,l);if(!V(n))throw c(t,`unsupported engine "${n}"; expected one of: ${j.join(", ")}`);let p;try{p=_(i,n)}catch(u){throw c(t,R(u),u)}return{engineId:n,locks:s.locks,profileId:p.id,runtimeIsolation:s.runtimeIsolation,skipReason:s.skipReason}}function P(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 ee(e,t){const i=a(),r=x(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 te(e,t){const i=k(e,t,'metadata property "runtimeIsolation"');try{return W(i,"defineFile runtimeIsolation")}catch(r){throw c(t,R(r),r)}}function ie(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 k(e,t,i){const r=x(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 re(e){const t=a();return(e.modifiers||[]).some(i=>i.kind===t.SyntaxKind.ExportKeyword)}function ne(e){const t=a();return(e.declarationList.flags&t.NodeFlags.Const)!==0}function se(e){return["engine","locks","runtimeIsolation","skip"].includes(e)}function oe(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 p=l.namedBindings;if(p&&r.isNamespaceImport(p)){p.name.text==="defineFile"&&(n+=1);continue}if(!p||!r.isNamedImports(p))continue;for(const u of p.elements){if(u.isTypeOnly||u.name.text!=="defineFile")continue;if(n+=1,(u.propertyName?.text??u.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+=Ie(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){ae(e,t,i);const r=U(i.profileId);for(const s of collectModuleSpecifiers(e))if(J(t,i,s),!z(r,s))throw G(t,i,s,r)}function ae(e,t,i){const r=a(),s=q(e),n=o=>{if(ce(o,t,i),le(o,s,t,i),r.isCallExpression(o)&&T(o,s)){const l=o.arguments.at(0);if(!l||!r.isStringLiteralLike(l)){const p=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 ${p}; 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 ce(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 y(t,i,"createRequire")}if(r.isPropertyAccessExpression(e)&&e.name.text==="createRequire"||r.isElementAccessExpression(e)&&x(e.argumentExpression)==="createRequire"||r.isBindingElement(e)&&(fe(e)==="createRequire"||r.isIdentifier(e.name)&&e.name.text==="createRequire"))throw y(t,i,"createRequire")}function le(e,t,i,r){const s=a();if(s.isPropertyAccessExpression(e)&&e.name.text==="require"&&v(e.expression,t)||s.isElementAccessExpression(e)&&x(e.argumentExpression)==="require"&&v(e.expression,t))throw y(i,r,e.getText());if(s.isIdentifier(e)&&e.text==="require"&&!E(e,t)&&!ue(e)&&!pe(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 v(e,t){return a().isIdentifier(e)&&(e.text==="globalThis"||e.text==="module")&&!E(e,t)}function ue(e){return a().isCallExpression(e.parent)&&e.parent.expression===e}function pe(e){const t=a(),i=e.parent;return me(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 me(e){const t=a(),i=e.parent;return i.name===e&&!t.isShorthandPropertyAssignment(i)&&!t.isExportSpecifier(i)}function fe(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))de(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?ge(n):w(n);r(l,n.name)}else t.isParameter(n)?r(ye(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 de(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(xe(t))return t;t=t.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();let i=e.parent;for(;;){if(t.isFunctionLike(i)||t.isSourceFile(i))return i;i=i.parent}}function xe(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=Se(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 Se(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 Ie(e){const t=a();return t.isVariableStatement(e)?e.declarationList.declarations.reduce((i,r)=>i+M(r.name,"defineFile"),0):(t.isClassDeclaration(e)||t.isEnumDeclaration(e)||t.isFunctionDeclaration(e))&&e.name?.text==="defineFile"?1:0}function M(e,t){const i=a();return i.isIdentifier(e)?e.text===t?1:0:e.elements.reduce((r,s)=>i.isOmittedExpression(s)?r:r+M(s.name,t),0)}function ke(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(!g.existsSync(r))throw new Error(`Test file metadata source does not exist: ${t}`);const s=g.realpathSync(i),n=g.realpathSync(r);if(!h(s,n))throw new Error(`Test file metadata path resolves outside the product root: ${t}`);return n}function Ee(e){return e.parseDiagnostics??[]}function c(e,t,i){return new Error(`Invalid testkit metadata in "${e}": ${t}.`,{cause:i})}function R(e){return e instanceof Error?e.message.replace(/\.$/u,""):String(e)}
@@ -0,0 +1 @@
1
+ import l from"node:path";import{requireServiceName as S}from"../../domain/service-name.js";import{errorMessage as y}from"../../kernel/error-serialization.js";import{isUnknownRecord as v,readDynamicProperty as d}from"../../kernel/unknown-values.js";import{normalizeDiscoveryConfig as b}from"./decode-discovery.js";import{DEFAULT_DISCOVERY_EXCLUDES as C,shouldExcludeDiscoveryPath as w}from"./path-policy.js";const j=String;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,r){const t=[],s=m(d(e,"discovery"),null,t),n=L(e,t),o=e&&Object.hasOwn(e,"groups")?D(d(e,"groups"),n,t):O(n,t);e&&Object.hasOwn(e,"groups")&&t.push(...z(n,o.groups));const u=(s.exclude??[]).map(f),p=[...C,...u],a=r.map(c=>P(c,o.rules,c.kind==="typed"?p:u)),i=new Set(o.groups.filter(c=>c.source==="services").map(c=>c.name));return{assignments:a,groups:[...o.groups,{name:ROOT_GROUP,roots:["."],source:"implicit",uses:[]}],notice:a.some(c=>c.status==="owned"&&i.has(c.group))?LEGACY_OWNERSHIP_NOTICE:null,problems:t}}export function readDiscoveryScan(e){return m(d(e,"discovery"),null,[])}export function repoDiscoveryProblem(e){const r=[];return m(d(e,"discovery"),null,r),r[0]??null}export function legacyServiceProblem(e,r){const t=[];return O({[e]:r},t),t[0]??null}function P(e,r,t){const s=I(e.path);if(w(s,t))return{path:s,status:"excluded"};const n=r.filter(i=>(e.kind==="typed"||!i.typedOnly)&&(i.prefix===null||x(s,i.prefix))),o=n.filter(i=>!w(s,i.exclude));if(n.length>0&&o.length===0)return{path:s,status:"excluded"};if(o.length===0)return{group:ROOT_GROUP,path:s,relativePath:s,status:"owned"};const u=Math.max(...o.map(i=>i.depth)),p=o.filter(i=>i.depth===u),a=[...new Set(p.map(i=>i.group))].sort((i,c)=>i.localeCompare(c));return a.length>1?{groups:a,path:s,status:"ambiguous"}:{group:a[0],path:s,relativePath:R(p[0],s),status:"owned"}}function D(e,r,t){const s={groups:[],rules:[]};if(!v(e))return t.push("testkit.config.ts groups must be an object"),s;for(const[n,o]of Object.entries(e)){const u=`groups.${n}`;if(n===ROOT_GROUP){t.push(`${u} is reserved for the implicit group that owns files no other group claims; rename it`);continue}try{S(n,`Group name "${n}"`)}catch(i){t.push(y(i));continue}if(!v(o)){t.push(`${u} must be an object with roots`);continue}const p=$(o.roots,`${u}.roots`,!0,t),a=$(o.exclude,`${u}.exclude`,!1,t);s.groups.push({name:n,roots:p,source:"groups",uses:A(o.uses,u,r,t)});for(const i of p)s.rules.push({depth:i==="."?0:i.split("/").length,exclude:a,group:n,legacyCwd:null,prefix:i==="."?null:i,typedOnly:!1})}return s}const E=["skip","requirements","runtimeIsolation"];function z(e,r){return Object.entries(e).flatMap(([t,s])=>E.filter(n=>d(s,n)!==void 0).map(n=>{const o=r.find(u=>u.uses.includes(t))?.name??t;return`services.${t}.${n} applies to tests, and services own no tests when groups is set; move it to groups.${o}.${n}`}))}function $(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 n=e,o=new Set;for(const u of n){const p=k(u);p===null?s.push(`${r} entry ${JSON.stringify(u)} must be a relative path inside the product directory`):o.add(p)}return[...o]}function A(e,r,t,s){if(e===void 0)return[];if(!_(e))return s.push(`${r}.uses must be an array of service names`),[];const n=[];for(const o of new Set(e))Object.hasOwn(t,o)?n.push(o):s.push(`${r}.uses names "${o}", which is not a service; declare services.${o} or remove it from ${r}.uses`);return n}function O(e,r){const t={groups:[],rules:[]};for(const[s,n]of Object.entries(e)){if(s===ROOT_GROUP){r.push("services.root is reserved for the implicit group that owns files no other group claims; rename the service");continue}const o=m(d(n,"discovery"),s,r),u=G(n),p=o.roots&&o.roots.length>0?o.roots:["."],a=(o.exclude??[]).map(c=>f(u==="."?c:l.posix.join(u,c))),i=p.map(c=>{const g=f(c),h=u==="."?g:g==="."?u:f(l.posix.join(u,g));return{depth:h==="."?0:h.split("/").filter(Boolean).length,exclude:a,group:s,legacyCwd:u==="."?null:u,prefix:h==="."?null:h,typedOnly:!0}});t.rules.push(...i),t.groups.push({name:s,roots:[...new Set(i.map(c=>c.prefix??"."))],source:"services",uses:[s]})}return t}function G(e){return f(j(d(d(e,"local"),"cwd")||"."))}function L(e,r){const t=d(e,"services");return t==null?{}:v(t)?t:(r.push("testkit.config.ts services must be an object"),{})}function m(e,r,t){try{return b(e,{allowRoots:!0})}catch(s){return t.push(r===null?y(s):`Service "${r}" has invalid discovery config: ${y(s)}`),{}}}function R(e,r){return e.prefix!==null&&x(r,e.prefix)?l.posix.relative(e.prefix,r):e.legacyCwd!==null&&x(r,e.legacyCwd)?l.posix.relative(e.legacyCwd,r):r}function _(e){return Array.isArray(e)&&e.every(r=>typeof r=="string")}function x(e,r){return e===r||e.startsWith(`${r}/`)}function k(e){if(typeof e!="string")return null;const r=e.trim(),t=r.replaceAll("\\","/");if(t===""||l.posix.isAbsolute(t)||l.win32.isAbsolute(r))return null;const s=l.posix.normalize(t).replace(/\/+$/u,"")||".";return s===".."||s.startsWith("../")?null:s}function I(e){return l.posix.normalize(e.split(l.sep).join("/")).replace(/\/+$/u,"")}function f(e){const r=e.split(l.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 K,discoveredRuleSuites as G}from"./test-selection.js";import H from"path";import{buildEngineConfigurations as J}from"../../engines/catalog.js";import{isPublicTestType as Q}from"../../domain/identifiers.js";import{discoverProject as V}from"./discovery.js";import{loadTestkitConfig as W}from"./config-loader.js";import{normalizeToolchainRegistry as X}from"../../toolchains/index.js";import{loadTestFileMetadataMap as Y}from"./file-metadata.js";import{mergeDiscoveryConfigs as Z}from"./path-policy.js";import{normalizeDiscoveryConfig as T}from"./decode-discovery.js";import{normalizeFingerprintPolicy as _}from"../../repo/fingerprint-policy.js";import{normalizeDatabaseConfig as N}from"./database.js";import{inferEnvFiles as ee,loadServiceEnv as re,parseDotenv as te}from"./env.js";import{normalizeRuntimeIsolationConfig as oe}from"./runtime-isolation.js";import{resolveProductDir as k,resolveServiceCwd as ne}from"./paths.js";import{inferLocalRuntime as ie,normalizeRepoExecution as se,normalizeRuntimeConfig as ce}from"./runtime.js";import{normalizeServiceRequirements as ae,normalizeSkipConfig as fe}from"./skip-config.js";import{normalizeArtifactArchiveConfig as de}from"../../evidence/index.js";import{validateConfigCoverage as le,validateServiceConfig as ue}from"./validation.js";import{isObjectRecord as w,readProperty as i}from"./values.js";import{assertPortableServiceNameSet as me,requireServiceName as ge}from"../../domain/service-name.js";import{resolveEngineProfile as pe}from"../../engines/catalog.js";export{te as parseDotenv,k as resolveProductDir,ne as resolveServiceCwd};export async function loadConfigContext(e={}){const r=k(process.cwd(),e.dir),t=e.requireLocalRuntime!==!1,o=e.configContext||await W(r,{importCacheSalt:e.configImportCacheSalt??""}),{config:n,configFile:c}=Ee(o),d=se(Me(i(n,"execution"))),l=de(i(n,"artifacts")),a=X(i(n,"toolchains")),s=_(i(n,"fingerprints")),g=T(i(n,"discovery"),{allowRoots:!0}),f=ve(i(n,"services")),u=e.preparedDiscovery?.project??V(r,$e(f),{...e.discoveryOptions||{},discovery:g}),v=e.testSelection?K(u.suitesByService,e.testSelection):u.suitesByService,$=Y(r,v,e.preparedDiscovery?.fileMetadataByPath),y=we(v,$),b=new Set([...Object.keys(f),...Object.keys(y)]),p=[];for(const m of[...b].sort((C,E)=>C.localeCompare(E)))p.push(await be({name:m,productDir:r,config:n,configFile:c,execution:d,discovery:g,artifacts:l,toolchains:a,fingerprints:s,explicitService:f[m]||{},discoveredService:u.services[m]||null,suites:y[m]||{},discoveredSuites:u.suitesByService[m]||{},fileMetadataByPath:$,requireLocalRuntime:t}));return le(p),{productDir:r,config:n,configFile:c,execution:d,toolchains:a,fingerprints:s,explicitServices:f,discovery:u,configs:p}}function we(e,r){return Object.fromEntries(Object.entries(e).map(([t,o])=>[t,ye(t,o||{},r)]))}function ye(e,r,t){const o={};for(const[n,c]of Object.entries(r)){if(!Q(n))throw new Error(`Discovered service "${e}" contains unknown test type "${n}"`);o[n]=c.map(d=>{const l=d.files[0];if(!l)throw new Error(`Discovered suite ${e}/${n}:${d.name} contains no files`);const a=P(t,l),s=pe(n,a.engineId);if(s.id!==a.profileId)throw new Error(`Discovered file ${l} resolved conflicting engine profile ${a.profileId}; expected ${s.id}`);for(const g of d.files.slice(1)){const f=P(t,g);if(f.engineId!==a.engineId||f.profileId!==a.profileId)throw new Error(`Discovered suite ${e}/${n}:${d.name} mixes engine profiles ${a.engineId}/${a.profileId} and ${f.engineId}/${f.profileId}`)}return{...d,testType:n,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(n=>n.name===e.service):t;if(e.service&&o.length===0){const n=t.map(c=>c.name).join(", ");throw new Error(`Service "${e.service}" not found. Available: ${n}`)}return o}async function be({name:e,productDir:r,config:t,configFile:o,execution:n,discovery:c,artifacts:d,toolchains:l,fingerprints:a,explicitService:s,discoveredService:g,suites:f,discoveredSuites:u,fileMetadataByPath:v,requireLocalRuntime:$}){const y=await J(t,new Set(Object.values(f).flatMap(h=>h.map(O=>O.engineId)))),b=he(e,s,g,r),p=ee(r,s,b),m={...re(r,p),...F(i(s,"env"),`Service "${e}" env`)},C=Z(c,D(i(s,"discovery"),e));if(i(s,"migrate")||i(s,"seed"))throw new Error(`Service "${e}" uses removed migrate/seed hooks. Move template lifecycle to database.template.{migrate,seed,verify}.`);const E=Se(s,e),z=ce(i(s,"runtime"),e,l),j=G(u),q=fe(i(s,"skip"),{name:e,suites:j}),x=ae(i(s,"requirements"),{name:e,suites:j}),U=oe(i(s,"runtimeIsolation"),{name:e,suites:j}),A=new Set(Object.values(f).flatMap(h=>h.flatMap(O=>O.files))),B=new Map([...v.entries()].filter(([h])=>A.has(h))),I=Ce(i(s,"dependsOn"),`Service "${e}" dependsOn`),M=S(i(s,"databaseFrom"),`Service "${e}" databaseFrom`);return ue({name:e,local:b,database:E,databaseFrom:M,runtime:z,dependsOn:I,suites:f,productDir:r,requireLocalRuntime:$}),{name:e,productDir:r,configFile:o,...y===void 0?{}:{engineConfigurations:y},stateDir:H.join(r,".testkit",e),artifacts:d,suites:f,testkit:{execution:n,dependsOn:I,discovery:C,database:E,databaseFrom:M,envFiles:p,requirements:x,serviceEnv:m,skip:q,runtime:z,runtimeIsolation:U,ui:i(t,"ui")||null,fingerprints:a,fileMetadataByPath:B,local:b}}}function he(e,r,t,o){if(Object.prototype.hasOwnProperty.call(r,"local"))return R(i(r,"local"),e);const n=t?.inferredLocalCwd||".",c=ie(o,n);if(c)return c}function R(e,r){if(e===!1)return;if(!w(e))throw new Error(`Service "${r}" local must be an object or false`);const t=L(e.baseUrl,`Service "${r}" local.baseUrl`),o=L(e.start,`Service "${r}" local.start`),{shutdownTimeoutMs:n,...c}=e;return{...c,...ze(n,r),baseUrl:t,start:o,cwd:S(e.cwd,`Service "${r}" local.cwd`)||".",env:F(e.env,`Service "${r}" local.env`),...je(e.port,`Service "${r}" local.port`),...Oe(e.readyTimeoutMs,`Service "${r}" local.readyTimeoutMs`),...Ie(e.readyUrl,r)}}function Se(e,r){const t=N(e,r);if(!t)return;const o=S(i(t,"image"),`Service "${r}" database.image`),n=S(i(t,"password"),`Service "${r}" database.password`),c=S(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:c}:{}}}function D(e,r){try{return T(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 ve(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(ge(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 me(Object.keys(r)),r}function $e(e){return Object.fromEntries(Object.entries(e).map(([r,t])=>{const o=t||{},n={discovery:D(i(o,"discovery"),r),local:Object.prototype.hasOwnProperty.call(o,"local")?R(i(o,"local"),r)||!1:void 0};return[r,n]}))}function Ee(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 Ce(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 F(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 je(e,r){if(e===void 0)return{};if(typeof e!="number")throw new Error(`${r} must be a number`);return{port:e}}function Oe(e,r){if(e===void 0)return{};if(typeof e!="number")throw new Error(`${r} must be a number`);return{readyTimeoutMs:e}}function ze(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 Ie(e,r){if(e===void 0)return{};if(e===!1||e===null||typeof e=="string")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 L(e,r){if(typeof e!="string")throw new Error(`${r} must be a string`);return e}function Me(e){if(e){if(!w(e))throw new Error("testkit.config.ts execution must be an object");return e}}
1
+ import{selectDiscoveredSuites as L,selectsOnlyTypedFiles as B}from"./test-selection.js";import q from"path";import{isUnknownRecord as w,readDynamicProperty as i}from"../../kernel/unknown-values.js";import{suiteKey as T}from"../../domain/suite-selection.js";import{legacyServiceProblem as k,repoDiscoveryProblem as G}from"./groups.js";import{discoverOwnedTests as K}from"./owned-discovery.js";import{loadTestkitConfig as _}from"./config-loader.js";import{normalizeToolchainRegistry as V}from"../../toolchains/index.js";import{loadTestFileMetadataMap as H}from"./file-metadata.js";import{normalizeFingerprintPolicy as J}from"../../repo/fingerprint-policy.js";import{normalizeDatabaseConfig as Q}from"./database.js";import{inferEnvFiles as W,parseDotenv as X}from"./env.js";import{normalizeRuntimeIsolationConfig as Y}from"./runtime-isolation.js";import{resolveProductDir as z,resolveServiceCwd as Z}from"./paths.js";import{normalizeRepoExecution as N,normalizeRuntimeConfig as ee}from"./runtime.js";import{normalizeServiceRequirements as re,normalizeSkipConfig as te}from"./skip-config.js";import{normalizeArtifactArchiveConfig as oe}from"../../evidence/index.js";import{validateConfigCoverage as ne,validateServiceConfig as ie}from"./validation.js";import{assertPortableServiceNameSet as se,requireServiceName as ae}from"../../domain/service-name.js";import{resolveExecutionProfile as ce}from"../../engines/catalog.js";import{optionalStringValue as S}from"../../evidence/read-fields.js";const U=["65533","65534"],fe=/\{(?:baseUrl|readyUrl|publicBaseUrl|privateBaseUrl|serviceContextUrl)(?::[^}]+)?\}/gu;export{X as parseDotenv,z as resolveProductDir,Z as resolveServiceCwd};export async function loadConfigContext(e={}){const r=z(process.cwd(),e.dir),t=e.configContext||await _(r,{importCacheSalt:e.configImportCacheSalt??""}),{config:o,configFile:n}=Se(t),a=N(Ce(i(o,"execution"))),f=oe(i(o,"artifacts")),p=V(i(o,"toolchains")),s=J(i(o,"fingerprints")),h=$e(i(o,"redact"));$(G(o));const c=ye(i(o,"services")),u=!Object.hasOwn(o,"groups");e.preparedDiscovery||be(c,u);const g=e.plain??!B(e.testSelection??{}),l=e.preparedDiscovery?.owned??await K(r,o,{...e.discoveryOptions,plain:g,retired:e.retired,selection:e.vitest}),d=l.project,b=e.testSelection?L(d.suitesByService,e.testSelection):d.suitesByService,y=H(r,b,e.preparedDiscovery?.fileMetadataByPath),A=le(b,y),E=[];for(const m of Object.keys(c).sort((v,O)=>v.localeCompare(O)))E.push(pe({name:m,productDir:r,config:o,configFile:n,execution:a,artifacts:f,toolchains:p,fingerprints:s,explicitService:c[m]??{},legacy:u}));$(l.problems[0]??null),ne(E);const C=[];for(const m of[...l.groups].sort((v,O)=>v.name.localeCompare(O.name)))C.push(de({declaration:m,productDir:r,configFile:n,execution:a,artifacts:f,policy:me(o,m),redact:h,suites:A[m.name]||[],discoveredSuites:d.suitesByService[m.name]||[],fileMetadataByPath:y,plainListed:g}));return{productDir:r,config:o,configFile:n,execution:a,toolchains:p,fingerprints:s,explicitServices:c,discovery:d,groups:C,ownershipNotice:l.notice,services:E}}function le(e,r){return Object.fromEntries(Object.entries(e).map(([t,o])=>[t,(o??[]).map(n=>ue(t,n,r))]))}function ue(e,r,t){const o=r.files[0];if(!o)throw new Error(`Discovered suite ${e}/${T(r)} contains no files`);const n=P(t,o);ce({...r,...n});for(const a of r.files.slice(1)){const f=P(t,a);if(f.engineId!==n.engineId||f.profileId!==n.profileId)throw new Error(`Discovered suite ${e}/${T(r)} mixes engine profiles ${n.engineId}/${n.profileId} and ${f.engineId}/${f.profileId}`)}return{...r,engineId:n.engineId,profileId:n.profileId}}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{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 pe({name:e,productDir:r,config:t,configFile:o,execution:n,artifacts:a,toolchains:f,fingerprints:p,explicitService:s,legacy:h}){const c=Object.hasOwn(s,"local")?I(i(s,"local"),e):void 0,u=W(r,s,c),g=D(i(s,"env"),`Service "${e}" env`);if(h&&$(k(e,s)),i(s,"migrate")||i(s,"seed"))throw new Error(`Service "${e}" uses removed migrate/seed hooks. Move template lifecycle to database.template.{migrate,seed,verify}.`);const l=he(s,e),d=ee(i(s,"runtime"),e,f),b=Ee(i(s,"dependsOn"),`Service "${e}" dependsOn`),y=S(i(s,"databaseFrom"),`Service "${e}" databaseFrom`);return ie({name:e,local:c,database:l,databaseFrom:y,runtime:d,dependsOn:b,productDir:r}),{name:e,productDir:r,configFile:o,stateDir:q.join(r,".testkit",e),artifacts:a,testkit:{execution:n,dependsOn:b,database:l,databaseFrom:y,envFiles:u,serviceEnv:g,runtime:d,ui:i(t,"ui")||null,fingerprints:p,local:c}}}function de({declaration:e,productDir:r,configFile:t,execution:o,artifacts:n,policy:a,redact:f,suites:p,discoveredSuites:s,fileMetadataByPath:h,plainListed:c}){const u=e.source==="services"?`Service "${e.name}"`:`Group "${e.name}"`,g=new Set(p.flatMap(l=>l.files));return{...e,roots:[...e.roots],uses:[...e.uses],artifacts:n,configFile:t,productDir:r,redact:f,suites:p,testkit:{execution:o,fileMetadataByPath:new Map([...h.entries()].filter(([l])=>g.has(l))),requirements:re(i(a,"requirements"),{owner:u,plainListed:c,suites:s}),runtimeIsolation:Y(i(a,"runtimeIsolation"),{owner:u,plainListed:c,suites:s}),skip:te(i(a,"skip"),{owner:u,plainListed:c,suites:s})}}}function me(e,r){if(r.source!=="implicit")return i(i(e,r.source==="groups"?"groups":"services"),r.name)}function I(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=F(e.start,`Service "${r}" local.start`),{baseUrl:o,shutdownTimeoutMs:n,...a}=e;return{...a,...Oe(n,r),...ge(o,r),start:t,cwd:S(e.cwd,`Service "${r}" local.cwd`)||".",env:D(e.env,`Service "${r}" local.env`),...ve(e.readyTimeoutMs,`Service "${r}" local.readyTimeoutMs`),...je(e.readyUrl,r)}}function ge(e,r){if(e==null)return{};const t=F(e,`Service "${r}" local.baseUrl`);x(t,`Service "${r}" local.baseUrl`);const o=new RegExp(`\\{port(?::${we(r)})?\\}`,"gu");if(!U.every(n=>R(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 j(e){return e.replace(/[\t\n\r]/gu,"").trim()}function M(e){return/^[a-z][a-z0-9+.-]*:[\\/]{2}(?![\\/])([^/\\?#]*)/iu.exec(j(e))?.[1]}function R(e,r,t,o){const n=j(e).replace(r,t).replace(fe,o?`http://template.invalid:${t}`:"http://template.invalid").replace(/\{[^}]+\}/gu,"template");try{return new URL(n).port}catch{return}}function we(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")}function x(e,r){if(/^[a-z][a-z0-9+.-]*:/iu.test(j(e))&&M(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(a=>R(e,/\{port(?::[^}]+)?\}/gu,a,!0)),n=/:(\d+)$/u.exec(M(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 he(e,r){const t=Q(e,r);if(!t)return;const o=S(i(t,"image"),`Service "${r}" database.image`),n=S(i(t,"password"),`Service "${r}" database.password`),a=S(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:a}:{}}}function be(e,r){for(const[t,o]of Object.entries(e))r&&$(k(t,o)),o&&Object.hasOwn(o,"local")&&I(i(o,"local"),t)}function $(e){if(e!==null)throw new Error(e)}function ye(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(ae(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 se(Object.keys(r)),r}function Se(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 $e(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 Ee(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 D(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 ve(e,r){if(e===void 0)return{};if(typeof e!="number")throw new Error(`${r} must be a number`);return{readyTimeoutMs:e}}function Oe(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 je(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 F(e,r){if(typeof e!="string")throw new Error(`${r} must be a string`);return e}function Ce(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,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,ownershipNotice:n.ownershipNotice,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 d}from"../../domain/retired-test-types.js";import{listPlainVitestFiles as f,resolveVitestSelection as h}from"../../engines/catalog.js";import{buildDiscoveryProject as m,scanTestFiles as v}from"./discovery.js";import{readDiscoveryScan as y,resolveGroups as l}from"./groups.js";export async function discoverOwnedTests(e,o,{plain:p=!0,selection:u=h({},e),...n}={}){const r=v(e,y(o)),c=r.untypedFiles.map(t=>({kind:"typed",path:t}));for(const t of l(o,c).assignments)t.status!=="excluded"&&d(t.path,n.retired);const i=new Map;for(const t of r.suiteFiles)i.set(t,{kind:"typed",path:t});const a=p?await f(e,u):[];for(const{file:t}of a)i.set(t,{kind:"plain",path:t});const s=l(o,[...i.values()]);return{groups:s.groups,notice:s.notice,plainFiles:a,problems:s.problems,project:m(r.legacyFiles,s.assignments.flatMap(w),n)}}function w(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}/`)}
@@ -1 +1 @@
1
- import{matchesSuiteSelectors as P,parseSuiteSelectors as v}from"../../domain/suite-selection.js";import{isObjectRecord as y}from"./values.js";import{DEFAULT_RUNTIME_ISOLATION_POLICY as E,normalizeRuntimeIsolationPolicy as m}from"../../domain/runtime-isolation-contract.js";import{normalizePath as I}from"./paths.js";export{DEFAULT_RUNTIME_ISOLATION_POLICY,isRuntimeIsolationPolicy,normalizeRuntimeIsolationPolicy,RUNTIME_ISOLATION_POLICIES}from"../../domain/runtime-isolation-contract.js";const R=String;export function normalizeRuntimeIsolationConfig(e,{name:t,suites:d}){if(!e)return h();if(typeof e=="string")return{...h(),defaultPolicy:m(e,`Service "${t}" runtimeIsolation`)};if(!y(e))throw new Error(`Service "${t}" runtimeIsolation must be a policy string or object`);const l=[],f=new Set;for(const o of Object.values(d||{}))for(const r of o||[]){l.push({testType:r.testType,name:r.name});for(const s of r.files||[])f.add(I(s))}const c=e.default==null?E:m(e.default,`Service "${t}" runtimeIsolation.default`),u=[],a=new Set;for(const[o,r]of g(e.suites,`Service "${t}" runtimeIsolation.suites`).entries()){if(!y(r))throw new Error(`Service "${t}" runtimeIsolation.suites entries must be objects`);const s=r,i=R(s.selector||"").trim();if(!i)throw new Error(`Service "${t}" runtimeIsolation.suites[${o.toString()}] requires a selector`);const w=v([i]);if(w.length!==1)throw new Error(`Service "${t}" runtimeIsolation.suites["${i}"] is invalid`);const n=w[0];if(n.kind!=="typed")throw new Error(`Service "${t}" runtimeIsolation.suites["${i}"] must use a typed selector like ui:auth`);if(a.has(n.raw))throw new Error(`Service "${t}" defines duplicate runtimeIsolation.suites selector "${n.raw}"`);if(!l.some($=>P($.testType,$.name,[n])))throw new Error(`Service "${t}" runtimeIsolation.suites selector "${n.raw}" did not match any discovered suite`);a.add(n.raw),u.push({selector:n,policy:m(s.policy||s.runtimeIsolation,`Service "${t}" runtimeIsolation.suites["${n.raw}"].policy`)})}const p=[],S=new Set;for(const[o,r]of g(e.files,`Service "${t}" runtimeIsolation.files`).entries()){if(!y(r))throw new Error(`Service "${t}" runtimeIsolation.files entries must be objects`);const s=r,i=I(T(s.path,`Service "${t}" runtimeIsolation.files[${o.toString()}].path`));if(!i)throw new Error(`Service "${t}" runtimeIsolation.files[${o.toString()}] requires a path`);if(!f.has(i))throw new Error(`Service "${t}" runtimeIsolation.files["${i}"] did not match any discovered test file`);if(S.has(i))throw new Error(`Service "${t}" defines duplicate runtimeIsolation.files path "${i}"`);S.add(i),p.push({path:i,policy:m(s.policy||s.runtimeIsolation,`Service "${t}" runtimeIsolation.files["${i}"].policy`)})}return{defaultPolicy:c,suites:u,files:p,filePolicyByPath:new Map(p.map(o=>[o.path,o.policy]))}}export function resolveRuntimeIsolationPolicy(e,t,d){const l=I(d),f=e.testkit?.fileMetadataByPath?.get(l)||null,c=e.testkit?.runtimeIsolation||h(),u=f?.runtimeIsolation||c.filePolicyByPath.get(l);if(u)return u;for(const a of c.suites)if(P(t.testType,t.name,[a.selector]))return a.policy;return c.defaultPolicy}function h(){return{defaultPolicy:E,suites:[],files:[],filePolicyByPath:new Map}}function g(e,t){if(e==null)return[];if(!Array.isArray(e))throw new Error(`${t} must be an array`);return e}function T(e,t){if(e==null||typeof e=="string")return e;throw new Error(`${t} must be a string`)}
1
+ import{matchesSuiteSelectors as E,parseSuiteSelectors as T}from"../../domain/suite-selection.js";import{isTypedTestFile as O}from"../../domain/identifiers.js";import{isUnknownRecord as I}from"../../kernel/unknown-values.js";import{DEFAULT_RUNTIME_ISOLATION_POLICY as g,normalizeRuntimeIsolationPolicy as m}from"../../domain/runtime-isolation-contract.js";import{normalizePath as y}from"./paths.js";import{optionalArray as R}from"./skip-config.js";export{DEFAULT_RUNTIME_ISOLATION_POLICY,isRuntimeIsolationPolicy,normalizeRuntimeIsolationPolicy,RUNTIME_ISOLATION_POLICIES}from"../../domain/runtime-isolation-contract.js";const L=String;export function normalizeRuntimeIsolationConfig(i,{owner:t,plainListed:p=!0,suites:u}){if(!i)return h();if(typeof i=="string")return{...h(),defaultPolicy:m(i,`${t} runtimeIsolation`)};if(!I(i))throw new Error(`${t} runtimeIsolation must be a policy string or object`);const c=u??[],n=new Set(c.flatMap(o=>(o.files??[]).map(y))),f=i.default==null?g:m(i.default,`${t} runtimeIsolation.default`),l=[],$=new Set;for(const[o,a]of R(i.suites,`${t} runtimeIsolation.suites`).entries()){if(!I(a))throw new Error(`${t} runtimeIsolation.suites entries must be objects`);const r=a,e=L(r.selector||"").trim();if(!e)throw new Error(`${t} runtimeIsolation.suites[${o.toString()}] requires a selector`);const S=T([e]);if(S.length!==1)throw new Error(`${t} runtimeIsolation.suites["${e}"] is invalid`);const s=S[0];if(s.kind!=="typed")throw new Error(`${t} runtimeIsolation.suites["${e}"] must use a typed selector like ui:auth`);if($.has(s.raw))throw new Error(`${t} defines duplicate runtimeIsolation.suites selector "${s.raw}"`);if(!c.some(w=>E(w.testType,w.name,[s])))throw new Error(`${t} runtimeIsolation.suites selector "${s.raw}" did not match any discovered suite`);$.add(s.raw),l.push({selector:s,policy:m(r.policy||r.runtimeIsolation,`${t} runtimeIsolation.suites["${s.raw}"].policy`)})}const d=[],P=new Set;for(const[o,a]of R(i.files,`${t} runtimeIsolation.files`).entries()){if(!I(a))throw new Error(`${t} runtimeIsolation.files entries must be objects`);const r=a,e=y(_(r.path,`${t} runtimeIsolation.files[${o.toString()}].path`));if(!e)throw new Error(`${t} runtimeIsolation.files[${o.toString()}] requires a path`);if(!n.has(e)&&(p||O(e)))throw new Error(`${t} runtimeIsolation.files["${e}"] did not match any discovered test file`);if(P.has(e))throw new Error(`${t} defines duplicate runtimeIsolation.files path "${e}"`);P.add(e),d.push({path:e,policy:m(r.policy||r.runtimeIsolation,`${t} runtimeIsolation.files["${e}"].policy`)})}return{defaultPolicy:f,suites:l,files:d,filePolicyByPath:new Map(d.map(o=>[o.path,o.policy]))}}export function resolveRuntimeIsolationPolicy(i,t,p){const u=y(p),c=i.testkit?.fileMetadataByPath?.get(u)||null,n=i.testkit?.runtimeIsolation||h(),f=c?.runtimeIsolation||n.filePolicyByPath.get(u);if(f)return f;for(const l of n.suites)if(E(t.testType,t.name,[l.selector]))return l.policy;return n.defaultPolicy}function h(){return{defaultPolicy:g,suites:[],files:[],filePolicyByPath:new Map}}function _(i,t){if(i==null||typeof i=="string")return i;throw new Error(`${t} must be a string`)}
@@ -1 +1 @@
1
- import n from"fs";import i from"path";import{DEFAULT_FILE_TIMEOUT_SECONDS as m}from"../../domain/file-timeout.js";import{normalizeExecutionConfig as a,normalizeRuntimeMaxConcurrentTasks as l,normalizeRuntimeInstances as f}from"./decode-execution.js";import"./execution-model.js";import{normalizeConfiguredInputs as S,normalizeConfiguredSteps as x}from"../../steps/configured-steps.js";import{buildConfigToPrepare as d,normalizeBuildConfig as h}from"../../steps/build-config.js";import{normalizeRuntimeToolchain as b}from"../../toolchains/index.js";import{resolveServiceCwd as C}from"./paths.js";export function inferLocalRuntime(e,r){const t=C(e,r);if(n.existsSync(t)){if(detectNextApp(t))return{cwd:r,start:"{bin:next} dev -p {port}",port:3e3,baseUrl:"http://127.0.0.1:{port}",readyUrl:"http://127.0.0.1:{port}",env:{}};if(n.existsSync(i.join(t,"cmd","server")))return{cwd:r,start:"go run ./cmd/server",port:3e3,baseUrl:"http://127.0.0.1:{port}",readyUrl:"http://127.0.0.1:{port}/health",env:{}};if(n.existsSync(i.join(t,"package.json"))&&n.existsSync(i.join(t,"src")))return{cwd:r,start:"{bin:tsx} watch src/index.ts",port:3e3,baseUrl:"http://127.0.0.1:{port}",readyUrl:"http://127.0.0.1:{port}/health",env:{}}}}export function normalizeRuntimeConfig(e,r,t){if(!e)return{build:null,instances:1,maxConcurrentTasks:Number.POSITIVE_INFINITY,prepare:{inputs:[],steps:[]},toolchain:null};const o=c(e)?e:{},s=h(o.build,`Service "${r}" runtime.build`),p=normalizeRuntimePrepareConfig(o.prepare,r),u=d(s);return{build:s,instances:f(o.instances??1,`Service "${r}" runtime.instances`),maxConcurrentTasks:l(o.maxConcurrentTasks,`Service "${r}" runtime.maxConcurrentTasks`),prepare:{inputs:[...new Set([...u.inputs,...p.inputs])],steps:[...u.steps,...p.steps]},toolchain:b(o.toolchain,`Service "${r}" runtime.toolchain`,t||{})}}export function normalizeRuntimePrepareConfig(e,r){if(e==null)return{inputs:[],steps:[]};if(!c(e))throw new Error(`Service "${r}" runtime.prepare must be an object`);return{inputs:S(e.inputs,`Service "${r}" runtime.prepare`),steps:x(e.steps,`Service "${r}" runtime.prepare.steps`)}}export function normalizeRepoExecution(e){return e?a(e):a({workers:1,fileTimeoutSeconds:m})}export function detectNextApp(e){return n.existsSync(i.join(e,"next.config.js"))||n.existsSync(i.join(e,"next.config.mjs"))||n.existsSync(i.join(e,"next.config.ts"))}function c(e){return e!==null&&typeof e=="object"}export{normalizeConfiguredStep as normalizeTemplateLifecycleStep,normalizeConfiguredSteps as normalizeTemplateLifecycleSteps,normalizeOptionalString,parseModuleSpecifier}from"../../steps/configured-steps.js";
1
+ import t from"fs";import i from"path";import{DEFAULT_FILE_TIMEOUT_SECONDS as c}from"../../domain/file-timeout.js";import{normalizeExecutionConfig as u,normalizeRuntimeMaxConcurrentTasks as f,normalizeRuntimeInstances as l}from"./decode-execution.js";import"./execution-model.js";import{normalizeConfiguredInputs as S,normalizeConfiguredSteps as x}from"../../steps/configured-steps.js";import{buildConfigToPrepare as C,normalizeBuildConfig as T}from"../../steps/build-config.js";import{normalizeRuntimeToolchain as z}from"../../toolchains/index.js";import{isNonNullObject as m}from"../../kernel/unknown-values.js";export function normalizeRuntimeConfig(e,n,a){if(!e)return{build:null,instances:1,maxConcurrentTasks:Number.POSITIVE_INFINITY,prepare:{inputs:[],steps:[]},toolchain:null};const r=m(e)?e:{},o=T(r.build,`Service "${n}" runtime.build`),s=normalizeRuntimePrepareConfig(r.prepare,n),p=C(o);return{build:o,instances:l(r.instances??1,`Service "${n}" runtime.instances`),maxConcurrentTasks:f(r.maxConcurrentTasks,`Service "${n}" runtime.maxConcurrentTasks`),prepare:{inputs:[...new Set([...p.inputs,...s.inputs])],steps:[...p.steps,...s.steps]},toolchain:z(r.toolchain,`Service "${n}" runtime.toolchain`,a||{})}}export function normalizeRuntimePrepareConfig(e,n){if(e==null)return{inputs:[],steps:[]};if(!m(e))throw new Error(`Service "${n}" runtime.prepare must be an object`);return{inputs:S(e.inputs,`Service "${n}" runtime.prepare`),steps:x(e.steps,`Service "${n}" runtime.prepare.steps`)}}export function normalizeRepoExecution(e){return e?u(e):u({workers:1,fileTimeoutSeconds:c})}export function detectNextApp(e){return t.existsSync(i.join(e,"next.config.js"))||t.existsSync(i.join(e,"next.config.mjs"))||t.existsSync(i.join(e,"next.config.ts"))}export{normalizeConfiguredStep as normalizeTemplateLifecycleStep,normalizeConfiguredSteps as normalizeTemplateLifecycleSteps,parseModuleSpecifier}from"../../steps/configured-steps.js";
@@ -1 +1 @@
1
- import{isObjectRecord as y}from"./values.js";import{matchesSuiteSelectors as k,parseSuiteSelectors as q}from"../../domain/suite-selection.js";import{normalizePath as E}from"./paths.js";const S=String;export function normalizeSkipReason(s,e){const u=S(s||"").trim();if(!u)throw new Error(`${e} requires a non-empty reason`);return u}export function normalizeSkipConfig(s,{name:e,suites:u}){if(!s)return;const f=b(s,`Service "${e}" skip`),l=new Set,a=[];for(const t of Object.values(u))for(const i of t||[]){a.push({testType:i.testType,name:i.name});for(const r of i.files)l.add(E(r))}const c=new Set,p=[];for(const t of m(f.files,`Service "${e}" skip.files`)){const i=$(t,`Service "${e}" skip.files entries must be objects`),r=E(typeof i.path=="string"?i.path:void 0),o=normalizeSkipReason(i.reason,`Service "${e}" skip.files["${r}"]`);if(!r)throw new Error(`Service "${e}" skip.files entries require a non-empty path`);if(c.has(r))throw new Error(`Service "${e}" defines duplicate skip.files path "${r}"`);if(!l.has(r))throw new Error(`Service "${e}" skip.files path "${r}" did not match any discovered suite file`);c.add(r),p.push({path:r,reason:o})}const d=m(f.suites,`Service "${e}" skip.suites`).map((t,i)=>{const r=$(t,`Service "${e}" skip.suites entries must be objects`),o=S(r.selector||"").trim();if(!o)throw new Error(`Service "${e}" skip.suites[${String(i)}] requires a non-empty selector`);const v=normalizeSkipReason(r.reason,`Service "${e}" skip.suites["${o}"]`),w=q([o]),g=w[0];if(w.length!==1)throw new Error(`Service "${e}" skip.suites["${o}"] is invalid`);return{selector:g,reason:v}}),h=new Set,n=[];for(const t of d){if(h.has(t.selector.raw))throw new Error(`Service "${e}" defines duplicate skip.suites selector "${t.selector.raw}"`);if(!a.some(r=>k(r.testType,r.name,[t.selector])))throw new Error(`Service "${e}" skip.suites selector "${t.selector.raw}" did not match any discovered suite`);h.add(t.selector.raw),n.push(t)}if(!(p.length===0&&n.length===0))return{files:p,fileReasonByPath:new Map(p.map(t=>[t.path,t.reason])),suites:n}}export function normalizeServiceRequirements(s,{name:e,suites:u}){if(!s)return R();const f=b(s,`Service "${e}" requirements`),l=[],a=new Set;for(const n of Object.values(u))for(const t of n||[]){l.push({testType:t.testType,name:t.name});for(const i of t.files)a.add(i)}const c=[],p=new Set;for(const n of m(f.suites,`Service "${e}" requirements.suites`)){const t=$(n,`Service "${e}" requirements.suites entries must be objects`),i=S(t.selector||"").trim();if(!i)throw new Error(`Service "${e}" requirements.suites entries require a selector`);const r=q([i]),o=r[0];if(r.length!==1)throw new Error(`Service "${e}" requirements.suites["${i}"] is invalid`);if(o.kind!=="typed")throw new Error(`Service "${e}" requirements.suites["${i}"] must use a typed selector like int:health`);if(p.has(o.raw))throw new Error(`Service "${e}" defines duplicate requirements.suites selector "${o.raw}"`);if(!l.some(w=>k(w.testType,w.name,[o])))throw new Error(`Service "${e}" requirements.suites selector "${o.raw}" did not match any discovered suite`);p.add(o.raw),c.push({selector:o,locks:normalizeRequirementLocks(t.locks,`Service "${e}" requirements.suites["${o.raw}"].locks`)})}const d=[],h=new Set;for(const[n,t]of m(f.files,`Service "${e}" requirements.files`).entries()){const i=$(t,`Service "${e}" requirements.files entries must be objects`),r=S(i.path||"").trim();if(!r)throw new Error(`Service "${e}" requirements.files[${String(n)}] requires a path`);if(!a.has(r))throw new Error(`Service "${e}" requirements.files["${r}"] did not match any discovered test file`);if(h.has(r))throw new Error(`Service "${e}" defines duplicate requirements.files path "${r}"`);h.add(r),d.push({path:r,locks:normalizeRequirementLocks(i.locks,`Service "${e}" requirements.files["${r}"].locks`)})}return{suites:c,files:d,fileLocksByPath:new Map(d.map(n=>[n.path,n.locks]))}}export function normalizeRequirementLocks(s,e){const u=Array.isArray(s)?s:s==null?[]:[s],f=new Set,l=[];for(const a of u){const c=S(a||"").trim();if(!c)throw new Error(`${e} entries must be non-empty strings`);f.has(c)||(f.add(c),l.push(c))}return l.sort()}function R(){return{suites:[],files:[],fileLocksByPath:new Map}}function b(s,e){if(!y(s))throw new Error(`${e} must be an object`);return s}function $(s,e){if(!y(s))throw new Error(e);return s}function m(s,e){if(s==null)return[];if(!Array.isArray(s))throw new Error(`${e} must be an array`);return s}
1
+ import{isTypedTestFile as y}from"../../domain/identifiers.js";import{matchesSuiteSelectors as q,parseSuiteSelectors as S}from"../../domain/suite-selection.js";import{normalizePath as E}from"./paths.js";import{isUnknownRecord as b}from"../../kernel/unknown-values.js";import{requireObjectRecord as g}from"../../evidence/read-fields.js";const $=String;export function normalizeSkipReason(r,e){const a=$(r||"").trim();if(!a)throw new Error(`${e} requires a non-empty reason`);return a}export function normalizeSkipConfig(r,{owner:e,plainListed:a=!0,suites:u}){if(!r)return;const l=g(r,`${e} skip`),p=new Set(u.flatMap(s=>s.files.map(E))),c=new Set,f=[];for(const s of optionalArray(l.files,`${e} skip.files`)){const n=k(s,`${e} skip.files entries must be objects`),t=E(typeof n.path=="string"?n.path:void 0),i=normalizeSkipReason(n.reason,`${e} skip.files["${t}"]`);if(!t)throw new Error(`${e} skip.files entries require a non-empty path`);if(c.has(t))throw new Error(`${e} defines duplicate skip.files path "${t}"`);if(!p.has(t)&&(a||y(t)))throw new Error(`${e} skip.files path "${t}" did not match any discovered suite file`);c.add(t),f.push({path:t,reason:i})}const m=optionalArray(l.suites,`${e} skip.suites`).map((s,n)=>{const t=k(s,`${e} skip.suites entries must be objects`),i=$(t.selector||"").trim();if(!i)throw new Error(`${e} skip.suites[${String(n)}] requires a non-empty selector`);const w=normalizeSkipReason(t.reason,`${e} skip.suites["${i}"]`),h=S([i]),R=h[0];if(h.length!==1)throw new Error(`${e} skip.suites["${i}"] is invalid`);return{selector:R,reason:w}}),d=new Set,o=[];for(const s of m){if(d.has(s.selector.raw))throw new Error(`${e} defines duplicate skip.suites selector "${s.selector.raw}"`);if(!u.some(t=>q(t.testType,t.name,[s.selector]))&&(a||s.selector.kind==="typed"))throw new Error(`${e} skip.suites selector "${s.selector.raw}" did not match any discovered suite`);d.add(s.selector.raw),o.push(s)}if(!(f.length===0&&o.length===0))return{files:f,fileReasonByPath:new Map(f.map(s=>[s.path,s.reason])),suites:o}}export function normalizeServiceRequirements(r,{owner:e,plainListed:a=!0,suites:u}){if(!r)return x();const l=g(r,`${e} requirements`),p=new Set(u.flatMap(o=>o.files)),c=[],f=new Set;for(const o of optionalArray(l.suites,`${e} requirements.suites`)){const s=k(o,`${e} requirements.suites entries must be objects`),n=$(s.selector||"").trim();if(!n)throw new Error(`${e} requirements.suites entries require a selector`);const t=S([n]),i=t[0];if(t.length!==1)throw new Error(`${e} requirements.suites["${n}"] is invalid`);if(i.kind!=="typed")throw new Error(`${e} requirements.suites["${n}"] must use a typed selector like contract:health`);if(f.has(i.raw))throw new Error(`${e} defines duplicate requirements.suites selector "${i.raw}"`);if(!u.some(h=>q(h.testType,h.name,[i])))throw new Error(`${e} requirements.suites selector "${i.raw}" did not match any discovered suite`);f.add(i.raw),c.push({selector:i,locks:normalizeRequirementLocks(s.locks,`${e} requirements.suites["${i.raw}"].locks`)})}const m=[],d=new Set;for(const[o,s]of optionalArray(l.files,`${e} requirements.files`).entries()){const n=k(s,`${e} requirements.files entries must be objects`),t=$(n.path||"").trim();if(!t)throw new Error(`${e} requirements.files[${String(o)}] requires a path`);if(!p.has(t)&&(a||y(t)))throw new Error(`${e} requirements.files["${t}"] did not match any discovered test file`);if(d.has(t))throw new Error(`${e} defines duplicate requirements.files path "${t}"`);d.add(t),m.push({path:t,locks:normalizeRequirementLocks(n.locks,`${e} requirements.files["${t}"].locks`)})}return{suites:c,files:m,fileLocksByPath:new Map(m.map(o=>[o.path,o.locks]))}}export function normalizeRequirementLocks(r,e){const a=Array.isArray(r)?r:r==null?[]:[r],u=new Set,l=[];for(const p of a){const c=$(p||"").trim();if(!c)throw new Error(`${e} entries must be non-empty strings`);u.has(c)||(u.add(c),l.push(c))}return l.sort()}function x(){return{suites:[],files:[],fileLocksByPath:new Map}}function k(r,e){if(!b(r))throw new Error(e);return r}export function optionalArray(r,e){if(r==null)return[];if(!Array.isArray(r))throw new Error(`${e} must be an array`);return r}
@@ -0,0 +1 @@
1
+ import{matchesSuiteSelectors as a}from"../../domain/suite-selection.js";import{normalizePath as l}from"./paths.js";import{resolveRuntimeIsolationPolicy as i}from"./runtime-isolation.js";export function resolveTaskPolicy(o,t,r){return{locks:m(o,t,r),runtimeIsolation:i({testkit:o},t,r)}}function m(o,t,r){const n=l(r),s=new Set;for(const e of o.requirements.suites)if(a(t.testType,t.name,[e.selector]))for(const c of e.locks)s.add(c);for(const e of o.requirements.fileLocksByPath.get(n)??[])s.add(e);for(const e of o.fileMetadataByPath.get(n)?.locks??[])s.add(e);return[...s].sort()}
@@ -1 +1 @@
1
- import{matchesSelectedTypes as a,matchesSuiteSelectors as u}from"../../domain/suite-selection.js";import{isPublicTestType as p}from"../../domain/identifiers.js";export function selectDiscoveredSuites(t,e){const s=new Set(e.fileNames?.map(l));return Object.fromEntries(Object.entries(t).map(([i,o])=>[i,e.service&&i!==e.service?{}:Object.fromEntries(Object.entries(o??{}).filter(([n])=>a(n,e.typeValues??[])).map(([n,f])=>[n,f.filter(r=>u(n,r.name,e.suiteSelectors??[])).flatMap(r=>{const c=s.size?r.files.filter(m=>s.has(l(m))):r.files;return c.length?[{...r,files:c}]:[]})]))]))}export function discoveredRuleSuites(t){return Object.fromEntries(Object.entries(t).map(([e,s])=>{if(!p(e))throw new Error(`Unknown discovered test type ${e}`);return[e,s.map(i=>({...i,testType:e}))]}))}function l(t){return t.replaceAll("\\","/")}
1
+ import{isTypedTestFile as o}from"../../domain/identifiers.js";import{matchesSelectedTypes as i,matchesSuiteSelectors as a}from"../../domain/suite-selection.js";export function selectDiscoveredSuites(r,e){const l=new Set(e.fileNames?.map(p));return Object.fromEntries(Object.entries(r).map(([s,f])=>[s,e.group&&s!==e.group?[]:(f??[]).filter(t=>i(t.testType,e.typeValues??[])&&a(t.testType,t.name,e.suiteSelectors??[])).flatMap(t=>{const n=l.size?t.files.filter(c=>l.has(p(c))):t.files;return n.length?[{...t,files:n}]:[]})]))}export function selectsOnlyTypedFiles({fileNames:r=[],typeValues:e=[]}){return!i(void 0,e)||r.length>0&&r.every(o)}function p(r){return r.replaceAll("\\","/")}
@@ -1 +1 @@
1
- import{finalizeConfiguredInputs as l,finalizeConfiguredSteps as w,validateConfiguredCollection as d}from"../../steps/configured-steps.js";import{findDatabasePlaceholders as h}from"../../steps/environment.js";import{resolveEngineProfile as S}from"../../engines/catalog.js";import{ensureExistingContainedPath as g,ensureExistingPath as E}from"./paths.js";const m=["migrate","seed","verify"];export function validateConfigCoverage(e){const i=new Set(e.map(r=>r.name));for(const r of e){for(const t of r.testkit.dependsOn)if(!i.has(t))throw new Error(`Service "${r.name}" depends on "${t}", but ${t} is not defined`);const n=r.testkit.databaseFrom;if(n&&!i.has(n))throw new Error(`Service "${r.name}" databaseFrom "${n}" is not defined`)}}export function validateServiceConfig({name:e,local:i,database:r,databaseFrom:n,runtime:t,dependsOn:c,suites:p,productDir:s,requireLocalRuntime:v=!0}){const $=Object.entries(p).some(([a,u])=>(u||[]).some(o=>{if(o.testType!==a)throw new Error(`Service "${e}" suite ${a}:${o.name} declares conflicting test type ${o.testType}`);const f=S(o.testType,o.engineId);if(f.id!==o.profileId)throw new Error(`Service "${e}" suite ${o.testType}:${o.name} declares conflicting engine profile ${o.profileId}; expected ${f.id}`);return f.capabilities.applicationRuntime==="required"}));if(v&&$&&!i)throw new Error(`Service "${e}" defines suites whose engine profile requires an application runtime, but no local runtime could be resolved. Add it in testkit.config.ts.`);if(r&&n)throw new Error(`Service "${e}" cannot define both database and databaseFrom`);if(t.instances<1)throw new Error(`Service "${e}" runtime.instances must be a positive integer`);if(t.maxConcurrentTasks<=0)throw new Error(`Service "${e}" runtime.maxConcurrentTasks must be a positive integer when provided`);for(const a of c)if(a===e)throw new Error(`Service "${e}" cannot depend on itself`);if(b({name:e,local:i,database:r,runtime:t}),i?.cwd&&E(s,i.cwd,`Service "${e}" local.cwd`),t.toolchain?.cwd&&g(s,t.toolchain.cwd,`Service "${e}" runtime.toolchain.cwd`),r)for(const a of m)d({productDir:s,label:`Service "${e}" database.template.${a}`,steps:r.template[a]});d({productDir:s,label:`Service "${e}" database.template`,inputs:r?.template.inputs||[]}),d({productDir:s,label:`Service "${e}" runtime.prepare`,inputs:t.prepare.inputs,steps:t.prepare.steps})}function b({name:e,local:i,database:r,runtime:n}){const t=c=>p=>{const s=h(p).at(0);if(s)throw new Error(`Service "${e}" ${c} uses ${s.placeholder}. Database placeholders resolve only in env values; commands read DATABASE_URL or a service env entry at run time.`);return p};if(i&&(t("local.start")(i.start),t("local.cwd")(i.cwd)),l(n.prepare.inputs,t("runtime.prepare.inputs")),w(n.prepare.steps,t("runtime.prepare.steps")),r){l(r.template.inputs,t("database.template.inputs"));for(const c of m)w(r.template[c],t(`database.template.${c}`))}}
1
+ import{finalizeConfiguredInputs as c,finalizeConfiguredSteps as f,validateConfiguredCollection as p}from"../../steps/configured-steps.js";import{findDatabasePlaceholders as l}from"../../steps/environment.js";import{ensureExistingContainedPath as v,ensureExistingPath as m}from"./paths.js";const d=["migrate","seed","verify"];export function validateConfigCoverage(t){const n=new Set(t.map(r=>r.name));for(const r of t){for(const e of r.testkit.dependsOn)if(!n.has(e))throw new Error(`Service "${r.name}" depends on "${e}", but ${e} is not defined`);const o=r.testkit.databaseFrom;if(o&&!n.has(o))throw new Error(`Service "${r.name}" databaseFrom "${o}" is not defined`)}}export function validateServiceConfig({name:t,local:n,database:r,databaseFrom:o,runtime:e,dependsOn:s,productDir:i}){if(r&&o)throw new Error(`Service "${t}" cannot define both database and databaseFrom`);if(e.instances<1)throw new Error(`Service "${t}" runtime.instances must be a positive integer`);if(e.maxConcurrentTasks<=0)throw new Error(`Service "${t}" runtime.maxConcurrentTasks must be a positive integer when provided`);for(const a of s)if(a===t)throw new Error(`Service "${t}" cannot depend on itself`);if(w({name:t,local:n,database:r,runtime:e}),n?.cwd&&m(i,n.cwd,`Service "${t}" local.cwd`),e.toolchain?.cwd&&v(i,e.toolchain.cwd,`Service "${t}" runtime.toolchain.cwd`),r)for(const a of d)p({productDir:i,label:`Service "${t}" database.template.${a}`,steps:r.template[a]});p({productDir:i,label:`Service "${t}" database.template`,inputs:r?.template.inputs||[]}),p({productDir:i,label:`Service "${t}" runtime.prepare`,inputs:e.prepare.inputs,steps:e.prepare.steps})}function w({name:t,local:n,database:r,runtime:o}){const e=s=>i=>{const a=l(i).at(0);if(a)throw new Error(`Service "${t}" ${s} uses ${a.placeholder}. Database placeholders resolve only in env values; commands read DATABASE_URL or a service env entry at run time.`);return i};if(n&&(e("local.start")(n.start),e("local.cwd")(n.cwd)),c(o.prepare.inputs,e("runtime.prepare.inputs")),f(o.prepare.steps,e("runtime.prepare.steps")),r){c(r.template.inputs,e("database.template.inputs"));for(const s of d)f(r.template[s],e(`database.template.${s}`))}}
@@ -1 +1 @@
1
- import{AsyncLocalStorage as p}from"node:async_hooks";import n from"node:fs";import h from"node:os";import c from"node:path";import{withProcessLock as E}from"../process/locks.js";import{hashString as u}from"./naming.js";const S=Object.freeze([".testkit","_locks","local-postgres"]),P=448,m=18,f=new p;export async function withUserHostLocalPostgresActivity(t,o,e={}){$();const r=e.location??readSystemUserHostLocalPostgresActivityLocation(),s=D(r),i=L(s.productsDirectory,t);return f.run(!0,()=>E(i,o,{hostScope:"current-host",signal:e.signal}))}export function resolveUserHostLocalPostgresActivityPaths({homeDirectory:t,hostname:o,uid:e,username:r}){const s=c.resolve(a(t,"home directory")),i=a(o,"hostname").trim().toLowerCase(),l=a(r,"username").trim().toLowerCase();if(!Number.isSafeInteger(e))throw new Error("Local Postgres activity gate requires a valid user ID");const w=e>=0?`uid:${e.toString()}`:`username:${l}`,y=c.join(s,...S,`host-${u(i,24)}-user-${u(w,24)}`);return Object.freeze({activityDirectory:y,productsDirectory:c.join(y,"products")})}export function readSystemUserHostLocalPostgresActivityLocation(){const t=h.userInfo();return{homeDirectory:t.homedir,hostname:h.hostname(),uid:t.uid,username:t.username}}function D(t){const o=k(t.homeDirectory,t.uid),e=resolveUserHostLocalPostgresActivityPaths({...t,homeDirectory:o});let r=o;const s=c.relative(o,e.activityDirectory).split(c.sep);for(const i of s)r=v(c.join(r,i),o,t.uid);return v(e.productsDirectory,o,t.uid),e}function L(t,o){const e=n.realpathSync.native(c.resolve(a(o,"product directory")));return c.join(t,`product-${u(e,24)}.lock`)}function k(t,o){const e=c.resolve(a(t,"home directory"));if(!n.statSync(e).isDirectory())throw new Error(`Cannot use non-directory home for the local Postgres activity gate: ${e}`);const s=n.realpathSync.native(e);return d(s,!1,o),s}function v(t,o,e){let r;try{r=n.lstatSync(t)}catch(i){if(!g(i,"ENOENT"))throw i;try{n.mkdirSync(t,{mode:P})}catch(l){if(!g(l,"EEXIST"))throw l}r=n.lstatSync(t)}if(!r.isDirectory()||r.isSymbolicLink())throw new Error(`Local Postgres activity lock ancestor is not a real directory: ${t}`);const s=n.realpathSync.native(t);return A(s,o),d(s,!0,e),s}function d(t,o,e){if(e<0)return;let r=n.lstatSync(t);if(r.uid!==e)throw new Error(`Local Postgres activity lock ancestor is not owned by the current user: ${t}`);if((r.mode&m)!==0){if(!o)throw new Error(`Local Postgres activity lock ancestor is writable by another user: ${t}`);if(n.chmodSync(t,r.mode&511&~m),r=n.lstatSync(t),(r.mode&m)!==0)throw new Error(`Could not secure local Postgres activity lock ancestor: ${t}`)}}function A(t,o){const e=c.relative(o,t);if(e===".."||e.startsWith(`..${c.sep}`)||c.isAbsolute(e))throw new Error(`Local Postgres activity lock escaped the user home: ${t}`)}function $(){if(f.getStore()!==void 0)throw new Error("Nested local Postgres activity is not allowed")}function a(t,o){if(t.trim().length===0)throw new Error(`Local Postgres activity gate requires a ${o}`);return t}function g(t,o){return typeof t=="object"&&t!==null&&"code"in t&&Reflect.get(t,"code")===o}
1
+ import{AsyncLocalStorage as p}from"node:async_hooks";import c from"node:fs";import y from"node:os";import i from"node:path";import{withProcessLock as E}from"../process/locks.js";import{hashString as u}from"./naming.js";import{hasErrorCode as f}from"../kernel/error-serialization.js";const S=Object.freeze([".testkit","_locks","local-postgres"]),P=448,m=18,v=new p;export async function withUserHostLocalPostgresActivity(t,o,r={}){$();const e=r.location??readSystemUserHostLocalPostgresActivityLocation(),s=D(e),n=L(s.productsDirectory,t);return v.run(!0,()=>E(n,o,{hostScope:"current-host",signal:r.signal}))}export function resolveUserHostLocalPostgresActivityPaths({homeDirectory:t,hostname:o,uid:r,username:e}){const s=i.resolve(a(t,"home directory")),n=a(o,"hostname").trim().toLowerCase(),l=a(e,"username").trim().toLowerCase();if(!Number.isSafeInteger(r))throw new Error("Local Postgres activity gate requires a valid user ID");const g=r>=0?`uid:${r.toString()}`:`username:${l}`,h=i.join(s,...S,`host-${u(n,24)}-user-${u(g,24)}`);return Object.freeze({activityDirectory:h,productsDirectory:i.join(h,"products")})}export function readSystemUserHostLocalPostgresActivityLocation(){const t=y.userInfo();return{homeDirectory:t.homedir,hostname:y.hostname(),uid:t.uid,username:t.username}}function D(t){const o=k(t.homeDirectory,t.uid),r=resolveUserHostLocalPostgresActivityPaths({...t,homeDirectory:o});let e=o;const s=i.relative(o,r.activityDirectory).split(i.sep);for(const n of s)e=d(i.join(e,n),o,t.uid);return d(r.productsDirectory,o,t.uid),r}function L(t,o){const r=c.realpathSync.native(i.resolve(a(o,"product directory")));return i.join(t,`product-${u(r,24)}.lock`)}function k(t,o){const r=i.resolve(a(t,"home directory"));if(!c.statSync(r).isDirectory())throw new Error(`Cannot use non-directory home for the local Postgres activity gate: ${r}`);const s=c.realpathSync.native(r);return w(s,!1,o),s}function d(t,o,r){let e;try{e=c.lstatSync(t)}catch(n){if(!f(n,"ENOENT"))throw n;try{c.mkdirSync(t,{mode:P})}catch(l){if(!f(l,"EEXIST"))throw l}e=c.lstatSync(t)}if(!e.isDirectory()||e.isSymbolicLink())throw new Error(`Local Postgres activity lock ancestor is not a real directory: ${t}`);const s=c.realpathSync.native(t);return A(s,o),w(s,!0,r),s}function w(t,o,r){if(r<0)return;let e=c.lstatSync(t);if(e.uid!==r)throw new Error(`Local Postgres activity lock ancestor is not owned by the current user: ${t}`);if((e.mode&m)!==0){if(!o)throw new Error(`Local Postgres activity lock ancestor is writable by another user: ${t}`);if(c.chmodSync(t,e.mode&511&~m),e=c.lstatSync(t),(e.mode&m)!==0)throw new Error(`Could not secure local Postgres activity lock ancestor: ${t}`)}}function A(t,o){const r=i.relative(o,t);if(r===".."||r.startsWith(`..${i.sep}`)||i.isAbsolute(r))throw new Error(`Local Postgres activity lock escaped the user home: ${t}`)}function $(){if(v.getStore()!==void 0)throw new Error("Nested local Postgres activity is not allowed")}function a(t,o){if(t.trim().length===0)throw new Error(`Local Postgres activity gate requires a ${o}`);return t}
@@ -1,2 +1,2 @@
1
- import{randomUUID as T}from"node:crypto";import{managedHostProcessInfrastructureError as g,runManagedHostProcess as E}from"../process/index.js";import{LOCAL_ADMIN_DB as u,LOCAL_ADMIN_QUERY_RETRY_INTERVAL_MS as f,LOCAL_ADMIN_QUERY_RETRY_MS as S,LOCAL_DROP_DATABASE_POLL_INTERVAL_MS as O,LOCAL_DROP_DATABASE_TIMEOUT_MS as R}from"./constants.js";import{buildDatabaseUrl as y,escapeIdentifier as c,escapeSqlLiteral as l}from"./naming.js";import{runDockerPsql as b}from"./postgres/index.js";export{y as buildDatabaseUrl};export const ADMIN_QUERY_COMMAND_TIMEOUT_MS=15e3;export async function databaseExists(t,e,o={}){return(await runAdminQuery(t,["-tAc",`SELECT 1 FROM pg_database WHERE datname = '${l(e)}'`],o)).trim()==="1"}export async function createEmptyDatabase(t,e,o={}){await runAdminQuery(t,["-c",`CREATE DATABASE "${c(e)}"`],o)}export async function cloneDatabaseFromTemplate(t,e,o,r={}){await runAdminQuery(t,["-c",`CREATE DATABASE "${c(e)}" TEMPLATE "${c(o)}"`],r)}export async function dropDatabaseIfExists(t,e,o={}){await dropDatabaseWithForceOrDrain(t,e,o)}export async function dropDatabaseWithForceOrDrain(t,e,o={}){const r={signal:o.signal};try{await runAdminQuery(t,["-c",`DROP DATABASE IF EXISTS "${c(e)}" WITH (FORCE)`],r);return}catch(n){if(!M(n))throw n}if(!await databaseExists(t,e,r))return;let s=!1;try{await runAdminQuery(t,["-c",`ALTER DATABASE "${c(e)}" WITH ALLOW_CONNECTIONS false`],r),s=!0,await waitForDatabaseConnectionsToDrain(t,e,{signal:o.signal}),await runAdminQuery(t,["-c",`DROP DATABASE IF EXISTS "${c(e)}"`],r),s=!1}finally{s&&await databaseExists(t,e)&&await runAdminQuery(t,["-c",`ALTER DATABASE "${c(e)}" WITH ALLOW_CONNECTIONS true`]).catch(()=>{})}}export async function waitForDatabaseConnectionsToDrain(t,e,o={}){const r=o.timeoutMs??R,s=Date.now()+r,n={signal:o.signal};for(;;){D(o.signal),await C(t,e,n);const i=await L(t,e,n);if(i===0)return;if(Date.now()>=s)throw new Error(`Timed out waiting for database "${e}" connections to close (${String(i)} remaining)`);await A(O,o.signal)}}export async function runAdminQuery(t,e,o={}){const r=buildAdminQueryCommandArgs(t,e),s=Date.now();for(;;){D(o.signal);try{let n;if(_(t)){const a=`testkit-admin-${T()}`,d=await E({args:["exec","-e",`PGAPPNAME=${a}`,...r.slice(1)],cwd:process.cwd(),displayLabel:`Docker Postgres admin query for ${t.containerName}`,env:process.env,executable:"docker",signal:o.signal,timeoutMs:ADMIN_QUERY_COMMAND_TIMEOUT_MS});d.cancelled&&await E({args:buildAdminQueryCommandArgs(t,["-tAc",`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE application_name = '${a}'`]),cwd:process.cwd(),displayLabel:`Docker Postgres admin query cancellation for ${t.containerName}`,env:process.env,executable:"docker",timeoutMs:ADMIN_QUERY_COMMAND_TIMEOUT_MS});const m=g(`Docker Postgres admin query for ${t.containerName}`,d);if(m)throw m;n={exitCode:d.exitCode,stderr:d.stderr,stdout:d.stdout}}else{const a={...process.env,PGPASSWORD:t.password,...t.sslMode?{PGSSLMODE:t.sslMode}:{}};n=await b({args:r,env:a,timeoutMs:ADMIN_QUERY_COMMAND_TIMEOUT_MS,connection:{host:t.host,port:t.port,user:t.user,password:t.password,database:t.adminDatabase||u,sslMode:t.sslMode},signal:o.signal})}if(n.exitCode!=null&&n.exitCode!==0){const a=new Error(n.shortMessage||n.stderr||n.stdout||`psql failed with exit code ${String(n.exitCode)}`);throw Reflect.set(a,"stdout",n.stdout||""),Reflect.set(a,"stderr",n.stderr||""),a}const{stdout:i}=n;return i}catch(n){if(Date.now()-s>=S||!isTransientAdminQueryConnectionError(n))throw n;await A(f,o.signal)}}}export function buildAdminQueryCommandArgs(t,e){return _(t)?["exec","-e",`PGPASSWORD=${t.password}`,t.containerId,"psql","-v","ON_ERROR_STOP=1","-U",t.user,"-d",t.adminDatabase||u,"-p",String(t.containerPort||5432),...e]:["-v","ON_ERROR_STOP=1","-h",t.host,"-p",String(t.port),"-U",t.user,"-d",t.adminDatabase||u,...e]}export function isTransientAdminQueryConnectionError(t){const e=w(t);return e.includes('connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed')||e.includes("No such file or directory")||e.includes("the database system is starting up")||e.includes("could not connect to server")||e.includes("connection refused")||e.includes("Connection timed out")||e.includes("connection timed out")||e.includes("Operation timed out")||e.includes("i/o timeout")||e.includes("server closed the connection unexpectedly")||e.includes("terminating connection due to administrator command")}async function C(t,e,o){await runAdminQuery(t,["-c",["SELECT pg_terminate_backend(pid)","FROM pg_stat_activity",`WHERE datname = '${l(e)}' AND pid <> pg_backend_pid();`].join(" ")],o)}async function L(t,e,o){const r=await runAdminQuery(t,["-tAc",["SELECT COUNT(*)","FROM pg_stat_activity",`WHERE datname = '${l(e)}' AND pid <> pg_backend_pid();`].join(" ")],o);return Number.parseInt(r.trim(),10)||0}function M(t){const e=w(t);return e.includes('syntax error at or near "WITH"')||e.includes('option "force"')}function A(t,e){return new Promise((o,r)=>{if(e?.aborted){r(p(e));return}const s=setTimeout(n,t);e?.addEventListener("abort",i,{once:!0});function n(){e?.removeEventListener("abort",i),o()}function i(){clearTimeout(s),r(e?p(e):new Error("Database administration aborted"))}})}function D(t){if(t?.aborted)throw p(t)}function p(t){return t.reason instanceof Error?t.reason:new Error("Database administration aborted",{cause:t.reason})}function w(t){return["shortMessage","stderr","stdout","message"].map(e=>P(x(t,e)||"")).join(`
2
- `)}function x(t,e){if(!(typeof t!="object"&&typeof t!="function"||t===null))return Reflect.get(t,e)}function P(t){if(typeof t=="symbol")throw new TypeError("Cannot convert a Symbol value to a string");return String(t)}function _(t){return!!t.containerName}
1
+ import{randomUUID as y}from"node:crypto";import{managedHostProcessInfrastructureError as R,runManagedHostProcess as C,startManagedHostProcess as M}from"../process/index.js";import{LOCAL_ADMIN_DB as p,LOCAL_ADMIN_QUERY_RETRY_INTERVAL_MS as L,LOCAL_ADMIN_QUERY_RETRY_MS as x,LOCAL_DROP_DATABASE_POLL_INTERVAL_MS as P,LOCAL_DROP_DATABASE_TIMEOUT_MS as h}from"./constants.js";import{buildDatabaseUrl as I,escapeIdentifier as c,escapeSqlLiteral as E}from"./naming.js";import{runDockerPsql as $}from"./postgres/index.js";import{readDynamicProperty as v}from"../kernel/unknown-values.js";export{I as buildDatabaseUrl};export const ADMIN_QUERY_COMMAND_TIMEOUT_MS=15e3;export async function databaseExists(t,e,o={}){return(await runAdminQuery(t,["-tAc",`SELECT 1 FROM pg_database WHERE datname = '${E(e)}'`],o)).trim()==="1"}export async function createEmptyDatabase(t,e,o={}){await runAdminQuery(t,["-c",`CREATE DATABASE "${c(e)}"`],o)}export async function cloneDatabaseFromTemplate(t,e,o,r={}){await runAdminQuery(t,["-c",`CREATE DATABASE "${c(e)}" TEMPLATE "${c(o)}"`],r)}export async function dropDatabaseWithForceOrDrain(t,e,o={}){const r={signal:o.signal};try{await runAdminQuery(t,["-c",`DROP DATABASE IF EXISTS "${c(e)}" WITH (FORCE)`],r);return}catch(n){if(!W(n))throw n}if(!await databaseExists(t,e,r))return;let s=!1;try{await runAdminQuery(t,["-c",`ALTER DATABASE "${c(e)}" WITH ALLOW_CONNECTIONS false`],r),s=!0,await waitForDatabaseConnectionsToDrain(t,e,{signal:o.signal}),await runAdminQuery(t,["-c",`DROP DATABASE IF EXISTS "${c(e)}"`],r),s=!1}finally{s&&await databaseExists(t,e)&&await runAdminQuery(t,["-c",`ALTER DATABASE "${c(e)}" WITH ALLOW_CONNECTIONS true`]).catch(()=>{})}}export async function waitForDatabaseConnectionsToDrain(t,e,o={}){const r=o.timeoutMs??h,s=Date.now()+r,n={signal:o.signal};for(;;){O(o.signal),await N(t,e,n);const i=await k(t,e,n);if(i===0)return;if(Date.now()>=s)throw new Error(`Timed out waiting for database "${e}" connections to close (${String(i)} remaining)`);await A(P,o.signal)}}export async function runAdminQuery(t,e,o={}){const r=buildAdminQueryCommandArgs(t,e),s=Date.now();for(;;){O(o.signal);try{let n;if(b(t)){const a=`testkit-admin-${y()}`,D=(l,m)=>C({args:buildAdminQueryCommandArgs(t,["-tAc",`SELECT ${l} FROM pg_stat_activity WHERE application_name = '${a}'`]),cwd:process.cwd(),displayLabel:`Docker Postgres admin session for ${t.containerName}`,env:process.env,executable:"docker",signal:m,timeoutMs:ADMIN_QUERY_COMMAND_TIMEOUT_MS}),_=M({args:["exec","-e",`PGAPPNAME=${a}`,...r.slice(1)],cwd:process.cwd(),displayLabel:`Docker Postgres admin query for ${t.containerName}`,env:process.env,executable:"docker",outputMode:"bounded-capture",recoveryIdentity:"none",signal:o.signal,timeoutMs:null}),d=new AbortController,f=(async()=>{for(let l=0;l<2;){await A(ADMIN_QUERY_COMMAND_TIMEOUT_MS,d.signal);const m=await D("count(*)",d.signal);if(d.signal.aborted)return;if(m.timedOut||m.exitCode!==0)break;l=m.stdout.trim()==="0"?l+1:0}d.abort("stalled"),await _.stop()})().catch(()=>{}),u=await _.completion.finally(()=>{d.abort()});await f;const g=d.signal.reason==="stalled";(u.cancelled||g)&&await D("pg_terminate_backend(pid)");const T=R(`Docker Postgres admin query for ${t.containerName}`,g?{...u,timedOut:!0}:u);if(T)throw T;n={exitCode:u.exitCode,stderr:u.stderr,stdout:u.stdout}}else{const a={...process.env,PGPASSWORD:t.password,...t.sslMode?{PGSSLMODE:t.sslMode}:{}};n=await $({args:r,env:a,timeoutMs:ADMIN_QUERY_COMMAND_TIMEOUT_MS,connection:{host:t.host,port:t.port,user:t.user,password:t.password,database:t.adminDatabase||p,sslMode:t.sslMode},signal:o.signal})}if(n.exitCode!=null&&n.exitCode!==0){const a=new Error(n.shortMessage||n.stderr||n.stdout||`psql failed with exit code ${String(n.exitCode)}`);throw Reflect.set(a,"stdout",n.stdout||""),Reflect.set(a,"stderr",n.stderr||""),a}const{stdout:i}=n;return i}catch(n){if(Date.now()-s>=x||!isTransientAdminQueryConnectionError(n))throw n;await A(L,o.signal)}}}export function buildAdminQueryCommandArgs(t,e){return b(t)?["exec","-e",`PGPASSWORD=${t.password}`,t.containerId,"psql","-v","ON_ERROR_STOP=1","-U",t.user,"-d",t.adminDatabase||p,"-p",String(t.containerPort||5432),...e]:["-v","ON_ERROR_STOP=1","-h",t.host,"-p",String(t.port),"-U",t.user,"-d",t.adminDatabase||p,...e]}export function isTransientAdminQueryConnectionError(t){const e=S(t);return e.includes('connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed')||e.includes("No such file or directory")||e.includes("the database system is starting up")||e.includes("could not connect to server")||e.includes("connection refused")||e.includes("Connection timed out")||e.includes("connection timed out")||e.includes("Operation timed out")||e.includes("i/o timeout")||e.includes("server closed the connection unexpectedly")||e.includes("terminating connection due to administrator command")}async function N(t,e,o){await runAdminQuery(t,["-c",["SELECT pg_terminate_backend(pid)","FROM pg_stat_activity",`WHERE datname = '${E(e)}' AND pid <> pg_backend_pid();`].join(" ")],o)}async function k(t,e,o){const r=await runAdminQuery(t,["-tAc",["SELECT COUNT(*)","FROM pg_stat_activity",`WHERE datname = '${E(e)}' AND pid <> pg_backend_pid();`].join(" ")],o);return Number.parseInt(r.trim(),10)||0}function W(t){const e=S(t);return e.includes('syntax error at or near "WITH"')||e.includes('option "force"')}function A(t,e){return new Promise((o,r)=>{if(e?.aborted){r(w(e));return}const s=setTimeout(n,t);e?.addEventListener("abort",i,{once:!0});function n(){e?.removeEventListener("abort",i),o()}function i(){clearTimeout(s),r(e?w(e):new Error("Database administration aborted"))}})}function O(t){if(t?.aborted)throw w(t)}function w(t){return t.reason instanceof Error?t.reason:new Error("Database administration aborted",{cause:t.reason})}function S(t){return["shortMessage","stderr","stdout","message"].map(e=>U(v(t,e)||"")).join(`
2
+ `)}function U(t){if(typeof t=="symbol")throw new TypeError("Cannot convert a Symbol value to a string");return String(t)}function b(t){return!!t.containerName}
@@ -0,0 +1 @@
1
+ export function bindDatabaseUrl(n){const e=new URL(n),s=e.searchParams.get("sslmode")||"disable";return{url:n,host:e.hostname,port:Number(e.port||"5432"),database:e.pathname.replace(/^\//,""),user:decodeURIComponent(e.username),password:decodeURIComponent(e.password),sslMode:s,ssl:s!=="disable"}}export function lendDatabases(n,e){const s=new Map(e);for(const t of n){const a=t.testkit.databaseFrom,o=a?e.get(a):void 0;o&&s.set(t.name,o)}return s}
@@ -1 +1 @@
1
- import{hasActiveRunManifest as A,hasActiveRunManifestWithTerminalAuthority as v}from"../process/runs/ownership.js";import{observeProcessCreationIdentity as l}from"../process/index.js";import{TESTKIT_PRODUCT_ID_LABEL as y,TESTKIT_RESOURCE_KIND_LABEL as g,TESTKIT_SCOPE_LABEL as k,buildProductIdentity as T,listManagedDockerContainers as L,listManagedDockerVolumes as P,removeDockerContainer as C,removeDockerVolume as w,stopDockerContainer as E}from"./docker.js";import{requireProductLifecycleFenceProductDir as i}from"../process/lifecycle-fence.js";import{hasRemainingLocalArtifacts as D,readOwnedStateValues as R}from"./state.js";export async function cleanupLocalPostgresDockerResources(e={}){return f({...e,force:!1})}export async function destroyLocalPostgresDockerResources(e,r={}){const t=i(e);return f({...r,assertMutationAuthority:()=>{if(i(e)!==t)throw new Error("Database destroy lifecycle authority changed products")},force:!0,productDir:t})}export async function cleanupTerminalRunLocalPostgresDockerResources(e,r,t={}){const s=i(e),a=()=>{assertTerminalRunDatabaseCleanupAuthority(e,r)};return a(),f({...t,assertMutationAuthority:a,force:!1,productDir:s,terminalRunAuthority:r})}export function assertTerminalRunDatabaseCleanupAuthority(e,r){const t=i(e);if(v(t,l,r))throw new Error(`Cannot clean terminal Testkit run ${r.runId} database resources while another product run is active or its terminal ownership is invalid`)}async function f(e){e.assertMutationAuthority?.();const r=T(e.productDir||process.cwd()),t=await L(r),s=await P(r),a=[],u=[],d=[],c=[],h=[];for(const o of t){if(!I(o))continue;const n=M(o,r,e);n.action==="remove"?a.push({...o,action:"remove",reason:n.reason}):n.action==="stop"?a.push({...o,action:"stop",reason:n.reason}):n.reason&&u.push({...o,reason:n.reason})}for(const o of s){if(!S(o))continue;const n=_(o,r,e);n.action==="remove"?a.push({...o,action:"remove",reason:n.reason,resourceType:"volume"}):n.reason&&u.push({...o,reason:n.reason,resourceType:"volume"})}if(!e.dryRun)for(const o of a)e.assertMutationAuthority?.(),o.action==="stop"?await E(o.id,o.name)?h.push(o):c.push(p(o)):o.resourceType==="volume"?await w(o.name,o)?d.push(o):c.push(p(o)):await C(o.id,o.name)?d.push(o):c.push(p(o));return{removed:e.dryRun?[]:d,stopped:e.dryRun?[]:h,skipped:e.dryRun?[]:c,targets:a,kept:u}}function p(e){return e.resourceType==="volume"?{...e,action:"skip",intendedAction:"remove",reason:"resource-changed-or-disappeared-before-mutation",selectionReason:e.reason}:{...e,action:"skip",intendedAction:e.action==="stop"?"stop":"remove",reason:"resource-changed-or-disappeared-before-mutation",selectionReason:e.reason}}function M(e,r,t){return e.labels[y]!==r.id?{action:"keep",reason:"different-product"}:t.force?{action:"remove",reason:"destroy-current-product"}:m(r.dir,t)?{action:"keep",reason:"current-product-active"}:D(r.dir)?R(r.dir,["container_name","local_container_name"]).has(e.name)?b(e,r.dir,t)?{action:"stop",reason:"current-product-idle"}:{action:"keep",reason:"current-product-referenced"}:{action:"remove",reason:"current-product-unreferenced"}:{action:"remove",reason:"current-product-no-local-artifacts"}}function _(e,r,t){return e.labels[y]!==r.id?{action:"keep",reason:"different-product"}:t.force?{action:"remove",reason:"destroy-current-product"}:m(r.dir,t)?{action:"keep",reason:"current-product-active"}:D(r.dir)?R(r.dir,["volume_name"]).has(e.name)?{action:"keep",reason:"current-product-referenced"}:{action:"remove",reason:"current-product-unreferenced"}:{action:"remove",reason:"current-product-no-local-artifacts"}}function b(e,r,t){return!!(t.stopIdle&&e.running&&!m(r,t))}function I(e){const{labels:r}=e;return r[g]==="postgres-container"&&r[k]==="local-postgres"}function S(e){const{labels:r}=e;return r[g]==="postgres-volume"&&r[k]==="local-postgres"}export function hasActiveProductRuntime(e){return A(e,l)}function m(e,r){return r.terminalRunAuthority===void 0?hasActiveProductRuntime(e):v(e,l,r.terminalRunAuthority)}
1
+ import{hasActiveRunManifest as A,hasActiveRunManifestWithTerminalAuthority as v}from"../process/runs/ownership.js";import{observeProcessCreationIdentity as l}from"../process/index.js";import{TESTKIT_PRODUCT_ID_LABEL as y,TESTKIT_RESOURCE_KIND_LABEL as g,TESTKIT_SCOPE_LABEL as k,buildProductIdentity as T,listManagedDockerContainers as L,listManagedDockerVolumes as P,removeDockerContainer as C,removeDockerVolume as w,stopDockerContainer as E}from"./docker.js";import{requireProductLifecycleFenceProductDir as i}from"../process/lifecycle-fence.js";import{hasRemainingLocalArtifacts as D,readOwnedStateValues as R}from"./state.js";export async function cleanupLocalPostgresDockerResources(e={}){return f({...e,force:!1})}export async function destroyLocalPostgresDockerResources(e,r={}){const t=i(e);return f({...r,assertMutationAuthority:()=>{if(i(e)!==t)throw new Error("Database destroy lifecycle authority changed products")},force:!0,productDir:t})}export async function cleanupTerminalRunLocalPostgresDockerResources(e,r,t={}){const s=i(e),a=()=>{assertTerminalRunDatabaseCleanupAuthority(e,r)};return a(),f({...t,assertMutationAuthority:a,force:!1,productDir:s,terminalRunAuthority:r})}export function assertTerminalRunDatabaseCleanupAuthority(e,r){const t=i(e);if(v(t,l,r))throw new Error(`Cannot clean terminal Testkit run ${r.runId} database resources while another product run is active or its terminal ownership is invalid`)}async function f(e){e.assertMutationAuthority?.();const r=T(e.productDir||process.cwd()),t=await L(r),s=await P(r),a=[],u=[],d=[],c=[],h=[];for(const o of t){if(!b(o))continue;const n=M(o,r,e);n.action==="remove"?a.push({...o,action:"remove",reason:n.reason}):n.action==="stop"?a.push({...o,action:"stop",reason:n.reason}):n.reason&&u.push({...o,reason:n.reason})}for(const o of s){if(!I(o))continue;const n=_(o,r,e);n.action==="remove"?a.push({...o,action:"remove",reason:n.reason,resourceType:"volume"}):n.reason&&u.push({...o,reason:n.reason,resourceType:"volume"})}if(!e.dryRun)for(const o of a)e.assertMutationAuthority?.(),o.action==="stop"?await E(o.id,o.name)?h.push(o):c.push(p(o)):o.resourceType==="volume"?await w(o.name,o)?d.push(o):c.push(p(o)):await C(o.id,o.name)?d.push(o):c.push(p(o));return{removed:e.dryRun?[]:d,stopped:e.dryRun?[]:h,skipped:e.dryRun?[]:c,targets:a,kept:u}}function p(e){return e.resourceType==="volume"?{...e,action:"skip",intendedAction:"remove",reason:"resource-changed-or-disappeared-before-mutation",selectionReason:e.reason}:{...e,action:"skip",intendedAction:e.action==="stop"?"stop":"remove",reason:"resource-changed-or-disappeared-before-mutation",selectionReason:e.reason}}function M(e,r,t){return e.labels[y]!==r.id?{action:"keep",reason:"different-product"}:t.force?{action:"remove",reason:"destroy-current-product"}:m(r.dir,t)?{action:"keep",reason:"current-product-active"}:D(r.dir)?R(r.dir,["container_name","local_container_name"]).has(e.name)?t.stopIdle&&e.running&&!m(r.dir,t)?{action:"stop",reason:"current-product-idle"}:{action:"keep",reason:"current-product-referenced"}:{action:"remove",reason:"current-product-unreferenced"}:{action:"remove",reason:"current-product-no-local-artifacts"}}function _(e,r,t){return e.labels[y]!==r.id?{action:"keep",reason:"different-product"}:t.force?{action:"remove",reason:"destroy-current-product"}:m(r.dir,t)?{action:"keep",reason:"current-product-active"}:D(r.dir)?R(r.dir,["volume_name"]).has(e.name)?{action:"keep",reason:"current-product-referenced"}:{action:"remove",reason:"current-product-unreferenced"}:{action:"remove",reason:"current-product-no-local-artifacts"}}function b(e){const{labels:r}=e;return r[g]==="postgres-container"&&r[k]==="local-postgres"}function I(e){const{labels:r}=e;return r[g]==="postgres-volume"&&r[k]==="local-postgres"}export function hasActiveProductRuntime(e){return A(e,l)}function m(e,r){return r.terminalRunAuthority===void 0?hasActiveProductRuntime(e):v(e,l,r.terminalRunAuthority)}
@@ -1,3 +1,3 @@
1
- import V from"node:crypto";import O from"node:fs";import A from"node:http";import k from"node:path";import{MAX_SUPERVISED_PROCESS_CAPTURE_BYTES as H}from"../process/process-limits.js";import{managedHostProcessInfrastructureError as I,normalizeManagedHostEnvironment as $,resolveManagedHostExecutable as j,runManagedHostProcess as L}from"../process/index.js";const N=5e3,B=256*1024,U=8*1024*1024,_=H/2,K=["DOCKER_HOST","DOCKER_TLS","DOCKER_TLS_VERIFY","DOCKER_CERT_PATH","DOCKER_API_VERSION","DOCKER_CUSTOM_HEADERS"];let b;export async function runDockerMetadataCommand(e,t,n,r,u){const o=performance.now()+n,h=()=>Math.floor(o-performance.now()),S=()=>{const s=R("");throw I(t,{...s,exitCode:null,cancelled:r?.aborted===!0,timedOut:r?.aborted!==!0})??new Error(`${t} exceeded its managed deadline`)};if(r?.aborted)return u(Math.max(1,h()));const m=new AbortController,y=()=>{m.abort(r?.reason)};r?.addEventListener("abort",y,{once:!0});const i=setTimeout(()=>{m.abort(new Error("Docker metadata probe timed out"))},Math.min(N,n));let l;try{const s=await v(m.signal);if(s!==null){let c=b?.key===s.key?b.value:void 0;c===void 0&&(c=await J(s,h,m.signal),m.signal.aborted||(b={key:s.key,value:c})),c!==null&&(l=await Y(c,e,m.signal),l!==void 0&&(await v(m.signal))?.key!==s.key&&(l=void 0,b=void 0))}}catch(s){if(d(d(s)?.result)?.terminationError)throw s;l=void 0}finally{clearTimeout(i),r?.removeEventListener("abort",y)}const a=h();return(r?.aborted||a<=0)&&S(),l!==void 0&&!m.signal.aborted?R(l):u(a)}async function v(e){e.throwIfAborted();const t=process.cwd(),n=$(process.env),r=j("docker",t,n),u=f=>q(n,f);if(K.some(f=>u(f)!==""))return null;const o=u(process.platform==="win32"?"USERPROFILE":"HOME"),h=u("DOCKER_CONFIG");if(!h&&(!o||!k.isAbsolute(o)))return null;const S=k.resolve(t,h||k.join(o,".docker")),m=await D(k.join(S,"config.json"),e),y=m?.toString("utf8"),i=y===void 0?{}:d(JSON.parse(y));if(i===null||y!==void 0&&W(y))return null;for(const f of Object.keys(i))if(f.toLowerCase()==="httpheaders"&&(d(i[f])===null||Object.keys(i[f]).length>0)||f.toLowerCase()==="currentcontext"&&f!=="currentContext")return null;if(i.currentContext!==void 0&&typeof i.currentContext!="string")return null;const l=u("DOCKER_CONTEXT")||i.currentContext||"default";let a=null,s=null,c=null,g=null;if(l!=="default"){const f=V.createHash("sha256").update(l).digest("hex");if(a=k.join(S,"contexts","meta",f),s=await D(k.join(a,"meta.json"),e),s===null)return null;const E=d(JSON.parse(s.toString("utf8"))),C=d(d(E?.Endpoints)?.docker);if(E?.Name!==l||typeof C?.Host!="string"||C.SkipTLSVerify!==!1)return null;c=C.Host;try{if(g=await O.promises.readdir(k.join(S,"contexts","tls",f)),g.length!==0)return null}catch(M){if(!P(M,"ENOENT"))return null}}const w=await O.promises.realpath(r),p=await O.promises.stat(w,{bigint:!0});return e.throwIfAborted(),{executable:r,cwd:t,env:n,context:l,metadataPath:a,endpoint:c,key:JSON.stringify([t,Object.entries(n).sort(([f],[E])=>f<E?-1:f>E?1:0),r,w,p.dev.toString(),p.ino.toString(),p.size.toString(),p.mtimeNs.toString(),p.ctimeNs.toString(),S,m?.toString("base64")??null,s?.toString("base64")??null,g])}}async function J(e,t,n){const r=async l=>{n.throwIfAborted();const a=Math.min(N,t());if(a<=0)return null;const s=await L({executable:e.executable,args:l,cwd:e.cwd,env:e.env,displayLabel:"Docker metadata transport resolution",timeoutMs:a,signal:n}),c=I("Docker metadata transport resolution",s);if(s.terminationError&&c!==null)throw c;return s.exitCode!==0||c!==null?null:JSON.parse(s.stdout)},u=await r(["context","inspect"]),o=Array.isArray(u)&&u.length===1?d(u[0]):null,h=d(d(o?.Endpoints)?.docker),S=d(o?.TLSMaterial),m=d(o?.Storage);if(o?.Name!==e.context||typeof h?.Host!="string"||h.SkipTLSVerify!==!1||S===null||Object.keys(S).length!==0||e.metadataPath!==null&&(m?.MetadataPath!==e.metadataPath||h.Host!==e.endpoint))return null;const y=F(h.Host);if(y===null)return null;const i=d(await r(["version","--format","{{json .Client}}"]));return typeof i?.Version!="string"||!/^29\.\d+\.\d+$/u.test(i.Version)||i.Context!==e.context||typeof i.Os!="string"||!x(i.DefaultAPIVersion)||!x(i.ApiVersion)?null:{key:e.key,socketPath:y,userAgent:`Docker-Client/${i.Version} (${i.Os})`,maximum:i.DefaultAPIVersion,negotiated:i.ApiVersion,server:null}}async function Y(e,t,n){const r=z(t);if(r===null)return;const u=new A.Agent({keepAlive:!0,maxSockets:1}),o=new Map;let h;const S=m=>new Promise((y,i)=>{const l=A.get({socketPath:e.socketPath,path:m,agent:u,signal:n,headers:{Host:"api.moby.localhost","User-Agent":e.userAgent}},a=>{const s=[];let c=0;a.on("data",g=>{c+=g.length,c>U?l.destroy(new Error("Docker metadata response exceeded its byte limit")):s.push(g)}),a.once("error",i),a.once("end",()=>{a.statusCode!==200||!a.complete?i(new Error("Docker metadata response was not a complete success")):y({headers:a.headers,body:Buffer.concat(s,c)})})});l.once("error",i),l.once("socket",a=>{o.has(a)||o.set(a,new Promise(s=>a.once("close",()=>{s()}))),h!==void 0&&a!==h&&l.destroy(new Error("Docker metadata connection changed during negotiation")),h=a})});try{const m=await S("/_ping"),y=d(JSON.parse((await S("/version")).body.toString("utf8"))),i=y?.ApiVersion,l=y?.MinAPIVersion;if(!x(i)||!x(l)||m.headers["api-version"]!==i)return;const a=T(e.maximum,i)<=0?e.maximum:i;if(a!==e.negotiated||T(a,l)<0){b=void 0;return}const s=JSON.stringify(y);if(e.server!==null&&e.server!==s){b=void 0;return}e.server=s;const c=await S(`/v${a}${r.path}`),g=JSON.parse(c.body.toString("utf8"));let w;if(r.kind==="container"||r.kind==="volume"){const p=d(g)?.[r.kind==="container"?"Id":"Name"];if(typeof p!="string"||p.length===0)return;const f=JSON.stringify([g],null,4).replace(/[<>&\u2028\u2029]/gu,E=>`\\u${E.charCodeAt(0).toString(16).padStart(4,"0")}`);if(c.body.length+Buffer.byteLength(f)+16>_)return;w=`[${c.body.toString("utf8")}]`}else if(r.kind==="containers"){if(!Array.isArray(g)||g.some(p=>typeof d(p)?.Id!="string"||!/^[a-f0-9]{64}$/u.test(d(p)?.Id)))return;w=g.map(p=>(d(p)?.Id).slice(0,12)).join(`
2
- `)}else{const p=d(g)?.Volumes;if(p===null)w="";else{if(!Array.isArray(p)||p.length>1)return;const f=p.map(E=>d(E)?.Name);if(f.some(E=>typeof E!="string"||E.length===0))return;w=f.join(`
3
- `)}}return Buffer.byteLength(w)+1<=_?w:void 0}finally{u.destroy();for(const m of o.keys())m.destroy();await Promise.all(o.values())}}function z(e){if(e.length===2&&e[0]==="inspect"&&e[1]&&!e[1].startsWith("-"))return{kind:"container",path:`/containers/${encodeURIComponent(e[1])}/json`};if(e.length===3&&e[0]==="volume"&&e[1]==="inspect"&&e[2]&&!e[2].startsWith("-"))return{kind:"volume",path:`/volumes/${encodeURIComponent(e[2])}`};let t,n;if(e[0]==="ps"&&e[1]==="-a"&&e[2]==="--format"&&e[3]==="{{.ID}}")t="containers",n=e.slice(4);else if(e[0]==="volume"&&e[1]==="ls"&&e[2]==="-q")t="volumes",n=e.slice(3);else return null;const r=[];for(let o=0;o<n.length;o+=2){if(n[o]!=="--filter"||!n[o+1]?.startsWith("label="))return null;r.push(n[o+1].slice(6))}const u=encodeURIComponent(JSON.stringify({label:r}));return{kind:t,path:t==="containers"?`/containers/json?all=true&filters=${u}`:`/volumes?filters=${u}`}}async function D(e,t){const n=O.createReadStream(e,{signal:t,highWaterMark:65536}),r=[];let u=0;try{for await(const o of n){if(u+=o.length,u>B)throw new Error("Docker metadata configuration exceeded its byte limit");r.push(o)}return Buffer.concat(r,u)}catch(o){if(P(o,"ENOENT"))return null;throw o}finally{n.destroy(),n.closed||await new Promise(o=>n.once("close",o))}}function F(e){if(process.platform==="win32"){const n=/^npipe:\/\/\/\/\.\/pipe\/([a-z0-9_.-]+)$/iu.exec(e);return n===null?null:`\\\\.\\pipe\\${n[1]}`}if(!e.startsWith("unix:///"))return null;const t=e.slice(7);return t.includes("\0")||t.includes("?")||t.includes("#")?null:t}function W(e){for(const t of e.matchAll(/"(?:\\.|[^"\\])*"/gu)){let n=t.index+t[0].length;for(;n<e.length&&/\s/u.test(e[n]);)n+=1;if(e[n]!==":")continue;const r=JSON.parse(t[0]);if(typeof r=="string"&&/^httpheaders$/iu.test(r))return!0}return!1}function q(e,t){return process.platform!=="win32"?e[t]||"":Object.entries(e).find(([n])=>n.toUpperCase()===t)?.[1]||""}function d(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)?e:null}function P(e,t){return d(e)?.code===t}function x(e){return typeof e=="string"&&/^1\.[1-9]\d*$/u.test(e)&&Number.isSafeInteger(Number(e.slice(2)))}function T(e,t){return Number(e.slice(2))-Number(t.slice(2))}function R(e){return{cancelled:!1,error:null,exitCode:0,exitSignal:null,outputLimitExceeded:!1,stderr:"",stdout:e,terminationError:null,timedOut:!1}}
1
+ import H from"node:crypto";import O from"node:fs";import I from"node:http";import E from"node:path";import{MAX_SUPERVISED_PROCESS_CAPTURE_BYTES as L}from"../process/process-limits.js";import{managedHostProcessInfrastructureError as _,normalizeManagedHostEnvironment as B,resolveManagedHostExecutable as U,runManagedHostProcess as K}from"../process/index.js";const v=5e3,F=256*1024,J=8*1024*1024,N=L/2,Y=["DOCKER_HOST","DOCKER_TLS","DOCKER_TLS_VERIFY","DOCKER_CERT_PATH","DOCKER_API_VERSION","DOCKER_CUSTOM_HEADERS"];let b,D=!1;export async function runDockerMetadataCommand(e,r,t,o,f){const i=performance.now(),S=i+t,y=()=>Math.floor(S-performance.now()),k=async(d,s)=>{const u=performance.now();try{return await f(d)}catch(w){throw P(w,`the direct read ${s}, then the docker CLI ran ${A(u)}`)}},g=()=>{const d=V(""),s=_(r,{...d,exitCode:null,cancelled:o?.aborted===!0,timedOut:o?.aborted!==!0});throw P(s??new Error(`${r} exceeded its managed deadline`),`the direct read took ${A(i)}, and the docker CLI did not run`)};if(o?.aborted||D)return k(Math.max(1,y()),"was skipped after an earlier one timed out");const n=new AbortController,m=()=>{n.abort(o?.reason)};o?.addEventListener("abort",m,{once:!0});const a=setTimeout(()=>{n.signal.aborted||(D=!0,n.abort(new Error("Docker metadata probe timed out")))},Math.min(v,t));let c;try{const d=await R(n.signal);if(d!==null){let s=b?.key===d.key?b.value:void 0;s===void 0&&(s=await z(d,y,n.signal),n.signal.aborted||(b={key:d.key,value:s})),s!==null&&(c=await W(s,e,n.signal),c!==void 0&&(await R(n.signal))?.key!==d.key&&(c=void 0,b=void 0))}}catch(d){if(l(l(d)?.result)?.terminationError)throw d;c=void 0}finally{clearTimeout(a),o?.removeEventListener("abort",m)}const p=`took ${A(i)}`,h=y();return(o?.aborted||h<=0)&&g(),c!==void 0&&!n.signal.aborted?V(c):k(h,p)}function A(e){return`${((performance.now()-e)/1e3).toFixed(1)} s`}function P(e,r){const t=l(l(e)?.result);if(t?.timedOut!==!0||!(e instanceof Error))return e;const o=new Error(`${e.message}: ${r}`,{cause:e});return Object.defineProperty(o,"result",{enumerable:!1,value:t}),o}async function R(e){e.throwIfAborted();const r=process.cwd(),t=B(process.env),o=U("docker",r,t),f=u=>Q(t,u);if(Y.some(u=>f(u)!==""))return null;const i=f(process.platform==="win32"?"USERPROFILE":"HOME"),S=f("DOCKER_CONFIG");if(!S&&(!i||!E.isAbsolute(i)))return null;const y=E.resolve(r,S||E.join(i,".docker")),k=await T(E.join(y,"config.json"),e),g=k?.toString("utf8"),n=g===void 0?{}:l(JSON.parse(g));if(n===null||g!==void 0&&G(g))return null;for(const u of Object.keys(n))if(u.toLowerCase()==="httpheaders"&&(l(n[u])===null||Object.keys(n[u]).length>0)||u.toLowerCase()==="currentcontext"&&u!=="currentContext")return null;if(n.currentContext!==void 0&&typeof n.currentContext!="string")return null;const m=f("DOCKER_CONTEXT")||n.currentContext||"default";let a=null,c=null,p=null,h=null;if(m!=="default"){const u=H.createHash("sha256").update(m).digest("hex");if(a=E.join(y,"contexts","meta",u),c=await T(E.join(a,"meta.json"),e),c===null)return null;const w=l(JSON.parse(c.toString("utf8"))),C=l(l(w?.Endpoints)?.docker);if(w?.Name!==m||typeof C?.Host!="string"||C.SkipTLSVerify!==!1)return null;p=C.Host;try{if(h=await O.promises.readdir(E.join(y,"contexts","tls",u)),h.length!==0)return null}catch(j){if(!$(j,"ENOENT"))return null}}const d=await O.promises.realpath(o),s=await O.promises.stat(d,{bigint:!0});return e.throwIfAborted(),{executable:o,cwd:r,env:t,context:m,metadataPath:a,endpoint:p,key:JSON.stringify([r,Object.entries(t).sort(([u],[w])=>u<w?-1:u>w?1:0),o,d,s.dev.toString(),s.ino.toString(),s.size.toString(),s.mtimeNs.toString(),s.ctimeNs.toString(),y,k?.toString("base64")??null,c?.toString("base64")??null,h])}}async function z(e,r,t){const o=async m=>{t.throwIfAborted();const a=Math.min(v,r());if(a<=0)return null;const c=await K({executable:e.executable,args:m,cwd:e.cwd,env:e.env,displayLabel:"Docker metadata transport resolution",timeoutMs:a,signal:t}),p=_("Docker metadata transport resolution",c);if(c.terminationError&&p!==null)throw p;return c.exitCode!==0||p!==null?null:JSON.parse(c.stdout)},f=await o(["context","inspect"]),i=Array.isArray(f)&&f.length===1?l(f[0]):null,S=l(l(i?.Endpoints)?.docker),y=l(i?.TLSMaterial),k=l(i?.Storage);if(i?.Name!==e.context||typeof S?.Host!="string"||S.SkipTLSVerify!==!1||y===null||Object.keys(y).length!==0||e.metadataPath!==null&&(k?.MetadataPath!==e.metadataPath||S.Host!==e.endpoint))return null;const g=X(S.Host);if(g===null)return null;const n=l(await o(["version","--format","{{json .Client}}"]));return typeof n?.Version!="string"||!/^29\.\d+\.\d+$/u.test(n.Version)||n.Context!==e.context||typeof n.Os!="string"||!x(n.DefaultAPIVersion)||!x(n.ApiVersion)?null:{key:e.key,socketPath:g,userAgent:`Docker-Client/${n.Version} (${n.Os})`,maximum:n.DefaultAPIVersion,negotiated:n.ApiVersion,server:null}}async function W(e,r,t){const o=q(r);if(o===null)return;const f=new I.Agent({keepAlive:!0,maxSockets:1}),i=new Map;let S;const y=k=>new Promise((g,n)=>{const m=I.get({socketPath:e.socketPath,path:k,agent:f,signal:t,headers:{Host:"api.moby.localhost","User-Agent":e.userAgent}},a=>{const c=[];let p=0;a.on("data",h=>{p+=h.length,p>J?m.destroy(new Error("Docker metadata response exceeded its byte limit")):c.push(h)}),a.once("error",n),a.once("end",()=>{a.statusCode!==200||!a.complete?n(new Error("Docker metadata response was not a complete success")):g({headers:a.headers,body:Buffer.concat(c,p)})})});m.once("error",n),m.once("socket",a=>{i.has(a)||i.set(a,new Promise(c=>a.once("close",()=>{c()}))),S!==void 0&&a!==S&&m.destroy(new Error("Docker metadata connection changed during negotiation")),S=a})});try{const k=await y("/_ping"),g=l(JSON.parse((await y("/version")).body.toString("utf8"))),n=g?.ApiVersion,m=g?.MinAPIVersion;if(!x(n)||!x(m)||k.headers["api-version"]!==n)return;const a=M(e.maximum,n)<=0?e.maximum:n;if(a!==e.negotiated||M(a,m)<0){b=void 0;return}const c=JSON.stringify(g);if(e.server!==null&&e.server!==c){b=void 0;return}e.server=c;const p=await y(`/v${a}${o.path}`),h=JSON.parse(p.body.toString("utf8"));let d;if(o.kind==="container"||o.kind==="volume"){const s=l(h)?.[o.kind==="container"?"Id":"Name"];if(typeof s!="string"||s.length===0)return;const u=JSON.stringify([h],null,4).replace(/[<>&\u2028\u2029]/gu,w=>`\\u${w.charCodeAt(0).toString(16).padStart(4,"0")}`);if(p.body.length+Buffer.byteLength(u)+16>N)return;d=`[${p.body.toString("utf8")}]`}else if(o.kind==="containers"){if(!Array.isArray(h)||h.some(s=>typeof l(s)?.Id!="string"||!/^[a-f0-9]{64}$/u.test(l(s)?.Id)))return;d=h.map(s=>(l(s)?.Id).slice(0,12)).join(`
2
+ `)}else{const s=l(h)?.Volumes;if(s===null)d="";else{if(!Array.isArray(s)||s.length>1)return;const u=s.map(w=>l(w)?.Name);if(u.some(w=>typeof w!="string"||w.length===0))return;d=u.join(`
3
+ `)}}return Buffer.byteLength(d)+1<=N?d:void 0}finally{f.destroy();for(const k of i.keys())k.destroy();await Promise.all(i.values())}}function q(e){if(e.length===2&&e[0]==="inspect"&&e[1]&&!e[1].startsWith("-"))return{kind:"container",path:`/containers/${encodeURIComponent(e[1])}/json`};if(e.length===3&&e[0]==="volume"&&e[1]==="inspect"&&e[2]&&!e[2].startsWith("-"))return{kind:"volume",path:`/volumes/${encodeURIComponent(e[2])}`};let r,t;if(e[0]==="ps"&&e[1]==="-a"&&e[2]==="--format"&&e[3]==="{{.ID}}")r="containers",t=e.slice(4);else if(e[0]==="volume"&&e[1]==="ls"&&e[2]==="-q")r="volumes",t=e.slice(3);else return null;const o=[];for(let i=0;i<t.length;i+=2){if(t[i]!=="--filter"||!t[i+1]?.startsWith("label="))return null;o.push(t[i+1].slice(6))}const f=encodeURIComponent(JSON.stringify({label:o}));return{kind:r,path:r==="containers"?`/containers/json?all=true&filters=${f}`:`/volumes?filters=${f}`}}async function T(e,r){const t=O.createReadStream(e,{signal:r,highWaterMark:65536}),o=[];let f=0;try{for await(const i of t){if(f+=i.length,f>F)throw new Error("Docker metadata configuration exceeded its byte limit");o.push(i)}return Buffer.concat(o,f)}catch(i){if($(i,"ENOENT"))return null;throw i}finally{t.destroy(),t.closed||await new Promise(i=>t.once("close",i))}}function X(e){if(process.platform==="win32"){const t=/^npipe:\/\/\/\/\.\/pipe\/([a-z0-9_.-]+)$/iu.exec(e);return t===null?null:`\\\\.\\pipe\\${t[1]}`}if(!e.startsWith("unix:///"))return null;const r=e.slice(7);return r.includes("\0")||r.includes("?")||r.includes("#")?null:r}function G(e){for(const r of e.matchAll(/"(?:\\.|[^"\\])*"/gu)){let t=r.index+r[0].length;for(;t<e.length&&/\s/u.test(e[t]);)t+=1;if(e[t]!==":")continue;const o=JSON.parse(r[0]);if(typeof o=="string"&&/^httpheaders$/iu.test(o))return!0}return!1}function Q(e,r){return process.platform!=="win32"?e[r]||"":Object.entries(e).find(([t])=>t.toUpperCase()===r)?.[1]||""}function l(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)?e:null}function $(e,r){return l(e)?.code===r}function x(e){return typeof e=="string"&&/^1\.[1-9]\d*$/u.test(e)&&Number.isSafeInteger(Number(e.slice(2)))}function M(e,r){return Number(e.slice(2))-Number(r.slice(2))}function V(e){return{cancelled:!1,error:null,exitCode:0,exitSignal:null,outputLimitExceeded:!1,stderr:"",stdout:e,terminationError:null,timedOut:!1}}