@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 +1 @@
1
- import{makeTempDirAsync as D}from"../../../process/files/temp-dir.js";import{classifyManagedProcessResult as F,terminalOutcome as T,processOutputEvidence as N,failureFromError as P,firstOutputLine as R,processExitDetails as C,processExitFailure as x,toError as h,executeEngineTasks as M,managedProcessFailure as b,emptyEvidence as W,taskTimeoutFailure as B}from"../../adapters/execution.js";import{requireRootDirectory as Y,requireAbsoluteWorkspacePath as O,requireConsumerFile as H,safeSegment as S}from"../../adapters/workspace.js";import u from"node:fs/promises";import U from"node:path";import{setTimeout as $}from"node:timers/promises";import{pathToFileURL as K}from"node:url";import{isEngineTaskDeadlineExceededReason as G,resolveEngineTaskInputs as V}from"../../api/index.js";import{createNativeInvocationProcessEnvironment as j,runManagedProcess as J}from"../../../process/index.js";import{PlaywrightConsumerConfigurationError as z,playwrightExactFileFilter as X,writePlaywrightTaskWorkspace as Q}from"./config.js";import{collectPlaywrightEvidence as Z}from"./evidence.js";import{engineEvidenceIdentity as q}from"../../adapters/evidence-identity.js";import{getNodeStartupCacheEnvironment as rr}from"../../adapters/node-startup-cache.js";const y={codePrefix:"PLAYWRIGHT",label:"Playwright"};export const PLAYWRIGHT_SPAWN_ENVIRONMENT_MAX_BYTES=24*1024;const k=64;class L extends Error{constructor(r){const e=h(r);super(e.message,{cause:e}),this.name="PlaywrightConsumerPreparationError"}}export const playwrightAdapterDependencies={createInvocationEnvironment:j,removeOwnedDirectory:ir,writeTaskWorkspace:Q};const tr=new Set(["EBUSY","ENOTEMPTY","EPERM"]),er=5;async function ir(t){for(let r=0;;r+=1)try{await u.rm(t,{force:!0,recursive:!0});return}catch(e){const i=e instanceof Error&&"code"in e?e.code:void 0;if(r===er||typeof i!="string"||!tr.has(i))throw e;await $((r+1)*100)}}export async function executePlaywrightEngine(t,r,e,i=playwrightAdapterDependencies){const o=await or(t,r,i,e);return M(t,o.tasks,y,(a,s)=>nr(t,o,a,s),lr(t,o.installation))}async function or(t,r,e,i){const o=await Y(t.workspace.rootDirectory);O(t.workspace.temporaryDirectory,"temporary directory"),O(t.workspace.artifactDirectory,"artifact directory"),await u.mkdir(t.workspace.temporaryDirectory,{recursive:!0}),await u.mkdir(t.workspace.artifactDirectory,{recursive:!0});const a=await u.realpath(t.workspace.temporaryDirectory),s=await u.realpath(t.workspace.artifactDirectory),n=await D(`playwright-${S(t.invocationId)}-`,{parentDir:a});i.defer(()=>e.removeOwnedDirectory(n));const l=await e.createInvocationEnvironment(n);i.defer(()=>e.removeOwnedDirectory(l.temporaryDirectory));const p=[];for(const[g,c]of t.tasks.entries()){const I=V(t,c),v=`${g.toString().padStart(3,"0")}-${S(c.id)}`,_=U.join(n,v),f=await D(`${v}-`,{parentDir:s});try{const m=cr(t,c.serviceName),E=await pr(()=>H(o,c.file,"Playwright task file")),w=await e.writeTaskWorkspace({artifactDirectory:f,baseUrl:m,browserFile:r.browserExecutable,endpoints:t.target.endpoints,inputs:I,invocationId:t.invocationId,managedModuleEntrypoints:{authoring:r.authoringEntrypoints.authoring,cli:r.family.cli,playwright:r.family.playwright.entrypoint,playwrightCore:r.family.playwrightCore.entrypoint,playwrightTest:r.family.playwrightTest.entrypoint,root:r.authoringEntrypoints.root,rootPackageJson:r.authoringEntrypoints.rootPackageJson},moduleFile:r.family.playwrightTest.entrypoint,orchestration:c.orchestration,rootDirectory:o,serviceName:c.serviceName,sourceFile:E,taskDirectory:_,taskId:c.id});i.defer(async()=>{try{await e.removeOwnedDirectory(w.attachmentDirectory)}catch(d){if(!(d instanceof Error&&"code"in d&&d.code==="ENOTDIR"))throw d}}),p.push({artifactDirectory:f,inputs:I,task:c,preparationFailure:null,prepared:{baseUrl:m,sourceFile:E,workspace:w}})}catch(m){const E=(await ur([_,f],e)).map(w=>w.error);p.push({artifactDirectory:f,inputs:I,task:c,preparationFailure:playwrightPreparationFailure(m,E),prepared:null})}}return Object.freeze({installation:r,invocationEnvironment:l.environment,rootDirectory:o,tasks:Object.freeze(p)})}async function nr(t,r,e,i){const a={...await rr(t.workspace.cacheDirectory,e.inputs.environment),...ar(t,r,e)};try{A(a)}catch{delete a.NODE_COMPILE_CACHE}const s=e.task.deadlineMs-Date.now();if(s<=0)return T(e.task.id,"failed",i,W(),B(e.task.timeoutMs,y));const n=await J({args:[r.installation.family.cli,"test",X(e.prepared.sourceFile),"--config",e.prepared.workspace.configFile],cwd:r.rootDirectory,displayLabel:"Playwright",env:a,executable:process.execPath,signal:t.signal,timeoutMs:s});let l;try{l=await Z({identity:{engineId:"playwright",invocationId:t.invocationId,taskId:e.task.id,sourceFile:e.prepared.sourceFile},artifactDirectory:e.artifactDirectory,outputDirectory:e.prepared.workspace.outputDirectory,reportFile:e.prepared.workspace.reportFile,rootDirectory:r.rootDirectory,sourceFile:e.prepared.sourceFile,stderr:n.stderr,stdout:n.stdout})}catch(g){return T(e.task.id,"failed",i,N(n),playwrightEvidenceCollectionFailure(n,g))}const p=classifyPlaywrightProcessResult(n,l,e.task.timeoutMs,G(t.signal.reason));return T(e.task.id,p.status,i,l.evidence,p.failure)}export function classifyPlaywrightProcessResult(t,r,e,i){const o=F(t,e,i,y);if(o!==null)return o;if(r.outputLimit!==null){const n=r.outputLimit;return{failure:{code:"PLAYWRIGHT_OUTPUT_ARTIFACT_LIMIT",details:{...n},message:`Playwright output exceeded its ${n.limit.toString()} ${n.kind==="bytes"?"byte aggregate":"entry"} artifact limit`},status:"failed"}}const a=r.attachmentFailures.find(n=>n.code==="PLAYWRIGHT_ATTACHMENT_LIMIT");if(a!==void 0)return{failure:a,status:"failed"};if(r.report.failure!==null){const n=r.report.failure;return{...r.report,failure:{...n,details:{...n.details,evidenceErrors:r.reportError===null?0:1,...C(t)}}}}const s=r.attachmentFailures.at(0);return s!==void 0?{failure:s,status:"failed"}:t.exitCode!==0?x(t,y,R(t.stderr)??R(t.stdout)):r.reportError!==null?{failure:{...P(r.reportError,"PLAYWRIGHT_REPORT_INVALID"),classification:"infra"},status:"failed"}:r.report}export function playwrightEvidenceCollectionFailure(t,r){const e=h(r);return b(t,y,e)??{...P(e,"PLAYWRIGHT_EVIDENCE_FAILED"),classification:"infra"}}function ar(t,r,e){const i={...r.invocationEnvironment},o=e.task,a=e.prepared.workspace.inputBootstrapFile,s=e.prepared.workspace.resolutionBootstrapFile;return Object.assign(i,{BASE_URL:e.prepared.baseUrl,FORCE_COLOR:"0",NO_COLOR:"1",PLAYWRIGHT_BROWSERS_PATH:r.installation.registry.canonicalValue,PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD:"1",TESTKIT_ACTIVE:"1",TESTKIT_INTERNAL_FILE_DEADLINE_MS:String(o.deadlineMs),TESTKIT_INTERNAL_FILE_TIMEOUT_SECONDS:String(Math.max(1,Math.ceil(o.timeoutMs/1e3))),TESTKIT_INVOCATION_ID:t.invocationId,TESTKIT_LEASE_DIR:o.orchestration.lease.directory,TESTKIT_LEASE_ID:o.orchestration.lease.id,TESTKIT_MODE:o.orchestration.mode,...o.orchestration.runtimeId===void 0?{}:{TESTKIT_RUNTIME_ID:o.orchestration.runtimeId},TESTKIT_TEST_FILE:o.file,TESTKIT_TEST_ID:o.id}),i.NODE_OPTIONS=sr(s,a),A(i),i}function sr(t,r){return["--experimental-strip-types",`--require=${JSON.stringify(t)}`,`--import=${JSON.stringify(K(r).href)}`].join(" ")}export function playwrightSpawnEnvironmentBytes(t){return Object.entries(t).reduce((r,[e,i])=>r+(process.platform==="win32"?(e.length+i.length+2)*2:Buffer.byteLength(e,"utf8")+Buffer.byteLength(i,"utf8")+2),0)}function A(t){if(Object.keys(t).length>k)throw new Error(`Playwright physical spawn environment exceeds its ${k.toString()} entry limit`);if(playwrightSpawnEnvironmentBytes(t)>PLAYWRIGHT_SPAWN_ENVIRONMENT_MAX_BYTES)throw new Error(`Playwright physical spawn environment exceeds its ${PLAYWRIGHT_SPAWN_ENVIRONMENT_MAX_BYTES.toString()} byte limit`)}function cr(t,r){const e=t.target.endpoints[r];if(typeof e!="string"||e.trim().length===0)throw new Error(`Playwright task service ${r} does not have a published endpoint`);let i;try{i=new URL(e)}catch(o){throw new Error(`Playwright task service ${r} endpoint is not a valid URL`,{cause:o})}if(i.protocol!=="http:"&&i.protocol!=="https:")throw new Error(`Playwright task service ${r} endpoint must use http or https`);return i.href}function lr(t,r){return{...q({engineId:"playwright",installationKind:"root-playwright-family",profile:t.profile}),browserName:"chromium",packages:{playwright:r.family.playwright.version,playwrightCore:r.family.playwrightCore.version,playwrightTest:r.family.playwrightTest.version},registryMode:r.registry.mode}}export function playwrightPreparationFailure(t,r){if(r.length===0)return{...P(t,"PLAYWRIGHT_PREPARE_FAILED"),classification:t instanceof L||t instanceof z?"product":"infra"};const e=h(t);return{classification:"infra",code:"PLAYWRIGHT_PREPARE_CLEANUP_FAILED",details:{cleanupFailures:r.map(i=>i.message),preparationFailure:e.message},message:`Playwright task preparation failed and its partial workspace could not be removed: ${r.map(i=>i.message).join("; ")}`,...e.stack===void 0?{}:{stack:e.stack}}}async function pr(t){try{return await t()}catch(r){throw new L(r)}}async function ur(t,r){const e=[];for(const i of t)try{await r.removeOwnedDirectory(i)}catch(o){e.push({directory:i,error:h(o)})}return e}
1
+ import{makeTempDirAsync as D}from"../../../process/files/temp-dir.js";import{toError as g}from"../../../kernel/error-serialization.js";import{classifyManagedProcessResult as F,terminalOutcome as T,processOutputEvidence as N,failureFromError as P,firstOutputLine as R,processExitDetails as b,processExitFailure as C,executeEngineTasks as x,managedProcessFailure as M,emptyEvidence as W,taskTimeoutFailure as U}from"../../adapters/execution.js";import{requireRootDirectory as B,requireAbsoluteWorkspacePath as O,requireConsumerFile as Y,safeSegment as S}from"../../adapters/workspace.js";import u from"node:fs/promises";import H from"node:path";import{setTimeout as $}from"node:timers/promises";import{pathToFileURL as K}from"node:url";import{isEngineTaskDeadlineExceededReason as G,resolveEngineTaskInputs as V}from"../../api/index.js";import{createNativeInvocationProcessEnvironment as j,runManagedProcess as J}from"../../../process/index.js";import{PlaywrightConsumerConfigurationError as z,playwrightExactFileFilter as X,writePlaywrightTaskWorkspace as Q}from"./config.js";import{collectPlaywrightEvidence as Z}from"./evidence.js";import{engineEvidenceIdentity as q}from"../../adapters/evidence-identity.js";import{getNodeStartupCacheEnvironment as rr}from"../../adapters/node-startup-cache.js";const y={codePrefix:"PLAYWRIGHT",label:"Playwright"};export const PLAYWRIGHT_SPAWN_ENVIRONMENT_MAX_BYTES=24*1024;const L=64;class k extends Error{constructor(r){const e=g(r);super(e.message,{cause:e}),this.name="PlaywrightConsumerPreparationError"}}export const playwrightAdapterDependencies={createInvocationEnvironment:j,removeOwnedDirectory:ir,writeTaskWorkspace:Q};const tr=new Set(["EBUSY","ENOTEMPTY","EPERM"]),er=5;async function ir(t){for(let r=0;;r+=1)try{await u.rm(t,{force:!0,recursive:!0});return}catch(e){const i=e instanceof Error&&"code"in e?e.code:void 0;if(r===er||typeof i!="string"||!tr.has(i))throw e;await $((r+1)*100)}}export async function executePlaywrightEngine(t,r,e,i=playwrightAdapterDependencies){const o=await or(t,r,i,e);return x(t,o.tasks,y,(a,s)=>nr(t,o,a,s),lr(t,o.installation))}async function or(t,r,e,i){const o=await B(t.workspace.rootDirectory);O(t.workspace.temporaryDirectory,"temporary directory"),O(t.workspace.artifactDirectory,"artifact directory"),await u.mkdir(t.workspace.temporaryDirectory,{recursive:!0}),await u.mkdir(t.workspace.artifactDirectory,{recursive:!0});const a=await u.realpath(t.workspace.temporaryDirectory),s=await u.realpath(t.workspace.artifactDirectory),n=await D(`playwright-${S(t.invocationId)}-`,{parentDir:a});i.defer(()=>e.removeOwnedDirectory(n));const l=await e.createInvocationEnvironment(n);i.defer(()=>e.removeOwnedDirectory(l.temporaryDirectory));const p=[];for(const[h,c]of t.tasks.entries()){const I=V(t,c),v=`${h.toString().padStart(3,"0")}-${S(c.id)}`,_=H.join(n,v),f=await D(`${v}-`,{parentDir:s});try{const m=cr(t,c.serviceName),E=await pr(()=>Y(o,c.file,"Playwright task file")),w=await e.writeTaskWorkspace({artifactDirectory:f,baseUrl:m,browserFile:r.browserExecutable,databases:t.target.databases,endpoints:t.target.endpoints,handles:t.target.handles,inputs:I,invocationId:t.invocationId,managedModuleEntrypoints:{authoring:r.authoringEntrypoints.authoring,cli:r.family.cli,environment:r.authoringEntrypoints.environment,playwright:r.family.playwright.entrypoint,playwrightCore:r.family.playwrightCore.entrypoint,playwrightTest:r.family.playwrightTest.entrypoint,root:r.authoringEntrypoints.root,rootPackageJson:r.authoringEntrypoints.rootPackageJson},moduleFile:r.family.playwrightTest.entrypoint,orchestration:c.orchestration,rootDirectory:o,serviceName:c.serviceName,sourceFile:E,taskDirectory:_,taskId:c.id});i.defer(async()=>{try{await e.removeOwnedDirectory(w.attachmentDirectory)}catch(d){if(!(d instanceof Error&&"code"in d&&d.code==="ENOTDIR"))throw d}}),p.push({artifactDirectory:f,inputs:I,task:c,preparationFailure:null,prepared:{baseUrl:m,sourceFile:E,workspace:w}})}catch(m){const E=(await ur([_,f],e)).map(w=>w.error);p.push({artifactDirectory:f,inputs:I,task:c,preparationFailure:playwrightPreparationFailure(m,E),prepared:null})}}return Object.freeze({installation:r,invocationEnvironment:l.environment,rootDirectory:o,tasks:Object.freeze(p)})}async function nr(t,r,e,i){const a={...await rr(t.workspace.cacheDirectory,e.inputs.environment),...ar(t,r,e)};try{A(a)}catch{delete a.NODE_COMPILE_CACHE}const s=e.task.deadlineMs-Date.now();if(s<=0)return T(e.task.id,"failed",i,W(),U(e.task.timeoutMs,y));const n=await J({args:[r.installation.family.cli,"test",X(e.prepared.sourceFile),"--config",e.prepared.workspace.configFile],cwd:r.rootDirectory,displayLabel:"Playwright",env:a,executable:process.execPath,signal:t.signal,timeoutMs:s});let l;try{l=await Z({identity:{engineId:"playwright",invocationId:t.invocationId,taskId:e.task.id,sourceFile:e.prepared.sourceFile},artifactDirectory:e.artifactDirectory,outputDirectory:e.prepared.workspace.outputDirectory,reportFile:e.prepared.workspace.reportFile,rootDirectory:r.rootDirectory,sourceFile:e.prepared.sourceFile,stderr:n.stderr,stdout:n.stdout})}catch(h){return T(e.task.id,"failed",i,N(n),playwrightEvidenceCollectionFailure(n,h))}const p=classifyPlaywrightProcessResult(n,l,e.task.timeoutMs,G(t.signal.reason));return T(e.task.id,p.status,i,l.evidence,p.failure)}export function classifyPlaywrightProcessResult(t,r,e,i){const o=F(t,e,i,y);if(o!==null)return o;if(r.outputLimit!==null){const n=r.outputLimit;return{failure:{code:"PLAYWRIGHT_OUTPUT_ARTIFACT_LIMIT",details:{...n},message:`Playwright output exceeded its ${n.limit.toString()} ${n.kind==="bytes"?"byte aggregate":"entry"} artifact limit`},status:"failed"}}const a=r.attachmentFailures.find(n=>n.code==="PLAYWRIGHT_ATTACHMENT_LIMIT");if(a!==void 0)return{failure:a,status:"failed"};if(r.report.failure!==null){const n=r.report.failure;return{...r.report,failure:{...n,details:{...n.details,evidenceErrors:r.reportError===null?0:1,...b(t)}}}}const s=r.attachmentFailures.at(0);return s!==void 0?{failure:s,status:"failed"}:t.exitCode!==0?C(t,y,R(t.stderr)??R(t.stdout)):r.reportError!==null?{failure:{...P(r.reportError,"PLAYWRIGHT_REPORT_INVALID"),classification:"infra"},status:"failed"}:r.report}export function playwrightEvidenceCollectionFailure(t,r){const e=g(r);return M(t,y,e)??{...P(e,"PLAYWRIGHT_EVIDENCE_FAILED"),classification:"infra"}}function ar(t,r,e){const i={...r.invocationEnvironment},o=e.task,a=e.prepared.workspace.inputBootstrapFile,s=e.prepared.workspace.resolutionBootstrapFile;return Object.assign(i,{...e.prepared.baseUrl===null?{}:{BASE_URL:e.prepared.baseUrl},FORCE_COLOR:"0",NO_COLOR:"1",PLAYWRIGHT_BROWSERS_PATH:r.installation.registry.canonicalValue,PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD:"1",TESTKIT_ACTIVE:"1",TESTKIT_INTERNAL_FILE_DEADLINE_MS:String(o.deadlineMs),TESTKIT_INTERNAL_FILE_TIMEOUT_SECONDS:String(Math.max(1,Math.ceil(o.timeoutMs/1e3))),TESTKIT_INVOCATION_ID:t.invocationId,TESTKIT_LEASE_DIR:o.orchestration.lease.directory,TESTKIT_LEASE_ID:o.orchestration.lease.id,TESTKIT_MODE:o.orchestration.mode,...o.orchestration.runtimeId===void 0?{}:{TESTKIT_RUNTIME_ID:o.orchestration.runtimeId},TESTKIT_TEST_FILE:o.file,TESTKIT_TEST_ID:o.id}),i.NODE_OPTIONS=sr(s,a),A(i),i}function sr(t,r){return["--experimental-strip-types",`--require=${JSON.stringify(t)}`,`--import=${JSON.stringify(K(r).href)}`].join(" ")}export function playwrightSpawnEnvironmentBytes(t){return Object.entries(t).reduce((r,[e,i])=>r+(process.platform==="win32"?(e.length+i.length+2)*2:Buffer.byteLength(e,"utf8")+Buffer.byteLength(i,"utf8")+2),0)}function A(t){if(Object.keys(t).length>L)throw new Error(`Playwright physical spawn environment exceeds its ${L.toString()} entry limit`);if(playwrightSpawnEnvironmentBytes(t)>PLAYWRIGHT_SPAWN_ENVIRONMENT_MAX_BYTES)throw new Error(`Playwright physical spawn environment exceeds its ${PLAYWRIGHT_SPAWN_ENVIRONMENT_MAX_BYTES.toString()} byte limit`)}function cr(t,r){const e=t.target.baseUrl;if(e===null)return null;if(typeof e!="string"||e.trim().length===0)throw new Error(`Playwright task service ${r} endpoint must be a non-empty URL`);let i;try{i=new URL(e)}catch(o){throw new Error(`Playwright task service ${r} endpoint is not a valid URL`,{cause:o})}if(i.protocol!=="http:"&&i.protocol!=="https:")throw new Error(`Playwright task service ${r} endpoint must use http or https`);return i.href}function lr(t,r){return{...q({engineId:"playwright",installationKind:"root-playwright-family",profile:t.profile}),browserName:"chromium",packages:{playwright:r.family.playwright.version,playwrightCore:r.family.playwrightCore.version,playwrightTest:r.family.playwrightTest.version},registryMode:r.registry.mode}}export function playwrightPreparationFailure(t,r){if(r.length===0)return{...P(t,"PLAYWRIGHT_PREPARE_FAILED"),classification:t instanceof k||t instanceof z?"product":"infra"};const e=g(t);return{classification:"infra",code:"PLAYWRIGHT_PREPARE_CLEANUP_FAILED",details:{cleanupFailures:r.map(i=>i.message),preparationFailure:e.message},message:`Playwright task preparation failed and its partial workspace could not be removed: ${r.map(i=>i.message).join("; ")}`,...e.stack===void 0?{}:{stack:e.stack}}}async function pr(t){try{return await t()}catch(r){throw new k(r)}}async function ur(t,r){const e=[];for(const i of t)try{await r.removeOwnedDirectory(i)}catch(o){e.push({directory:i,error:g(o)})}return e}
@@ -1,8 +1,8 @@
1
- import{ownedRuntimeInputModuleUrl as w}from"../../runtime-input-file.js";import b from"node:crypto";import n from"node:fs/promises";import o from"node:path";import{fileURLToPath as j,pathToFileURL as g}from"node:url";import{managedNodeModuleResolutionBootstrapSource as P}from"../../managed-module-resolution.js";import{materializePlaywrightRuntimeInput as v,playwrightRuntimeInputBootstrapSource as T}from"../runtime/runtime-input.js";import{nativeReporterFile as k}from"../../adapters/native-report.js";export class PlaywrightConsumerConfigurationError extends Error{constructor(r){const t=r instanceof Error?r:new Error(String(r));super(t.message,{cause:t}),this.name="PlaywrightConsumerConfigurationError"}}export function playwrightExactFileFilter(e){return d(e)}export async function writePlaywrightTaskWorkspace(e){let r;try{x(e.inputs.supportModules),r=await O(e.rootDirectory,e.inputs)}catch(m){throw new PlaywrightConsumerConfigurationError(m)}await n.mkdir(e.taskDirectory,{recursive:!0}),await n.mkdir(e.artifactDirectory,{recursive:!0});const t=b.randomUUID(),i=o.join(e.taskDirectory,`playwright-${t}.config.mjs`),a=o.join(e.taskDirectory,`playwright-${t}.input-bootstrap.mjs`),l=o.join(e.taskDirectory,`playwright-${t}.resolution-bootstrap.cjs`),f=o.join(e.taskDirectory,"testkit-playwright-report.json"),p=o.join(e.artifactDirectory,"playwright-output");await n.mkdir(p);const c=o.join(e.artifactDirectory,"playwright-attachments");await n.mkdir(c,{mode:448,recursive:!1});const u=await v({baseUrl:e.baseUrl,directory:e.taskDirectory,endpoints:e.endpoints,inputs:e.inputs,invocationId:e.invocationId,orchestration:e.orchestration,taskId:e.taskId}),y=k("playwright");return await h(l,playwrightResolutionBootstrapSource(e.managedModuleEntrypoints,{consumerRoots:[e.rootDirectory],trustedImporterFiles:[i,a],trustedInternalEntrypoints:[e.moduleFile,y,j(w)]})),await h(a,T({digest:u.digest,file:u.file,sizeBytes:u.sizeBytes,invocationId:e.invocationId,taskId:e.taskId})),await h(i,F({baseConfigFile:r,baseUrl:e.baseUrl,browserFile:e.browserFile,inputBootstrapFile:a,outputDirectory:p,reporterFile:y,report:{attachmentDirectory:c,identity:{engineId:"playwright",invocationId:e.invocationId,taskId:e.taskId,sourceFile:e.sourceFile},reportFile:f,workspaceDirectory:e.taskDirectory},rootDirectory:e.rootDirectory,sourceFile:e.sourceFile})),{attachmentDirectory:c,configFile:i,inputBootstrapFile:a,outputDirectory:p,reportFile:f,resolutionBootstrapFile:l}}export function playwrightResolutionBootstrapSource(e,r){const t={authoring:s(e.authoring,"authoring"),cli:s(e.cli,"cli"),playwright:s(e.playwright,"playwright"),playwrightCore:s(e.playwrightCore,"playwrightCore"),playwrightTest:s(e.playwrightTest,"playwrightTest"),root:s(e.root,"root"),rootPackageJson:s(e.rootPackageJson,"rootPackageJson")},i={"@playwright/test":t.playwrightTest,playwright:t.playwright,"playwright-core":t.playwrightCore};return P({consumerRoots:r.consumerRoots,direct:{"@gfdelarue/testkit":t.root,"@gfdelarue/testkit/package.json":t.rootPackageJson,"@gfdelarue/testkit/playwright":t.authoring},directBridgeRoots:[o.dirname(t.root)],engineLabel:"Playwright",forbiddenConsumerPackagePrefixes:[],packageAnchors:i,reservedPackageNames:["@gfdelarue/testkit"],stateSymbol:"@gfdelarue/testkit/playwright-resolution-hooks/v1",trustedImporterFiles:r.trustedImporterFiles,trustedInternalEntrypoints:r.trustedInternalEntrypoints,verifiedParentlessPackageFiles:{playwright:["lib/common/process.js"]},verifiedProcessEntrypoints:[t.cli]})}function s(e,r){if(!o.isAbsolute(e))throw new Error(`Resolved Playwright installation ${r} entrypoint must be absolute`);return e}function F(e){return`
1
+ import{ownedRuntimeInputModuleUrl as d}from"../../runtime-input-file.js";import w from"node:crypto";import n from"node:fs/promises";import o from"node:path";import{fileURLToPath as b,pathToFileURL as g}from"node:url";import{createManagedNodeModuleResolution as j}from"../../managed-module-resolution.js";import{materializePlaywrightRuntimeInput as P,playwrightRuntimeInputBootstrapSource as v}from"../runtime/runtime-input.js";import{nativeReporterFile as T}from"../../adapters/native-report.js";import{requireConsumerFile as k}from"../../adapters/workspace.js";export class PlaywrightConsumerConfigurationError extends Error{constructor(r){const t=r instanceof Error?r:new Error(String(r));super(t.message,{cause:t}),this.name="PlaywrightConsumerConfigurationError"}}export async function writePlaywrightTaskWorkspace(e){let r;try{F(e.inputs.supportModules),r=await D(e.rootDirectory,e.inputs)}catch(m){throw new PlaywrightConsumerConfigurationError(m)}await n.mkdir(e.taskDirectory,{recursive:!0}),await n.mkdir(e.artifactDirectory,{recursive:!0});const t=w.randomUUID(),i=o.join(e.taskDirectory,`playwright-${t}.config.mjs`),s=o.join(e.taskDirectory,`playwright-${t}.input-bootstrap.mjs`),h=o.join(e.taskDirectory,`playwright-${t}.resolution-bootstrap.cjs`),f=o.join(e.taskDirectory,"testkit-playwright-report.json"),l=o.join(e.artifactDirectory,"playwright-output");await n.mkdir(l);const p=o.join(e.artifactDirectory,"playwright-attachments");await n.mkdir(p,{mode:448,recursive:!1});const c=await P({baseUrl:e.baseUrl,databases:e.databases,directory:e.taskDirectory,endpoints:e.endpoints,handles:e.handles,inputs:e.inputs,invocationId:e.invocationId,orchestration:e.orchestration,taskId:e.taskId}),y=T("playwright");return await u(h,playwrightResolutionBootstrapSource(e.managedModuleEntrypoints,{consumerRoots:[e.rootDirectory],trustedImporterFiles:[i,s],trustedInternalEntrypoints:[e.moduleFile,y,b(d)]})),await u(s,v({digest:c.digest,file:c.file,sizeBytes:c.sizeBytes,invocationId:e.invocationId,taskId:e.taskId})),await u(i,O({baseConfigFile:r,baseUrl:e.baseUrl,browserFile:e.browserFile,inputBootstrapFile:s,outputDirectory:l,reporterFile:y,report:{attachmentDirectory:p,identity:{engineId:"playwright",invocationId:e.invocationId,taskId:e.taskId,sourceFile:e.sourceFile},reportFile:f,workspaceDirectory:e.taskDirectory},rootDirectory:e.rootDirectory,sourceFile:e.sourceFile})),{attachmentDirectory:p,configFile:i,inputBootstrapFile:s,outputDirectory:l,reportFile:f,resolutionBootstrapFile:h}}export function playwrightResolutionBootstrapSource(e,r){const t={authoring:a(e.authoring,"authoring"),cli:a(e.cli,"cli"),environment:a(e.environment,"environment"),playwright:a(e.playwright,"playwright"),playwrightCore:a(e.playwrightCore,"playwrightCore"),playwrightTest:a(e.playwrightTest,"playwrightTest"),root:a(e.root,"root"),rootPackageJson:a(e.rootPackageJson,"rootPackageJson")},i={"@playwright/test":t.playwrightTest,playwright:t.playwright,"playwright-core":t.playwrightCore};return j({consumerRoots:r.consumerRoots,direct:{"@gfdelarue/testkit":t.root,"@gfdelarue/testkit/environment":t.environment,"@gfdelarue/testkit/package.json":t.rootPackageJson,"@gfdelarue/testkit/playwright":t.authoring},directBridgeRoots:[o.dirname(t.root)],engineLabel:"Playwright",forbiddenConsumerPackagePrefixes:[],packageAnchors:i,reservedPackageNames:["@gfdelarue/testkit"],stateSymbol:"@gfdelarue/testkit/playwright-resolution-hooks/v1",trustedImporterFiles:r.trustedImporterFiles,trustedInternalEntrypoints:r.trustedInternalEntrypoints,verifiedParentlessPackageFiles:{playwright:["lib/common/process.js"]},verifiedProcessEntrypoints:[t.cli]}).bootstrapSource}function a(e,r){if(!o.isAbsolute(e))throw new Error(`Resolved Playwright installation ${r} entrypoint must be absolute`);return e}function O(e){return`
2
2
  import path from "node:path";
3
3
  import { createRequire } from "node:module";
4
4
 
5
- const OPTIONS = ${JSON.stringify({baseConfigUrl:e.baseConfigFile===null?null:g(e.baseConfigFile).href,baseUrl:e.baseUrl,browserFile:e.browserFile,exactTaskMatchSource:d(e.sourceFile),originalConfigDirectory:e.baseConfigFile===null?e.rootDirectory:o.dirname(e.baseConfigFile),originalConfigFile:e.baseConfigFile??o.join(e.rootDirectory,"__testkit_playwright_config__.mjs"),inputBootstrapUrl:g(e.inputBootstrapFile).href,outputDirectory:e.outputDirectory,report:e.report,reporterFile:e.reporterFile,rootDirectory:e.rootDirectory,sourceFile:e.sourceFile})};
5
+ const OPTIONS = ${JSON.stringify({baseConfigUrl:e.baseConfigFile===null?null:g(e.baseConfigFile).href,baseUrl:e.baseUrl,browserFile:e.browserFile,exactTaskMatchSource:playwrightExactFileFilter(e.sourceFile),originalConfigDirectory:e.baseConfigFile===null?e.rootDirectory:o.dirname(e.baseConfigFile),originalConfigFile:e.baseConfigFile??o.join(e.rootDirectory,"__testkit_playwright_config__.mjs"),inputBootstrapUrl:g(e.inputBootstrapFile).href,outputDirectory:e.outputDirectory,report:e.report,reporterFile:e.reporterFile,rootDirectory:e.rootDirectory,sourceFile:e.sourceFile})};
6
6
  const inputBootstrap = await import(OPTIONS.inputBootstrapUrl);
7
7
  if (typeof inputBootstrap.installPlaywrightRuntimeInput !== "function")
8
8
  throw new Error("Managed Playwright runtime-input bootstrap is invalid");
@@ -63,7 +63,7 @@ function normalizeUse(use, label) {
63
63
  return {
64
64
  ...value,
65
65
  browserName: "chromium",
66
- baseURL: OPTIONS.baseUrl,
66
+ ...(OPTIONS.baseUrl === null ? {} : { baseURL: OPTIONS.baseUrl }),
67
67
  launchOptions: {
68
68
  ...(value.launchOptions && typeof value.launchOptions === "object" ? value.launchOptions : {}),
69
69
  executablePath: OPTIONS.browserFile,
@@ -164,4 +164,4 @@ export default {
164
164
  fullyParallel: false,
165
165
  workers: 1,
166
166
  };
167
- `}function d(e){return`^${e.split(/[\\/]+/u).map(r=>r.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")).join("[\\\\/]")}$`}async function O(e,r){if(!Object.hasOwn(r.supportModules,"playwrightConfig"))return null;const t=r.supportModules.playwrightConfig;if(!o.isAbsolute(t))throw new Error("supportModules.playwrightConfig must be an absolute path");return D(e,t,"supportModules.playwrightConfig")}function x(e){const r=Object.keys(e).filter(t=>t!=="playwrightConfig");if(r.length>0)throw new Error(`Playwright engine does not support support module(s): ${r.join(", ")}`)}async function D(e,r,t){const i=o.resolve(e,r),a=await n.realpath(i);if(!I(e,a))throw new Error(`${t} must stay within the consumer root`);if(!(await n.stat(a)).isFile())throw new Error(`${t} must be a regular file`);return a}function I(e,r){const t=o.relative(e,r);return t===""||!t.startsWith("..")&&!o.isAbsolute(t)}async function h(e,r){const t=await n.open(e,"wx",384);try{await t.writeFile(r,"utf8")}finally{await t.close()}}
167
+ `}export function playwrightExactFileFilter(e){return`^${e.split(/[\\/]+/u).map(r=>r.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")).join("[\\\\/]")}$`}async function D(e,r){if(!Object.hasOwn(r.supportModules,"playwrightConfig"))return null;const t=r.supportModules.playwrightConfig;if(!o.isAbsolute(t))throw new Error("supportModules.playwrightConfig must be an absolute path");return k(e,t,"supportModules.playwrightConfig")}function F(e){const r=Object.keys(e).filter(t=>t!=="playwrightConfig");if(r.length>0)throw new Error(`Playwright engine does not support support module(s): ${r.join(", ")}`)}async function u(e,r){const t=await n.open(e,"wx",384);try{await t.writeFile(r,"utf8")}finally{await t.close()}}
@@ -1 +1 @@
1
- import e from"node:path";export function nonNegativeInteger(t,r){if(typeof t!="number"||!Number.isSafeInteger(t)||t<0)throw new Error(`${r} must be a non-negative safe integer`);return t}export function optionalNonNegativeInteger(t,r){return t==null?null:nonNegativeInteger(t,r)}export function nonNegativeNumber(t,r){if(typeof t!="number"||!Number.isFinite(t)||t<0)throw new Error(`${r} must be a non-negative finite number`);return t}export function requireNonEmptyString(t,r){const n=optionalNonEmptyString(t);if(n===null)throw new Error(`${r} must be a non-empty string`);return n}export function optionalNonEmptyString(t){return typeof t=="string"&&t.trim().length>0?t.trim():null}export function portableReportPath(t){return t.replaceAll("\\","/")}export function portableRelativePath(t,r){return portableReportPath(e.relative(t,r))}export function requireRecord(t,r){if(!isRecord(t))throw new Error(`${r} must contain an object`);return t}export function isRecord(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}export function isPathWithin(t,r){const n=e.relative(t,r);return n===""||!n.startsWith("..")&&!e.isAbsolute(n)}export function isMissingFileError(t){return t instanceof Error&&"code"in t&&t.code==="ENOENT"}export function toError(t){return t instanceof Error?t:new Error(String(t))}
1
+ import e from"node:path";import{isUnknownRecord as o}from"../../../kernel/unknown-values.js";export function nonNegativeInteger(n,r){if(typeof n!="number"||!Number.isSafeInteger(n)||n<0)throw new Error(`${r} must be a non-negative safe integer`);return n}export function optionalNonNegativeInteger(n,r){return n==null?null:nonNegativeInteger(n,r)}export function nonNegativeNumber(n,r){if(typeof n!="number"||!Number.isFinite(n)||n<0)throw new Error(`${r} must be a non-negative finite number`);return n}export function requireNonEmptyString(n,r){const t=optionalNonEmptyString(n);if(t===null)throw new Error(`${r} must be a non-empty string`);return t}export function optionalNonEmptyString(n){return typeof n=="string"&&n.trim().length>0?n.trim():null}export function portableReportPath(n){return n.replaceAll("\\","/")}export function portableRelativePath(n,r){return portableReportPath(e.relative(n,r))}export function requireRecord(n,r){if(!o(n))throw new Error(`${r} must contain an object`);return n}
@@ -1 +1 @@
1
- import w from"node:fs/promises";import g from"node:path";import{evidenceArtifact as F,evidenceFileAccess as q,readStableJsonFile as tt,snapshotStableEvidenceFile as C,stableEvidenceFromBuffer as et,writeOwnedEvidenceFile as Y}from"../../adapters/evidence-files.js";import{materializePlaywrightFailureDetails as it}from"./failure-details.js";import{isMissingFileError as rt,isPathWithin as $,nonNegativeInteger as E,nonNegativeNumber as H,optionalNonEmptyString as N,optionalNonNegativeInteger as G,portableRelativePath as U,portableReportPath as W,requireNonEmptyString as b,requireRecord as S,toError as nt}from"./evidence-validation.js";import{readNativeReport as at}from"../../adapters/native-report.js";import{attachmentLimitError as st,attachmentIoError as ot,MAX_ATTACHMENT_BYTES as X,MAX_TOTAL_ATTACHMENT_BYTES as ct}from"./attachments.js";const lt=64*1024*1024,J=1e4,M=512*1024*1024,ut=2*1024*1024,V=128,pt=".testkit-playwright-evidence",dt=/(?:^|\n)(?:Error:\s*)?No tests found(?:\.|\n|$)/u,ht=["failed","interrupted","passed","timedout"];class R extends Error{limit;constructor(e){super(vt(e)),this.limit=e,this.name="PlaywrightOutputArtifactLimitError"}}export async function collectPlaywrightEvidence(t,e=q){await w.mkdir(t.artifactDirectory,{recursive:!0});const i=await w.realpath(t.artifactDirectory),c=await w.realpath(t.rootDirectory),n=g.join(i,pt);await w.mkdir(n,{mode:448,recursive:!1});const a=[],s=[];for(const r of["stdout","stderr"]){const l=t[r];if(l.length===0)continue;a.push({stream:r,text:l});const m=et(Buffer.from(l,"utf8")),y=await Y(n,`${r}.log`,m.contents);s.push(F(y,m,"text/plain; charset=utf-8","engine.process-output",`playwright-${r}`,`${m.sizeBytes.toString()} bytes`))}let p=null,d=null,f=new Set,h=[];try{const r=await tt(t.reportFile,lt,"Testkit native Playwright report",e);if(r.file===null)p=new Error("Playwright did not produce its Testkit native report");else{d=gt(at(r.value,t.identity).result,t.sourceFile);const l=await Y(n,"testkit-playwright-report.json",r.file.contents);s.push(F(l,r.file,"application/json","engine.testkit-playwright-report","testkit-playwright-report","Testkit native Playwright report")),a.push(...d.logs);const m=await it(n,d.failureDetails);m!==null&&s.push(m);const y=await wt(i,n,c,d.attachments,e);s.push(...y.artifacts),f=y.sourcePaths,h=y.failures}}catch(r){p=nt(r)}let o={artifacts:[],bytes:0,entries:0},u=null;try{o=await Pt(i,n,t.outputDirectory,f,e),s.push(...o.artifacts)}catch(r){if(!(r instanceof R))throw r;u=r.limit,a.push({stream:"engine",text:r.message})}const P=ft(d,c,t.sourceFile,h.length),k=u??o;return{attachmentFailures:h,evidence:{artifacts:s,logs:a,metrics:[...Object.entries(d?.stats??{}).map(([r,l])=>({name:r==="duration"?"playwright.duration":`playwright.tests.${r}`,unit:r==="duration"?"milliseconds":"tests",value:l})),...["bytes","entries"].map(r=>({name:`playwright.output.${r}`,unit:r,value:k[r]}))],...d===null?{}:{native:{playwright:{attachmentFailures:h.map(r=>({...r})),specs:d.specs,stats:d.stats}}}},outputLimit:u,report:P,reportError:p}}function ft(t,e,i,c){if(t===null)return{failure:null,status:"failed"};const n=t.specs.filter((s,p)=>K(i,t.sourceFiles[p])),a=t.failureMessages.length>0&&t.failureMessages.every(s=>dt.test(s));return t.stats.unexpected>0||t.failureMessages.length>0&&(!a||n.length>0)?{failure:{...t.failureMessages.some(s=>/browserType\.launch(?:PersistentContext)?:/u.test(s)&&/Executable doesn't exist|Host system is missing dependencies|error while loading shared libraries|Failed to launch/u.test(s))?{classification:"infra"}:{},code:"PLAYWRIGHT_SPECS_FAILED",details:{attachmentFailures:c,failOnFlakyTests:t.failOnFlakyTests,reportErrors:t.reportErrors,runStatus:t.runStatus,stats:t.stats,specs:t.specs.slice(0,50)},message:t.failureMessages.at(0)??`${t.stats.unexpected.toString()} Playwright test(s) failed`},status:"failed"}:n.length>0?{failure:null,status:n.every(s=>s.status==="skipped")?"skipped":"passed"}:{failure:{code:"PLAYWRIGHT_NO_TESTS",details:{file:U(e,i),reportedSpecs:t.specs.slice(0,50),stats:t.stats},message:"Selected Playwright task did not execute any tests"},status:"failed"}}function K(t,e){return g.relative(g.normalize(t),e)===""}function gt(t,e){const i=S(t,"Playwright native report result"),c=ht.find(r=>r===i.status);if(c===void 0)throw new Error("Playwright native report status is invalid");if(typeof i.failOnFlakyTests!="boolean")throw new Error("Playwright native report failOnFlakyTests must be a boolean");const n=i.failOnFlakyTests,a=bt(i.stats),s=O(i.errors,"errors"),p=s.length,d=[],f=[],h=[],o=new Set,u={expected:0,flaky:0,skipped:0,unexpected:0};for(const r of A(i.specs,"specs")){const l=S(r,"Playwright native report spec"),m=b(l.id,"Playwright native spec.id");if(o.has(m))throw new Error("Playwright native report contains a duplicate test identity");o.add(m);const y=b(l.title,"Playwright native spec.title"),v=O(l.parents,"spec.parents");v.length>0&&(v[0]=W(v[0]));const L=W(b(l.file,"Playwright native spec.file")),x=b(l.sourceFile,"Playwright native spec.sourceFile");if(!g.isAbsolute(x)&&!g.win32.isAbsolute(x))throw new Error("Playwright native spec.sourceFile must be absolute");const Z=_(l.projectName,"spec.projectName"),T=l.status;if(T!=="expected"&&T!=="flaky"&&T!=="skipped"&&T!=="unexpected")throw new Error("Playwright native spec.status is invalid");u[T]+=1;const j=O(l.failureMessages,"spec.failureMessages"),z=l.failureStack===null?null:_(l.failureStack,"spec.failureStack"),D=G(l.line,"Playwright native spec.line"),B=G(l.column,"Playwright native spec.column");T==="unexpected"&&(s.push(...j),h.push({kind:K(e,x)?"playwright-spec":"playwright-other-file-spec",key:[...v.slice(1),y].filter(Boolean).join(" "),title:y,count:1,message:j[0]??`Playwright reported "${y}" as an unexpected failure`,...v.length===0?{}:{suitePath:v},location:{path:L,...D===null?{}:{line:D},...B===null?{}:{column:B}},...z===null?{}:{stack:z}})),f.push(x),d.push({durationMs:H(l.durationMs,"Playwright native spec.durationMs"),retries:E(l.retries,"Playwright native spec.retries"),file:L,projectName:Z,status:T,title:[...v,y].filter(Boolean).join(" > ")})}for(const r of["expected","flaky","skipped","unexpected"])if(a[r]!==u[r])throw new Error("Playwright native report stats do not match its cases");const P=A(i.logs,"logs").map(r=>{const l=S(r,"Playwright native report log");if(l.stream!=="stdout"&&l.stream!=="stderr")throw new Error("Playwright native report log stream is invalid");return{stream:l.stream,text:_(l.text,"log.text")}});return{attachments:A(i.attachments,"attachments").map((r,l)=>yt(r,l,o)),failOnFlakyTests:n,failureDetails:h,failureMessages:s,logs:St(P),reportErrors:p,runStatus:c,sourceFiles:f,specs:d,stats:a}}function A(t,e){if(!Array.isArray(t))throw new Error(`Playwright native report ${e} must be an array`);return t}function O(t,e){return A(t,e).map(i=>_(i,e))}function _(t,e){if(typeof t!="string")throw new Error(`Playwright native report ${e} must be a string`);return t}function yt(t,e,i){const c=S(t,`Playwright attachment[${e.toString()}]`),n=b(c.specId,"Playwright attachment.specId");if(!i.has(n))throw new Error("Playwright native attachment references an unknown test identity");const a=N(c.path),s=c.error===void 0?void 0:mt(c.error);if(c.body!==void 0||a===null&&s===void 0)throw new Error("Playwright attachment must contain a path or an error");return{contentType:N(c.contentType)??"application/octet-stream",name:N(c.name)??`attachment-${e.toString()}`,specId:n,...a===null?{}:{path:a},...s===void 0?{}:{error:s},retry:E(c.retry,"Playwright attachment.retry"),specTitle:b(c.specTitle,"Playwright attachment.specTitle")}}function mt(t){const e=S(t,"Playwright attachment.error");if(e.kind==="io")return{kind:"io",message:b(e.message,"Playwright attachment.error.message")};const i=e.kind;if(i!=="individual"&&i!=="total")throw new Error("Playwright attachment.error has an invalid kind");const c=i==="individual"?X:ct,n=E(e.observed,"Playwright attachment.error.observed");if(e.limit!==c||n<=c)throw new Error("Playwright attachment.error has an invalid limit");return{kind:i,limit:c,observed:n}}function I(t,e){const{name:i,specId:c,specTitle:n,retry:a}=t,s=e.kind==="io"?e.message:`exceeds its ${e.limit.toString()} byte ${e.kind} limit (observed ${e.observed.toString()} bytes)`;return{code:e.kind==="io"?"PLAYWRIGHT_ATTACHMENT_FAILED":"PLAYWRIGHT_ATTACHMENT_LIMIT",...e.kind==="io"?{classification:"infra"}:{},details:{name:i,specId:c,specTitle:n,retry:a,...e},message:`Playwright attachment "${i}" (${n}, retry ${a.toString()}): ${s}`}}async function wt(t,e,i,c,n){const a=[],s=[],p=new Set;let d=0;const f=g.join(e,"attachments");c.length>0&&await w.mkdir(f,{mode:448,recursive:!1});for(const[h,o]of c.entries())try{if(o.error!==void 0){o.path!==void 0&&p.add(g.resolve(i,o.path)),s.push(I(o,o.error));continue}const u=await Tt(o.path,i,t,n);p.add(u.file);const P=E(Number(u.identity.size),"Playwright attachment size"),k=st(P,d+P);if(k!==null){s.push(I(o,k));continue}const r=await C(u.file,X,"Playwright attachment",n,u.identity,f,`${h.toString().padStart(4,"0")}-${Q(o.name)}${kt(o)}`);d+=r.identity.sizeBytes,a.push({path:r.filePath,contentType:o.contentType,kind:"engine.playwright-attachment",name:o.name,summary:`${o.specTitle} retry ${o.retry.toString()}`,metadata:{...r.identity,specId:o.specId,specTitle:o.specTitle,retry:o.retry}})}catch(u){s.push(I(o,ot(u)))}return{artifacts:a,failures:s,sourcePaths:p}}async function Pt(t,e,i,c,n){try{const a=await n.lstat(i);if(!a.isDirectory()||a.isSymbolicLink())throw new Error("Playwright output directory must be a non-symbolic-link directory");const s=await w.realpath(i);if(!$(t,s))throw new Error("Playwright output directory escaped the artifact root");const p=await Et(s,c,n),d=[],f=g.join(e,"output");p.candidates.length>0&&await w.mkdir(f,{mode:448,recursive:!1});for(const[h,o]of p.candidates.entries()){const u=await C(o.file,M,"Playwright output file",n,o.identity,f,`${h.toString().padStart(5,"0")}-${Q(g.basename(o.file))}${At(o.file)}`);d.push(F(u.filePath,u.identity,xt(o.file),"engine.playwright-output",o.relativePath,"Playwright output"))}return{artifacts:d,bytes:p.bytes,entries:p.entries}}catch(a){if(rt(a))return{artifacts:[],bytes:0,entries:0};throw a}}async function Et(t,e,i){const c=[];let n=0,a=0;const s=[{depth:0,directory:t}];for(;s.length>0;){const p=s.pop();if(p===void 0)continue;if(p.depth>V)throw new Error(`Playwright output exceeds the ${V.toString()} level directory depth limit`);const d=p.directory,f=await w.readdir(d,{withFileTypes:!0});f.sort((h,o)=>h.name.localeCompare(o.name));for(const h of f){if(a+=1,a>J)throw new R({bytes:n,entries:a,kind:"entries",limit:J,observed:a});const o=g.join(d,h.name),u=await i.lstat(o);if(u.isSymbolicLink())throw new Error("Playwright output must not contain symbolic links");if(u.isDirectory()){s.push({depth:p.depth+1,directory:o});continue}if(!u.isFile())continue;if(u.size<0n||u.size>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("Playwright output file has an invalid size");const P=Number(u.size);if(n+=P,!Number.isSafeInteger(n)||n>M)throw new R({bytes:n,entries:a,kind:"bytes",limit:M,observed:n});e.has(o)||c.push({file:o,identity:u,relativePath:U(t,o)})}}return{bytes:n,candidates:c,entries:a}}function vt(t){return t.kind==="bytes"?`Playwright output exceeds its ${t.limit.toString()} byte aggregate limit (observed ${t.observed.toString()} bytes)`:`Playwright output exceeds its ${t.limit.toString()} entry limit (observed ${t.observed.toString()} entries)`}async function Tt(t,e,i,c){if(t===void 0)throw new Error("Playwright path attachment did not declare a path");const n=g.resolve(e,t),a=await c.lstat(n);if(!a.isFile()||a.isSymbolicLink())throw new Error("Playwright attachment path must be a regular non-symbolic-link file");const s=await w.realpath(n);if(!$(e,s)&&!$(i,s))throw new Error("Playwright attachment path must stay within the consumer or artifact root");return{file:s,identity:a}}function bt(t){const e=S(t,"Playwright report.stats");return{expected:E(e.expected,"Playwright stats.expected"),unexpected:E(e.unexpected,"Playwright stats.unexpected"),flaky:E(e.flaky,"Playwright stats.flaky"),skipped:E(e.skipped,"Playwright stats.skipped"),duration:H(e.duration,"Playwright stats.duration")}}function St(t){let e=ut;const i=[];for(const c of t){if(e<=0)break;const a=Buffer.from(c.text,"utf8").subarray(0,e).toString("utf8");a.length>0&&i.push({...c,text:a}),e-=Buffer.byteLength(a)}return e<=0&&i.push({stream:"engine",text:"Playwright report log evidence was truncated at its bounded limit"}),i}function kt(t){if(t.path!==void 0){const e=g.extname(t.path);if(/^\.[a-z0-9]{1,12}$/iu.test(e))return e}return t.contentType==="application/json"?".json":t.contentType.startsWith("text/")?".txt":t.contentType==="image/png"?".png":t.contentType==="image/jpeg"?".jpg":".bin"}function xt(t){const e=g.extname(t).toLowerCase();return e===".json"?"application/json":e===".zip"?"application/zip":e===".png"?"image/png":e===".jpg"||e===".jpeg"?"image/jpeg":e===".webm"?"video/webm":[".log",".txt",".md"].includes(e)?"text/plain; charset=utf-8":"application/octet-stream"}function At(t){const e=g.extname(t).toLowerCase();return/^\.[a-z0-9]{1,12}$/u.test(e)?e:".bin"}function Q(t){const e=t.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,80);return e.length>0?e:"attachment"}
1
+ import{toError as ot}from"../../../kernel/error-serialization.js";import{isPathWithin as N}from"../../../process/files/paths.js";import v from"node:fs/promises";import g from"node:path";import{evidenceArtifact as O,evidenceFileAccess as lt,readStableJsonFile as ct,snapshotStableEvidenceFile as U,stableEvidenceFromBuffer as X,writeOwnedEvidenceFile as V,isMissingFileError as ut}from"../../adapters/evidence-files.js";import{materializePlaywrightFailureDetails as pt}from"./failure-details.js";import{nonNegativeInteger as T,nonNegativeNumber as J,optionalNonEmptyString as R,optionalNonNegativeInteger as K,portableRelativePath as Q,portableReportPath as Z,requireNonEmptyString as k,requireRecord as P}from"./evidence-validation.js";import{readNativeReport as dt}from"../../adapters/native-report.js";import{environmentValueMissingFailure as ht,parseEnvironmentValueMissingFailure as q,readEnvironmentValueMissingFailure as ft}from"../../contracts/environment-values.js";import{attachmentLimitError as mt,attachmentIoError as gt,MAX_ATTACHMENT_BYTES as tt,MAX_TOTAL_ATTACHMENT_BYTES as yt}from"./attachments.js";const wt=64*1024*1024,et=1e4,I=512*1024*1024,vt=2*1024*1024,it=128,Pt=".testkit-playwright-evidence",Et=/(?:^|\n)(?:Error:\s*)?No tests found(?:\.|\n|$)/u,Tt=["failed","interrupted","passed","timedout"];class L extends Error{limit;constructor(e){super(Mt(e)),this.limit=e,this.name="PlaywrightOutputArtifactLimitError"}}export async function collectPlaywrightEvidence(t,e=lt){await v.mkdir(t.artifactDirectory,{recursive:!0});const i=await v.realpath(t.artifactDirectory),s=await v.realpath(t.rootDirectory),n=g.join(i,Pt);await v.mkdir(n,{mode:448,recursive:!1});const r=[],o=[];for(const l of["stdout","stderr"]){const y=t[l];if(y.length===0)continue;r.push({stream:l,text:y});const F=X(Buffer.from(y,"utf8")),f=await V(n,`${l}.log`,F.contents);o.push(O(f,F,"text/plain; charset=utf-8","engine.process-output",`playwright-${l}`,`${F.sizeBytes.toString()} bytes`))}let c=null,p=null,m=new Set,h=[];try{const l=await ct(t.reportFile,wt,"Testkit native Playwright report",e);if(l.file===null)c=new Error("Playwright did not produce its Testkit native report");else{p=St(dt(l.value,t.identity).result,t.sourceFile);const y=p.carriesEnvironmentFailures?X(Buffer.from(kt(l.value))):l.file,F=await V(n,"testkit-playwright-report.json",y.contents);o.push(O(F,y,"application/json","engine.testkit-playwright-report","testkit-playwright-report","Testkit native Playwright report")),r.push(...p.logs);const f=await pt(n,p.failureDetails);f!==null&&o.push(f);const u=await At(i,n,s,p.attachments,e);o.push(...u.artifacts),m=u.sourcePaths,h=u.failures}}catch(l){c=ot(l)}let a={artifacts:[],bytes:0,entries:0},d=null;try{a=await _t(i,n,t.outputDirectory,m,e),o.push(...a.artifacts)}catch(l){if(!(l instanceof L))throw l;d=l.limit,r.push({stream:"engine",text:l.message})}const w=bt(p,s,t.sourceFile,h.length),E=d??a;return{attachmentFailures:h,evidence:{artifacts:o,logs:r,metrics:[...Object.entries(p?.stats??{}).map(([l,y])=>({name:l==="duration"?"playwright.duration":`playwright.tests.${l}`,unit:l==="duration"?"milliseconds":"tests",value:y})),...["bytes","entries"].map(l=>({name:`playwright.output.${l}`,unit:l,value:E[l]}))],...p===null?{}:{native:{playwright:{attachmentFailures:h.map(l=>({...l})),specs:p.specs,stats:p.stats}}}},outputLimit:d,report:w,reportError:c}}function bt(t,e,i,s){if(t===null)return{failure:null,status:"failed"};const n=t.environmentFailures.at(0);if(n!==void 0)return{failure:ht(t.environmentFailures.flatMap(c=>ft(c)??[]),n.message),status:"failed"};const r=t.specs.filter((c,p)=>rt(i,t.sourceFiles[p])),o=t.failureMessages.length>0&&t.failureMessages.every(c=>Et.test(c));return t.stats.unexpected>0||t.failureMessages.length>0&&(!o||r.length>0)?{failure:{...t.failureMessages.some(c=>/browserType\.launch(?:PersistentContext)?:/u.test(c)&&/Executable doesn't exist|Host system is missing dependencies|error while loading shared libraries|Failed to launch/u.test(c))?{classification:"infra"}:{},code:"PLAYWRIGHT_SPECS_FAILED",details:{attachmentFailures:s,failOnFlakyTests:t.failOnFlakyTests,reportErrors:t.reportErrors,runStatus:t.runStatus,stats:t.stats,specs:t.specs.slice(0,50)},message:t.failureMessages.at(0)??`${t.stats.unexpected.toString()} Playwright test(s) failed`},status:"failed"}:r.length>0?{failure:null,status:r.every(c=>c.status==="skipped")?"skipped":"passed"}:{failure:{code:"PLAYWRIGHT_NO_TESTS",details:{file:Q(e,i),reportedSpecs:t.specs.slice(0,50),stats:t.stats},message:"Selected Playwright task did not execute any tests"},status:"failed"}}function rt(t,e){return g.relative(g.normalize(t),e)===""}function St(t,e){const i=P(t,"Playwright native report result"),s=Tt.find(f=>f===i.status);if(s===void 0)throw new Error("Playwright native report status is invalid");if(typeof i.failOnFlakyTests!="boolean")throw new Error("Playwright native report failOnFlakyTests must be a boolean");const n=i.failOnFlakyTests,r=Ot(i.stats),o=j(i.errors,"errors"),c=o.length,p=q(i.environmentFailure,"Playwright native report environment failure"),m=p===null?[]:[p];let h=p!==null;const a=[],d=[],w=[],E=new Set,l={expected:0,flaky:0,skipped:0,unexpected:0};for(const f of x(i.specs,"specs")){const u=P(f,"Playwright native report spec"),B=k(u.id,"Playwright native spec.id");if(E.has(B))throw new Error("Playwright native report contains a duplicate test identity");E.add(B);const A=k(u.title,"Playwright native spec.title"),b=j(u.parents,"spec.parents");b.length>0&&(b[0]=Z(b[0]));const D=Z(k(u.file,"Playwright native spec.file")),_=k(u.sourceFile,"Playwright native spec.sourceFile");if(!g.isAbsolute(_)&&!g.win32.isAbsolute(_))throw new Error("Playwright native spec.sourceFile must be absolute");const st=M(u.projectName,"spec.projectName"),S=u.status;if(S!=="expected"&&S!=="flaky"&&S!=="skipped"&&S!=="unexpected")throw new Error("Playwright native spec.status is invalid");l[S]+=1;const C=j(u.failureMessages,"spec.failureMessages"),Y=u.failureStack===null?null:M(u.failureStack,"spec.failureStack"),H=K(u.line,"Playwright native spec.line"),W=K(u.column,"Playwright native spec.column"),G=rt(e,_),$=q(u.environmentFailure,"Playwright native spec environment failure");$!==null&&(h=!0),G&&$!==null&&m.push($),S==="unexpected"&&(o.push(...C),w.push({...$===null?{}:{classification:"infra"},kind:G?"playwright-spec":"playwright-other-file-spec",key:[...b.slice(1),A].filter(Boolean).join(" "),title:A,count:1,message:C[0]??`Playwright reported "${A}" as an unexpected failure`,...b.length===0?{}:{suitePath:b},location:{path:D,...H===null?{}:{line:H},...W===null?{}:{column:W}},...Y===null?{}:{stack:Y}})),d.push(_),a.push({durationMs:J(u.durationMs,"Playwright native spec.durationMs"),retries:T(u.retries,"Playwright native spec.retries"),file:D,projectName:st,status:S,title:[...b,A].filter(Boolean).join(" > ")})}for(const f of["expected","flaky","skipped","unexpected"])if(r[f]!==l[f])throw new Error("Playwright native report stats do not match its cases");const y=x(i.logs,"logs").map(f=>{const u=P(f,"Playwright native report log");if(u.stream!=="stdout"&&u.stream!=="stderr")throw new Error("Playwright native report log stream is invalid");return{stream:u.stream,text:M(u.text,"log.text")}});return{attachments:x(i.attachments,"attachments").map((f,u)=>Ft(f,u,E)),carriesEnvironmentFailures:h,environmentFailures:m,failOnFlakyTests:n,failureDetails:w,failureMessages:o,logs:Rt(y),reportErrors:c,runStatus:s,sourceFiles:d,specs:a,stats:r}}function kt(t){const e=P(t,"Testkit native Playwright report"),i=nt(P(e.result,"Playwright native report result")),s=x(i.specs,"specs").map(n=>nt(P(n,"Playwright native report spec")));return JSON.stringify({...e,result:{...i,specs:s}})}function nt(t){return Object.fromEntries(Object.entries(t).filter(([e])=>e!=="environmentFailure"))}function x(t,e){if(!Array.isArray(t))throw new Error(`Playwright native report ${e} must be an array`);return t}function j(t,e){return x(t,e).map(i=>M(i,e))}function M(t,e){if(typeof t!="string")throw new Error(`Playwright native report ${e} must be a string`);return t}function Ft(t,e,i){const s=P(t,`Playwright attachment[${e.toString()}]`),n=k(s.specId,"Playwright attachment.specId");if(!i.has(n))throw new Error("Playwright native attachment references an unknown test identity");const r=R(s.path),o=s.error===void 0?void 0:xt(s.error);if(s.body!==void 0||r===null&&o===void 0)throw new Error("Playwright attachment must contain a path or an error");return{contentType:R(s.contentType)??"application/octet-stream",name:R(s.name)??`attachment-${e.toString()}`,specId:n,...r===null?{}:{path:r},...o===void 0?{}:{error:o},retry:T(s.retry,"Playwright attachment.retry"),specTitle:k(s.specTitle,"Playwright attachment.specTitle")}}function xt(t){const e=P(t,"Playwright attachment.error");if(e.kind==="io")return{kind:"io",message:k(e.message,"Playwright attachment.error.message")};const i=e.kind;if(i!=="individual"&&i!=="total")throw new Error("Playwright attachment.error has an invalid kind");const s=i==="individual"?tt:yt,n=T(e.observed,"Playwright attachment.error.observed");if(e.limit!==s||n<=s)throw new Error("Playwright attachment.error has an invalid limit");return{kind:i,limit:s,observed:n}}function z(t,e){const{name:i,specId:s,specTitle:n,retry:r}=t,o=e.kind==="io"?e.message:`exceeds its ${e.limit.toString()} byte ${e.kind} limit (observed ${e.observed.toString()} bytes)`;return{code:e.kind==="io"?"PLAYWRIGHT_ATTACHMENT_FAILED":"PLAYWRIGHT_ATTACHMENT_LIMIT",...e.kind==="io"?{classification:"infra"}:{},details:{name:i,specId:s,specTitle:n,retry:r,...e},message:`Playwright attachment "${i}" (${n}, retry ${r.toString()}): ${o}`}}async function At(t,e,i,s,n){const r=[],o=[],c=new Set;let p=0;const m=g.join(e,"attachments");s.length>0&&await v.mkdir(m,{mode:448,recursive:!1});for(const[h,a]of s.entries())try{if(a.error!==void 0){a.path!==void 0&&c.add(g.resolve(i,a.path)),o.push(z(a,a.error));continue}const d=await Nt(a.path,i,t,n);c.add(d.file);const w=T(Number(d.identity.size),"Playwright attachment size"),E=mt(w,p+w);if(E!==null){o.push(z(a,E));continue}const l=await U(d.file,tt,"Playwright attachment",n,d.identity,m,`${h.toString().padStart(4,"0")}-${at(a.name)}${It(a)}`);p+=l.identity.sizeBytes,r.push({path:l.filePath,contentType:a.contentType,kind:"engine.playwright-attachment",name:a.name,summary:`${a.specTitle} retry ${a.retry.toString()}`,metadata:{...l.identity,specId:a.specId,specTitle:a.specTitle,retry:a.retry}})}catch(d){o.push(z(a,gt(d)))}return{artifacts:r,failures:o,sourcePaths:c}}async function _t(t,e,i,s,n){try{const r=await n.lstat(i);if(!r.isDirectory()||r.isSymbolicLink())throw new Error("Playwright output directory must be a non-symbolic-link directory");const o=await v.realpath(i);if(!N(t,o))throw new Error("Playwright output directory escaped the artifact root");const c=await $t(o,s,n),p=[],m=g.join(e,"output");c.candidates.length>0&&await v.mkdir(m,{mode:448,recursive:!1});for(const[h,a]of c.candidates.entries()){const d=await U(a.file,I,"Playwright output file",n,a.identity,m,`${h.toString().padStart(5,"0")}-${at(g.basename(a.file))}${jt(a.file)}`);p.push(O(d.filePath,d.identity,Lt(a.file),"engine.playwright-output",a.relativePath,"Playwright output"))}return{artifacts:p,bytes:c.bytes,entries:c.entries}}catch(r){if(ut(r))return{artifacts:[],bytes:0,entries:0};throw r}}async function $t(t,e,i){const s=[];let n=0,r=0;const o=[{depth:0,directory:t}];for(;o.length>0;){const c=o.pop();if(c===void 0)continue;if(c.depth>it)throw new Error(`Playwright output exceeds the ${it.toString()} level directory depth limit`);const p=c.directory,m=await v.readdir(p,{withFileTypes:!0});m.sort((h,a)=>h.name.localeCompare(a.name));for(const h of m){if(r+=1,r>et)throw new L({bytes:n,entries:r,kind:"entries",limit:et,observed:r});const a=g.join(p,h.name),d=await i.lstat(a);if(d.isSymbolicLink())throw new Error("Playwright output must not contain symbolic links");if(d.isDirectory()){o.push({depth:c.depth+1,directory:a});continue}if(!d.isFile())continue;if(d.size<0n||d.size>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("Playwright output file has an invalid size");const w=Number(d.size);if(n+=w,!Number.isSafeInteger(n)||n>I)throw new L({bytes:n,entries:r,kind:"bytes",limit:I,observed:n});e.has(a)||s.push({file:a,identity:d,relativePath:Q(t,a)})}}return{bytes:n,candidates:s,entries:r}}function Mt(t){return t.kind==="bytes"?`Playwright output exceeds its ${t.limit.toString()} byte aggregate limit (observed ${t.observed.toString()} bytes)`:`Playwright output exceeds its ${t.limit.toString()} entry limit (observed ${t.observed.toString()} entries)`}async function Nt(t,e,i,s){if(t===void 0)throw new Error("Playwright path attachment did not declare a path");const n=g.resolve(e,t),r=await s.lstat(n);if(!r.isFile()||r.isSymbolicLink())throw new Error("Playwright attachment path must be a regular non-symbolic-link file");const o=await v.realpath(n);if(!N(e,o)&&!N(i,o))throw new Error("Playwright attachment path must stay within the consumer or artifact root");return{file:o,identity:r}}function Ot(t){const e=P(t,"Playwright report.stats");return{expected:T(e.expected,"Playwright stats.expected"),unexpected:T(e.unexpected,"Playwright stats.unexpected"),flaky:T(e.flaky,"Playwright stats.flaky"),skipped:T(e.skipped,"Playwright stats.skipped"),duration:J(e.duration,"Playwright stats.duration")}}function Rt(t){let e=vt;const i=[];for(const s of t){if(e<=0)break;const r=Buffer.from(s.text,"utf8").subarray(0,e).toString("utf8");r.length>0&&i.push({...s,text:r}),e-=Buffer.byteLength(r)}return e<=0&&i.push({stream:"engine",text:"Playwright report log evidence was truncated at its bounded limit"}),i}function It(t){if(t.path!==void 0){const e=g.extname(t.path);if(/^\.[a-z0-9]{1,12}$/iu.test(e))return e}return t.contentType==="application/json"?".json":t.contentType.startsWith("text/")?".txt":t.contentType==="image/png"?".png":t.contentType==="image/jpeg"?".jpg":".bin"}function Lt(t){const e=g.extname(t).toLowerCase();return e===".json"?"application/json":e===".zip"?"application/zip":e===".png"?"image/png":e===".jpg"||e===".jpeg"?"image/jpeg":e===".webm"?"video/webm":[".log",".txt",".md"].includes(e)?"text/plain; charset=utf-8":"application/octet-stream"}function jt(t){const e=g.extname(t).toLowerCase();return/^\.[a-z0-9]{1,12}$/u.test(e)?e:".bin"}function at(t){const e=t.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,80);return e.length>0?e:"attachment"}
@@ -1 +1 @@
1
- import f from"node:path";import E from"node:fs/promises";import x from"node:crypto";import{writeNativeReport as D}from"../../adapters/native-report.js";import{writeOwnedEvidenceFile as P}from"../../adapters/evidence-files.js";import{attachmentIoError as j,attachmentLimitError as M}from"./attachments.js";export default class A{options;config;suite;errors=[];constructor(e){this.options=e}onBegin(e,r){this.config=e,this.suite=r}onError(e){this.errors.push(F(e))}async onEnd(e){const r=this.suite.allTests(),o={duration:e.duration,expected:0,flaky:0,skipped:0,unexpected:0},u=[],p=[];let m=0;const d=[];for(const i of r){const y=i.outcome();o[y]+=1;let g=0,h=0,w=[],k=null;for(const s of i.results){g+=s.duration,h=Math.max(h,s.retry);for(const t of["stdout","stderr"])for(const a of s[t])u.push({stream:t,text:typeof a=="string"?a:a.toString("utf8")});for(const t of s.attachments){const a={name:t.name,contentType:t.contentType,...t.path===void 0?{}:{path:t.path},specId:i.id,specTitle:i.title,retry:s.retry};try{let c=t.body?.byteLength;if(c===void 0){if(t.path===void 0)throw new Error("Attachment has no body or path");const l=await E.lstat(t.path);if(!l.isFile()||l.isSymbolicLink())throw new Error("Attachment path must be a regular non-symbolic-link file");c=l.size}const b=M(c,m+c);if(b!==null){p.push({...a,error:b});continue}let v=t.path;if(t.body!==void 0){const l=this.options.attachmentDirectory;if(await E.realpath(l)!==f.resolve(l))throw new Error("Attachment directory must not resolve through symbolic links");v=await P(l,x.randomUUID(),t.body)}p.push({...a,path:v}),m+=c}catch(c){p.push({...a,error:j(c)})}}s.errors.length>0&&(w=s.errors.map(F),k=s.errors.find(t=>t.stack)?.stack??null)}d.push({id:i.id,title:i.title,parents:L(i,this.config.rootDir),file:T(this.config.rootDir,i.location.file),sourceFile:I(i,this.config.rootDir),projectName:i.parent.project()?.name??"",line:i.location.line,column:i.location.column,status:y,durationMs:g,retries:h,failureMessages:w,failureStack:k})}await D(this.options,{status:e.status,failOnFlakyTests:this.options.failOnFlakyTests,stats:o,specs:d,logs:u,attachments:p,errors:this.errors},64*1024*1024)}}function I(n,e){for(let r=n.parent;r;r=r.parent)if(r.type==="file")return f.resolve(e,r.title);return n.location.file}function L(n,e){const r=[];for(let o=n.parent;o&&o.type!=="project"&&o.type!=="root";o=o.parent)r.unshift(o.type==="file"&&o.location?T(e,o.location.file):o.title);return r}function T(n,e){return f.relative(n,e).split(f.sep).join("/")}function F(n){return n.message?.trim()||n.stack?.trim()||n.value?.trim()||"Playwright reported an error"}
1
+ import h from"node:path";import M from"node:fs/promises";import U from"node:crypto";import{stripVTControlCharacters as D}from"node:util";import{writeNativeReport as L}from"../../adapters/native-report.js";import{writeOwnedEvidenceFile as P}from"../../adapters/evidence-files.js";import{boundEnvironmentValueMissingText as V,environmentValueMissingFailure as j,readEnvironmentValueMissingText as F}from"../../contracts/environment-values.js";import{attachmentIoError as C,attachmentLimitError as O}from"./attachments.js";export default class S{options;config;suite;errors=[];missing=[];constructor(t){this.options=t}onBegin(t,r){this.config=t,this.suite=r}onError(t){this.missing.push(...x(t,!1)),this.errors.push(d(g(t)))}async onEnd(t){const r=this.suite.allTests(),o={duration:t.duration,expected:0,flaky:0,skipped:0,unexpected:0},p=[],c=[];let f=0;const y=[];for(const i of r){const v=i.outcome();o[v]+=1;let E=0,m=0,T=[],w=null;const k=[],R=i.parent.project()?.use.baseURL;for(const a of i.results){for(const n of a.errors)k.push(...x(n,!R));E+=a.duration,m=Math.max(m,a.retry);for(const n of["stdout","stderr"])for(const s of a[n])p.push({stream:n,text:typeof s=="string"?s:s.toString("utf8")});for(const n of a.attachments){const s={name:n.name,contentType:n.contentType,...n.path===void 0?{}:{path:n.path},specId:i.id,specTitle:i.title,retry:a.retry};try{let l=n.body?.byteLength;if(l===void 0){if(n.path===void 0)throw new Error("Attachment has no body or path");const u=await M.lstat(n.path);if(!u.isFile()||u.isSymbolicLink())throw new Error("Attachment path must be a regular non-symbolic-link file");l=u.size}const b=O(l,f+l);if(b!==null){c.push({...s,error:b});continue}let A=n.path;if(n.body!==void 0){const u=this.options.attachmentDirectory;if(await M.realpath(u)!==h.resolve(u))throw new Error("Attachment directory must not resolve through symbolic links");A=await P(u,U.randomUUID(),n.body)}c.push({...s,path:A}),f+=l}catch(l){c.push({...s,error:C(l)})}}if(a.errors.length>0){T=a.errors.map(s=>d(g(s)));const n=a.errors.find(s=>s.stack)?.stack;w=n===void 0?null:d(n)}}y.push({id:i.id,title:i.title,parents:X(i,this.config.rootDir),file:I(this.config.rootDir,i.location.file),sourceFile:Z(i,this.config.rootDir),projectName:i.parent.project()?.name??"",line:i.location.line,column:i.location.column,status:v,durationMs:E,retries:m,failureMessages:T,failureStack:w,...N(k)})}await L(this.options,{status:t.status,failOnFlakyTests:this.options.failOnFlakyTests,stats:o,specs:y,logs:p,attachments:c,errors:this.errors,...N(this.missing)},64*1024*1024)}}const z=8,_=/^(?:\w*Error: )?page\.goto: .*Cannot navigate to invalid URL/u,G=/^\s*- navigating to "([^"]*)"/mu,B=/^[A-Za-z][A-Za-z\d+.-]*:/u;function x(e,t){const r=[];let o=e;for(let p=0;p<z&&o!==void 0;p+=1){const c=g(o),f=[...F(c),...t?H(c):[]];f.length>0&&r.push({message:c,values:f}),o=o.cause}return r}function H(e){const t=D(e);if(!_.test(t))return[];const r=G.exec(t)?.[1];return r===void 0||B.test(r)?[]:[{kind:"endpoint",valueName:null}]}function N(e){const t=e.at(0);return t===void 0?{}:{environmentFailure:j(e.flatMap(({values:r})=>r),t.message)}}function d(e){return F(e).length===0?e:V(e)}function Z(e,t){for(let r=e.parent;r;r=r.parent)if(r.type==="file")return h.resolve(t,r.title);return e.location.file}function X(e,t){const r=[];for(let o=e.parent;o&&o.type!=="project"&&o.type!=="root";o=o.parent)r.unshift(o.type==="file"&&o.location?I(t,o.location.file):o.title);return r}function I(e,t){return h.relative(e,t).split(h.sep).join("/")}function g(e){return e.message?.trim()||e.stack?.trim()||e.value?.trim()||"Playwright reported an error"}
@@ -1 +1 @@
1
- import r from"node:fs";import e from"node:path";export const PLAYWRIGHT_CONFIG_FILENAMES=Object.freeze(["playwright.config.ts","playwright.config.mts","playwright.config.js","playwright.config.mjs","playwright.config.cjs","playwright.config.cts"]);export function findPlaywrightConfigFile(t){for(const o of PLAYWRIGHT_CONFIG_FILENAMES){const i=e.join(t,o);try{if(r.statSync(i).isFile())return i}catch(n){if(c(n,"ENOENT"))continue;throw new Error(`Could not inspect optional support module ${i}`,{cause:n})}}return null}function c(t,o){return typeof t=="object"&&t!==null&&Reflect.get(t,"code")===o}
1
+ import f from"node:fs";import i from"node:path";import{hasErrorCode as c}from"../../../kernel/error-serialization.js";export const PLAYWRIGHT_CONFIG_FILENAMES=Object.freeze(["playwright.config.ts","playwright.config.mts","playwright.config.js","playwright.config.mjs","playwright.config.cjs","playwright.config.cts"]);export function findPlaywrightConfigFile(e){for(const o of PLAYWRIGHT_CONFIG_FILENAMES){const r=i.join(e,o);try{if(f.statSync(r).isFile())return r}catch(t){if(c(t,"ENOENT")||c(t,"ENOTDIR"))continue;throw new Error(`Could not inspect optional support module ${r}`,{cause:t})}}return null}export function findNearestPlaywrightConfigFile(e,o){const r=i.resolve(e);let t=i.resolve(r,s(o));const n=i.relative(r,t);for((n.split(i.sep)[0]===".."||i.isAbsolute(n))&&(t=r);;){const l=findPlaywrightConfigFile(t);if(l!==null||t===r)return l;t=i.dirname(t)}}function s(e){if(e.length===0)return".";const[o,...r]=e.map(n=>i.posix.normalize(n).split("/").filter(l=>l!==""&&l!=="."));let t=0;for(;t<o.length&&r.every(n=>n[t]===o[t]);)t+=1;return o.slice(0,t).join("/")||"."}
@@ -1 +1 @@
1
- import{DEFAULT_FILE_TIMEOUT_SECONDS as w,INTERNAL_FILE_TIMEOUT_SECONDS_ENV as b}from"../../../domain/file-timeout.js";import{readPlaywrightContext as E}from"./runtime-input.js";import{defineConfig as T}from"@playwright/test";import{loadDotenvFiles as y}from"../../../config/runtime/env/index.js";export function defineTestkitConfig(e={},n={}){const t=n.env||process.env;y({cwd:n.cwd,env:t,files:n.dotenvFiles||[".env.local"],onlyWhenAllowed:n.onlyWhenAllowed,override:n.override});const o=S(t,n.defaultFileTimeoutSeconds)*1e3,i=E(),c=i?.managed===!0,s=a(e.use,"Playwright config.use"),d=a(e.expect,"Playwright config.expect"),f=U(s.baseURL,"Playwright config.use.baseURL"),u=i?.baseUrl??t.BASE_URL??f,m={...s,...u?{baseURL:u}:{},actionTimeout:o,navigationTimeout:o},g={...e,...c?{globalTimeout:o}:{},timeout:o,expect:{...d,timeout:o},use:m,...c?{webServer:void 0}:{}};return T(g)}function S(e,n){const t=e[b],r=l(n??w);return t==null?r:l(t)}function l(e){const n=Number(e);if(!Number.isInteger(n)||n<=0)throw new Error("Playwright file timeout seconds must be a positive integer.");return n}function a(e,n){if(e==null)return{};if(!h(e))throw new Error(`${n} must be an object`);return e}function h(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function U(e,n){if(e!=null){if(typeof e!="string")throw new Error(`${n} must be a string`);return e}}
1
+ import{DEFAULT_FILE_TIMEOUT_SECONDS as h,INTERNAL_FILE_TIMEOUT_SECONDS_ENV as E}from"../../../domain/file-timeout.js";import{readPlaywrightContext as T}from"./runtime-input.js";import{defineConfig as b}from"@playwright/test";import{isUnknownRecord as p}from"../../../kernel/unknown-values.js";const y=["cwd","dotenvFiles","onlyWhenAllowed","override"];export function defineTestkitConfig(e={},t={}){const n=y.filter(w=>Object.hasOwn(t,w));if(n.length>0)throw new Error(`defineTestkitConfig no longer loads dotenv files, so it does not accept ${n.join(", ")}. In a Testkit run, the services your tests use already provide their values. To load a file when you run Playwright on its own, use a dotenv library of your own in playwright.config.ts.`);const r=t.env||process.env,o=S(r,t.defaultFileTimeoutSeconds)*1e3,i=T(),s=i?.managed===!0,u=l(e.use,"Playwright config.use"),d=l(e.expect,"Playwright config.expect"),f=O(u.baseURL,"Playwright config.use.baseURL"),a=i?.baseUrl??r.BASE_URL??f,m={...u,...a?{baseURL:a}:{},actionTimeout:o,navigationTimeout:o},g={...e,...s?{globalTimeout:o}:{},timeout:o,expect:{...d,timeout:o},use:m,...s?{webServer:void 0}:{}};return b(g)}function S(e,t){const n=e[E],r=c(t??h);return n==null?r:c(n)}function c(e){const t=Number(e);if(!Number.isInteger(t)||t<=0)throw new Error("Playwright file timeout seconds must be a positive integer.");return t}function l(e,t){if(e==null)return{};if(!p(e))throw new Error(`${t} must be an object`);return e}function O(e,t){if(e!=null){if(typeof e!="string")throw new Error(`${t} must be a string`);return e}}
@@ -1,9 +1,9 @@
1
- import l from"node:fs/promises";import c from"node:path";import{writeOwnedRuntimeInput as m,ownedRuntimeInputModuleUrl as f}from"../../runtime-input-file.js";import{requireBoundedJsonValue as y,RUNTIME_INPUT_JSON_BOUNDS as h}from"../../contracts/json-bounds.js";import{ENGINE_PROCESS_RESERVED_ENVIRONMENT_KEYS as g}from"../../../process/environment.js";import{managedProcessEnvironmentOverlayInstallerSource as w}from"../../../process/environment-overlay.js";export const PLAYWRIGHT_RUNTIME_INPUT_MAX_BYTES=4*1024*1024,PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_BYTES=2*1024*1024,PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_ENTRIES=512;const d=new Set(["BASE_URL","FORCE_COLOR","NODE_OPTIONS","NO_COLOR","PLAYWRIGHT_BROWSERS_PATH","PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD","TESTKIT_ACTIVE","TESTKIT_INTERNAL_FILE_DEADLINE_MS","TESTKIT_INTERNAL_FILE_TIMEOUT_SECONDS","TESTKIT_INVOCATION_ID","TESTKIT_RUNTIME_ID","TESTKIT_TEST_FILE","TESTKIT_TEST_ID",...g].map(e=>e.toUpperCase())),p={filename:"runtime-input.json",label:"Playwright runtime input",maxSizeBytes:PLAYWRIGHT_RUNTIME_INPUT_MAX_BYTES},E=Symbol.for("@gfdelarue/testkit/playwright-runtime-input/v1");export function readPlaywrightContext(){const e=Reflect.get(globalThis,E);return T(e)?e.context:null}export async function materializePlaywrightRuntimeInput(e){if(!c.isAbsolute(e.directory))throw new Error("Playwright runtime-input directory must be absolute");await l.mkdir(e.directory,{recursive:!0,mode:448}),process.platform!=="win32"&&await l.chmod(e.directory,448);const t=I(e.inputs.environment),r={baseUrl:v(e.baseUrl),endpoints:e.endpoints,engineId:"playwright",environment:t,fixtures:e.inputs.fixtures,invocationId:e.invocationId,managed:!0,schemaVersion:1,taskId:e.taskId,uiConfig:e.inputs.configuration??{},...e.inputs.setupData===void 0?{}:{setupData:e.inputs.setupData}},o=await m(e.directory,r,p);return{digest:o.sha256,file:o.file,sizeBytes:o.sizeBytes}}export function playwrightRuntimeInputBootstrapSource(e){const t=JSON.stringify({digest:e.digest,file:e.file,ownedInput:{directory:c.dirname(e.file),file:e.file,sha256:e.digest,sizeBytes:e.sizeBytes},protocol:p,invocationId:e.invocationId,jsonBounds:h,maximumEnvironmentBytes:PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_BYTES,maximumEnvironmentEntries:PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_ENTRIES,reservedEnvironmentKeys:[...d],taskId:e.taskId}),n=w(),r=`const requireBoundedJsonValue = (${y.toString()});`;return`
1
+ import l from"node:fs/promises";import c from"node:path";import{writeOwnedRuntimeInput as m,ownedRuntimeInputModuleUrl as f}from"../../runtime-input-file.js";import{requireBoundedJsonValue as y,RUNTIME_INPUT_JSON_BOUNDS as h}from"../../adapters/json-bounds.js";import{ENGINE_PROCESS_RESERVED_ENVIRONMENT_KEYS as w}from"../../../process/environment.js";import{managedProcessEnvironmentOverlayInstallerSource as g}from"../../../process/environment-overlay.js";import{isUnknownRecord as u}from"../../../kernel/unknown-values.js";export const PLAYWRIGHT_RUNTIME_INPUT_MAX_BYTES=4*1024*1024,PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_BYTES=2*1024*1024,PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_ENTRIES=512;const d=new Set(["BASE_URL","FORCE_COLOR","NODE_OPTIONS","NO_COLOR","PLAYWRIGHT_BROWSERS_PATH","PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD","TESTKIT_ACTIVE","TESTKIT_INTERNAL_FILE_DEADLINE_MS","TESTKIT_INTERNAL_FILE_TIMEOUT_SECONDS","TESTKIT_INVOCATION_ID","TESTKIT_RUNTIME_ID","TESTKIT_TEST_FILE","TESTKIT_TEST_ID",...w].map(e=>e.toUpperCase())),p={filename:"runtime-input.json",label:"Playwright runtime input",maxSizeBytes:PLAYWRIGHT_RUNTIME_INPUT_MAX_BYTES},E=Symbol.for("@gfdelarue/testkit/playwright-runtime-input/v1");export function readPlaywrightContext(){const e=Reflect.get(globalThis,E);return T(e)?e.context:null}export async function materializePlaywrightRuntimeInput(e){if(!c.isAbsolute(e.directory))throw new Error("Playwright runtime-input directory must be absolute");await l.mkdir(e.directory,{recursive:!0,mode:448}),process.platform!=="win32"&&await l.chmod(e.directory,448);const t=I(e.inputs.environment),i={baseUrl:e.baseUrl===null?null:v(e.baseUrl),databases:e.databases,endpoints:e.endpoints,engineId:"playwright",environment:t,fixtures:e.inputs.fixtures,handles:e.handles,invocationId:e.invocationId,managed:!0,schemaVersion:1,taskId:e.taskId,uiConfig:e.inputs.configuration??{},...e.inputs.setupData===void 0?{}:{setupData:e.inputs.setupData}},o=await m(e.directory,i,p);return{digest:o.sha256,file:o.file,sizeBytes:o.sizeBytes}}export function playwrightRuntimeInputBootstrapSource(e){const t=JSON.stringify({digest:e.digest,file:e.file,ownedInput:{directory:c.dirname(e.file),file:e.file,sha256:e.digest,sizeBytes:e.sizeBytes},protocol:p,invocationId:e.invocationId,jsonBounds:h,maximumEnvironmentBytes:PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_BYTES,maximumEnvironmentEntries:PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_ENTRIES,reservedEnvironmentKeys:[...d],taskId:e.taskId}),n=g(),i=`const requireBoundedJsonValue = (${y.toString()});`;return`
2
2
  import path from "node:path";
3
3
  import { readVerifiedOwnedFile } from ${JSON.stringify(f)};
4
4
 
5
5
  ${n}
6
- ${r}
6
+ ${i}
7
7
  const OPTIONS = ${t};
8
8
  const STATE = Symbol.for("@gfdelarue/testkit/playwright-runtime-input/v1");
9
9
 
@@ -31,9 +31,11 @@ export async function installPlaywrightRuntimeInput() {
31
31
  });
32
32
  const context = Object.freeze({
33
33
  baseUrl: input.baseUrl,
34
+ databases: input.databases,
34
35
  endpoints: input.endpoints,
35
36
  env: input.environment,
36
37
  fixtures: input.fixtures,
38
+ handles: input.handles,
37
39
  managed: true,
38
40
  ...(input.setupData === undefined ? {} : { setupData: input.setupData }),
39
41
  uiConfig: input.uiConfig,
@@ -68,11 +70,11 @@ function deepFreezeJson(root) {
68
70
 
69
71
  function validateRuntimeInput(value) {
70
72
  const input = requireRecord(value, "Playwright runtime input");
71
- const allowed = new Set(["baseUrl", "endpoints", "engineId", "environment", "fixtures", "invocationId", "managed", "schemaVersion", "setupData", "taskId", "uiConfig"]);
73
+ const allowed = new Set(["baseUrl", "databases", "endpoints", "engineId", "environment", "fixtures", "handles", "invocationId", "managed", "schemaVersion", "setupData", "taskId", "uiConfig"]);
72
74
  for (const key of Object.keys(input)) {
73
75
  if (!allowed.has(key)) throw new Error("Playwright runtime input contains unsupported field " + key);
74
76
  }
75
- for (const key of ["baseUrl", "endpoints", "engineId", "environment", "fixtures", "invocationId", "managed", "schemaVersion", "taskId", "uiConfig"]) {
77
+ for (const key of ["baseUrl", "databases", "endpoints", "engineId", "environment", "fixtures", "handles", "invocationId", "managed", "schemaVersion", "taskId", "uiConfig"]) {
76
78
  if (!Object.prototype.hasOwnProperty.call(input, key))
77
79
  throw new Error("Playwright runtime input is missing field " + key);
78
80
  }
@@ -80,29 +82,32 @@ function validateRuntimeInput(value) {
80
82
  throw new Error("Playwright runtime input has an unsupported identity");
81
83
  if (input.managed !== true)
82
84
  throw new Error("Playwright runtime input must be managed by Testkit");
83
- if (typeof input.baseUrl !== "string" || input.baseUrl.trim().length === 0)
84
- throw new Error("Playwright runtime input.baseUrl must be a non-empty string");
85
- let parsedBaseUrl;
86
- try {
87
- parsedBaseUrl = new URL(input.baseUrl);
88
- } catch (error) {
89
- throw new Error("Playwright runtime input.baseUrl must be a valid URL", { cause: error });
90
- }
91
- if ((parsedBaseUrl.protocol !== "http:" && parsedBaseUrl.protocol !== "https:") || parsedBaseUrl.href !== input.baseUrl)
92
- throw new Error("Playwright runtime input.baseUrl must be a canonical HTTP(S) URL");
85
+ if (input.baseUrl !== null) validateBaseUrl(input.baseUrl);
93
86
  if (input.invocationId !== OPTIONS.invocationId || input.taskId !== OPTIONS.taskId)
94
87
  throw new Error("Playwright runtime input does not match its invocation and task");
95
- requireStringRecord(input.endpoints, "Playwright runtime input.endpoints");
88
+ requireNamedValues(input.databases, "Playwright runtime input.databases");
89
+ requireNamedValues(input.endpoints, "Playwright runtime input.endpoints");
90
+ requireHandles(input.handles, "Playwright runtime input.handles");
96
91
  validateEnvironment(input.environment);
97
92
  requireRecord(input.fixtures, "Playwright runtime input.fixtures");
98
93
  requireRecord(input.uiConfig, "Playwright runtime input.uiConfig");
99
- requireBoundedJsonValue(input, "Playwright runtime input", OPTIONS.jsonBounds, {
100
- unitLabel: "bytes",
101
- unitsOf: (text) => Buffer.byteLength(text, "utf8"),
102
- });
94
+ requireBoundedJsonValue(input, "Playwright runtime input", OPTIONS.jsonBounds);
103
95
  return input;
104
96
  }
105
97
 
98
+ function validateBaseUrl(value) {
99
+ if (typeof value !== "string" || value.trim().length === 0)
100
+ throw new Error("Playwright runtime input.baseUrl must be null or a non-empty string");
101
+ let parsed;
102
+ try {
103
+ parsed = new URL(value);
104
+ } catch (error) {
105
+ throw new Error("Playwright runtime input.baseUrl must be a valid URL", { cause: error });
106
+ }
107
+ if ((parsed.protocol !== "http:" && parsed.protocol !== "https:") || parsed.href !== value)
108
+ throw new Error("Playwright runtime input.baseUrl must be a canonical HTTP(S) URL");
109
+ }
110
+
106
111
  function validateEnvironment(value) {
107
112
  const environment = requireStringRecord(value, "Playwright runtime input.environment");
108
113
  const keys = Object.keys(environment);
@@ -132,6 +137,24 @@ function validateEnvironmentEntry(key, value) {
132
137
  throw new Error("Playwright runtime input.environment contains an invalid value for " + key);
133
138
  }
134
139
 
140
+ function requireNamedValues(value, label) {
141
+ const record = requireRecord(value, label);
142
+ for (const [key, entry] of Object.entries(record)) {
143
+ if (key.length === 0 || typeof entry !== "string" || entry.length === 0 || entry.includes("\\0"))
144
+ throw new Error(label + " must map names to non-empty strings");
145
+ }
146
+ return record;
147
+ }
148
+
149
+ function requireHandles(value, label) {
150
+ const record = requireRecord(value, label);
151
+ for (const [name, descriptor] of Object.entries(record)) {
152
+ if (name.length === 0 || typeof descriptor !== "object" || descriptor === null || Array.isArray(descriptor) || typeof descriptor.kind !== "string" || descriptor.kind.length === 0)
153
+ throw new Error(label + " must map names to handle descriptors with a kind");
154
+ }
155
+ return record;
156
+ }
157
+
135
158
  function requireStringRecord(value, label) {
136
159
  const record = requireRecord(value, label);
137
160
  for (const [key, entry] of Object.entries(record)) {
@@ -148,4 +171,4 @@ function requireRecord(value, label) {
148
171
  }
149
172
 
150
173
  await installPlaywrightRuntimeInput();
151
- `}function T(e){return!u(e)||!u(e.context)||!u(e.input)?!1:typeof e.digest=="string"&&typeof e.file=="string"&&e.input.engineId==="playwright"&&e.input.schemaVersion===1&&Object.isFrozen(e)&&Object.isFrozen(e.context)&&Object.isFrozen(e.input)}function u(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function I(e){const t=Object.create(null),n=new Set;let r=0;const o=Object.entries(e);if(o.length>PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_ENTRIES)throw new Error(`Playwright consumer environment exceeds its ${PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_ENTRIES.toString()} entry limit`);for(const[s,a]of o){O(s,a);const i=s.toUpperCase();if(n.has(i))throw new Error(`Playwright consumer environment contains case-insensitive duplicate key ${s}`);if(n.add(i),i.startsWith("TESTKIT_")||i.startsWith("PLAYWRIGHT_")||i.startsWith("PWTEST_")||i.startsWith("PW_TEST_")||d.has(i))throw new Error(`Playwright consumer environment contains reserved key ${s}`);if(r+=Buffer.byteLength(s,"utf8")+Buffer.byteLength(a,"utf8")+2,r>PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_BYTES)throw new Error(`Playwright consumer environment exceeds its ${PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_BYTES.toString()} byte limit`);t[s]=a}return t}function v(e){if(typeof e!="string"||e.trim().length===0)throw new Error("Playwright runtime input base URL must be non-empty");let t;try{t=new URL(e)}catch(n){throw new Error("Playwright runtime input base URL must be a valid URL",{cause:n})}if(t.protocol!=="http:"&&t.protocol!=="https:")throw new Error("Playwright runtime input base URL must use HTTP or HTTPS");return t.href}function O(e,t){if(e.length===0||e.includes("=")||e.includes("\0")||typeof t!="string")throw new Error("Playwright consumer environment contains an invalid key");if(t.includes("\0"))throw new Error(`Playwright consumer environment contains an invalid value for ${e}`)}
174
+ `}function T(e){return!u(e)||!u(e.context)||!u(e.input)?!1:typeof e.digest=="string"&&typeof e.file=="string"&&e.input.engineId==="playwright"&&e.input.schemaVersion===1&&Object.isFrozen(e)&&Object.isFrozen(e.context)&&Object.isFrozen(e.input)}function I(e){const t=Object.create(null),n=new Set;let i=0;const o=Object.entries(e);if(o.length>PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_ENTRIES)throw new Error(`Playwright consumer environment exceeds its ${PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_ENTRIES.toString()} entry limit`);for(const[a,s]of o){b(a,s);const r=a.toUpperCase();if(n.has(r))throw new Error(`Playwright consumer environment contains case-insensitive duplicate key ${a}`);if(n.add(r),r.startsWith("TESTKIT_")||r.startsWith("PLAYWRIGHT_")||r.startsWith("PWTEST_")||r.startsWith("PW_TEST_")||d.has(r))throw new Error(`Playwright consumer environment contains reserved key ${a}`);if(i+=Buffer.byteLength(a,"utf8")+Buffer.byteLength(s,"utf8")+2,i>PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_BYTES)throw new Error(`Playwright consumer environment exceeds its ${PLAYWRIGHT_RUNTIME_ENVIRONMENT_MAX_BYTES.toString()} byte limit`);t[a]=s}return t}function v(e){if(typeof e!="string"||e.trim().length===0)throw new Error("Playwright runtime input base URL must be non-empty");let t;try{t=new URL(e)}catch(n){throw new Error("Playwright runtime input base URL must be a valid URL",{cause:n})}if(t.protocol!=="http:"&&t.protocol!=="https:")throw new Error("Playwright runtime input base URL must use HTTP or HTTPS");return t.href}function b(e,t){if(e.length===0||e.includes("=")||e.includes("\0")||typeof t!="string")throw new Error("Playwright consumer environment contains an invalid key");if(t.includes("\0"))throw new Error(`Playwright consumer environment contains an invalid value for ${e}`)}
@@ -1 +1 @@
1
- import u from"node:crypto";import a from"node:fs/promises";import o from"node:path";import{serializeBoundedJson as c,RUNTIME_INPUT_JSON_BOUNDS as h}from"./contracts/json-bounds.js";import{readStableEvidenceFile as y,evidenceFileAccess as b}from"./adapters/evidence-files.js";export const ownedRuntimeInputModuleUrl=new URL("../../dist/engines/runtime-input-file.js",import.meta.url).href,RUNTIME_INPUT_BYTE_MEASURE={unitLabel:"bytes",unitsOf:t=>Buffer.byteLength(t,"utf8")};export async function writeOwnedRuntimeInput(t,e,i){const r=c(e,i.label,h,RUNTIME_INPUT_BYTE_MEASURE),s=await m(t,i.label),w=Buffer.byteLength(r);if(w>i.maxSizeBytes)throw new Error(`${i.label} exceeds the ${i.maxSizeBytes.toString()} byte limit`);const f=o.join(s,i.filename),l=o.join(s,`.${i.filename}.${process.pid.toString()}.${u.randomUUID()}.tmp`);let n=null;try{n=await a.open(l,"wx",384),await n.writeFile(r,"utf8"),await n.close(),n=null,await a.rename(l,f),await a.chmod(f,384)}catch(d){throw await n?.close().catch(()=>{}),await a.rm(l,{force:!0}).catch(()=>{}),d}return{directory:s,file:f,sha256:u.createHash("sha256").update(r,"utf8").digest("hex"),sizeBytes:w}}export async function readVerifiedOwnedFile(t,e){const i=await m(t.directory,e.label);if(o.dirname(t.file)!==i)throw new Error(`${e.label} escaped its owned task directory`);const r=await a.lstat(t.file,{bigint:!0});if(!r.isFile()||r.isSymbolicLink())throw new Error(`${e.label} must be an owned regular file`);if(r.size!==BigInt(t.sizeBytes)||r.size>BigInt(e.maxSizeBytes))throw new Error(`${e.label} size changed after preparation`);if(process.platform!=="win32"&&(r.mode&63n)!==0n)throw new Error(`${e.label} permissions must be owner-only`);const s=await a.realpath(t.file);if(s!==t.file||o.dirname(s)!==i)throw new Error(`${e.label} resolved outside its owned task directory`);const{contents:w,sha256:f}=await y(s,e.maxSizeBytes,e.label,b,r),l=Buffer.from(t.sha256),n=Buffer.from(f);if(l.length!==n.length||!u.timingSafeEqual(n,l))throw new Error(`${e.label} integrity check failed`);return w.toString("utf8")}async function m(t,e){if(!o.isAbsolute(t))throw new Error(`${e} directory must be absolute`);const i=await a.realpath(t);if(!(await a.stat(i)).isDirectory())throw new Error(`${e} directory must be a directory`);return i}
1
+ import m from"node:crypto";import a from"node:fs/promises";import f from"node:path";import{serializeBoundedJson as c,RUNTIME_INPUT_JSON_BOUNDS as h}from"./adapters/json-bounds.js";import{readStableEvidenceFile as y,evidenceFileAccess as b}from"./adapters/evidence-files.js";export const ownedRuntimeInputModuleUrl=new URL("../../dist/engines/runtime-input-file.js",import.meta.url).href;export async function writeOwnedRuntimeInput(i,e,t){const r=c(e,t.label,h),s=await d(i,t.label),w=Buffer.byteLength(r);if(w>t.maxSizeBytes)throw new Error(`${t.label} exceeds the ${t.maxSizeBytes.toString()} byte limit`);const o=f.join(s,t.filename),l=f.join(s,`.${t.filename}.${process.pid.toString()}.${m.randomUUID()}.tmp`);let n=null;try{n=await a.open(l,"wx",384),await n.writeFile(r,"utf8"),await n.close(),n=null,await a.rename(l,o),await a.chmod(o,384)}catch(u){throw await n?.close().catch(()=>{}),await a.rm(l,{force:!0}).catch(()=>{}),u}return{directory:s,file:o,sha256:m.createHash("sha256").update(r,"utf8").digest("hex"),sizeBytes:w}}export async function readVerifiedOwnedFile(i,e){const t=await d(i.directory,e.label);if(f.dirname(i.file)!==t)throw new Error(`${e.label} escaped its owned task directory`);const r=await a.lstat(i.file,{bigint:!0});if(!r.isFile()||r.isSymbolicLink())throw new Error(`${e.label} must be an owned regular file`);if(r.size!==BigInt(i.sizeBytes)||r.size>BigInt(e.maxSizeBytes))throw new Error(`${e.label} size changed after preparation`);if(process.platform!=="win32"&&(r.mode&63n)!==0n)throw new Error(`${e.label} permissions must be owner-only`);const s=await a.realpath(i.file);if(s!==i.file||f.dirname(s)!==t)throw new Error(`${e.label} resolved outside its owned task directory`);const{contents:w,sha256:o}=await y(s,e.maxSizeBytes,e.label,b,r),l=Buffer.from(i.sha256),n=Buffer.from(o);if(l.length!==n.length||!m.timingSafeEqual(n,l))throw new Error(`${e.label} integrity check failed`);return w.toString("utf8")}async function d(i,e){if(!f.isAbsolute(i))throw new Error(`${e} directory must be absolute`);const t=await a.realpath(i);if(!(await a.stat(t)).isDirectory())throw new Error(`${e} directory must be a directory`);return t}
@@ -1 +1 @@
1
- import o from"fs";import a from"path";import{finalizeLiveRunArtifact as i}from"../evidence/index.js";export function reconcileInactiveRunArtifact(t,n){typeof n.runId=="string"&&i(t,{runId:n.runId,reason:"stale run process not active",status:"interrupted"})}export function reconcileOrphanedLiveRunArtifact(t,{activeRunIds:n=new Set}={}){const r=c(t),e=r?.run.id||null;return!e||r?.run.status!=="running"||n.has(e)?!1:i(t,{runId:e,reason:"stale live artifact has no active run manifest",status:"interrupted"})}function c(t){try{const n=JSON.parse(o.readFileSync(a.join(t,".testkit","results","live.json"),"utf8"));return f(n)}catch{return null}}function f(t){if(!u(t)||!u(t.run))return null;const n=t.run.id,r=t.run.status;return!s(n)||!s(r)?null:{run:{id:n,status:r}}}function u(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function s(t){return t===void 0||typeof t=="string"}
1
+ import o from"fs";import a from"path";import{finalizeLiveRunArtifact as e}from"../evidence/index.js";import{isUnknownRecord as u}from"../kernel/unknown-values.js";export function reconcileInactiveRunArtifact(n,t){typeof t.runId=="string"&&e(n,{runId:t.runId,reason:"stale run process not active",status:"interrupted"})}export function reconcileOrphanedLiveRunArtifact(n,{activeRunIds:t=new Set}={}){const r=f(n),i=r?.run.id||null;return!i||r?.run.status!=="running"||t.has(i)?!1:e(n,{runId:i,reason:"stale live artifact has no active run manifest",status:"interrupted"})}function f(n){try{const t=JSON.parse(o.readFileSync(a.join(n,".testkit","results","live.json"),"utf8"));return c(t)}catch{return null}}function c(n){if(!u(n)||!u(n.run))return null;const t=n.run.id,r=n.run.status;return!s(t)||!s(r)?null:{run:{id:t,status:r}}}function s(n){return n===void 0||typeof n=="string"}
@@ -1 +1 @@
1
- import H from"crypto";import{isTerminalRunStatus as x}from"../process/runs/schema.js";import{observeProcessCreationIdentity as U}from"../process/process-identity.js";import{isRunManifestActive as B}from"../process/runs/inspection.js";export{isRunManifestActive}from"../process/runs/inspection.js";import{normalizeOperationReason as _}from"../domain/operation-reason.js";import{finalizeLiveRunArtifact as Y}from"../evidence/index.js";import{captureProcessCreationIdentity as J}from"../process/service-processes.js";import{requireProductLifecycleFenceProductDir as K,withProductLifecycleFence as Q}from"../process/lifecycle-fence.js";import{createRunManifest as X,listRunManifests as $,readRunMaintenanceStopRequest as Z,removeRunManifestFile as G,requireSafeRunId as ee,RUN_MANIFEST_SCHEMA_VERSION as te,runManifestPath as ne,writeRunManifest as re}from"../process/runs/manifest.js";const ie=1e3,oe=String,T=new WeakMap;export function createUnpublishedRunLifecycle(n,r={}){const i=r.runId===void 0?ce():ee(r.runId,"Testkit run id"),a=ne(n,i),s=new AbortController,m=new AbortController,u=r.pid===void 0?process.pid:r.pid;if(!Number.isSafeInteger(u)||u<0)throw new Error("Testkit run pid must be a non-negative safe integer");const b=u>0?J(u):null;if(u>0&&b===null)throw new Error(`Could not capture the Testkit run process identity for pid ${u.toString()}`);let f={incarnationId:H.randomUUID(),schemaVersion:te,runId:i,pid:u,processIdentity:typeof b=="string"?b:null,controller:ae(r.controller),status:"starting",startedAt:new Date().toISOString(),heartbeatAt:r.heartbeat===!1?null:new Date().toISOString(),interruptReason:null,services:[],runtimeDirs:[]};const O=[];let w,D=null;const y=new Set,S=new Set,L=r.keepAlive===!0?setInterval(()=>{},ie):null;let R=null,g=null,v=null,P=!1;function j(e){const t=T.get(I);if(!t)throw new Error("Testkit run lifecycle ownership is unavailable");if(!t.published){X(n,e),t.published=!0;return}re(n,e)}function A(){const e=Z(n,i);return e===null||e.targetIncarnationId!==f.incarnationId||e.targetPid!==u||e.targetProcessIdentity!==f.processIdentity||e.coordinatorPid===D?.coordinatorPid&&e.coordinatorProcessIdentity===D.coordinatorProcessIdentity?null:U(e.coordinatorPid,e.coordinatorProcessIdentity)==="different"?(D=e,null):e}function h(e){k("mutate run state");const t=se(f);e(t),t.heartbeatAt!==null&&(t.heartbeatAt=new Date().toISOString()),j(t),f=t}function k(e){if(g!==null)throw new Error(`Cannot ${e} after Testkit run ${i} finalization is committed`)}function W(){R||(R=setInterval(()=>{},1e3))}function q(){R&&(clearInterval(R),R=null)}function N(){for(const e of S)clearInterval(e);S.clear()}function z(e="controller process exited before Testkit run finalized"){if(P||x(f.status))return!1;const t=_(e,"controller process exited before Testkit run finalized"),o=new Date,l=f.status==="interrupting"||s.signal.aborted?"interrupted":"failed",c=l==="interrupted"?f.interruptReason??v??t:t;return h(p=>{p.status=l,p.finishedAt=o.toISOString(),p.interruptReason=c,p.heartbeatAt!==null&&(p.heartbeatAt=o.toISOString())}),Y(n,{runId:i,reason:c,status:l,finishedAt:o}),!0}const F=()=>{z()};process.on("exit",F);const I={runId:i,manifestPath:a,maintenanceStopSignal:m.signal,signal:s.signal,commitFinalization(e="finished"){if(g!==null)return g;const t=A(),o=s.signal.aborted||t!==null||f.status==="interrupting",l=o?f.interruptReason??v??t?.reason??"run interrupted":null,c=Object.freeze({interruptReason:l,interrupted:o});return h(p=>{p.status=o?"interrupted":e,p.finishedAt=new Date().toISOString(),p.interruptReason=l}),g=c,N(),c},getInterruptReason(){return f.interruptReason??v},isMaintenanceStopCoordinated(){return A()!==null},isStopRequested(){return s.signal.aborted||g?.interrupted===!0},markRunning(){h(e=>{e.status="running"})},markFinished(e="finished"){h(t=>{t.status=e,t.finishedAt=new Date().toISOString()})},heartbeat(e={}){h(t=>{t.heartbeatAt=new Date().toISOString(),e&&typeof e=="object"&&!Array.isArray(e)&&(t.session={...t.session||{},...e})})},startHeartbeat(e=5e3,t=null){k("start a run heartbeat");const o=Number.isFinite(Number(e))&&Number(e)>0?Math.floor(Number(e)):5e3,l=setInterval(()=>{let c;try{c=typeof t=="function"?t():{}}catch{c={}}I.heartbeat(c)},o);return l.unref(),S.add(l),()=>{clearInterval(l),S.delete(l)}},requestStop(e="interrupted"){if(g!==null||x(f.status))return;const t=A(),o=t?t.reason:_(e,"interrupted"),l=!s.signal.aborted;l&&(v=o),W();let c=null;if(l)try{h(d=>{d.status="interrupting",d.interruptReason=o})}catch(d){c=d instanceof Error?d:new Error("Failed to persist the Testkit stop request",{cause:d})}t!==null&&!m.signal.aborted&&m.abort(new Error(`Testkit run ${i} is being stopped by external maintenance`));const p=[...y].map(({supervisor:d})=>d.stop(t===null?void 0:Date.parse(t.requestedAt)+d.shutdownTimeoutMs));if(Promise.allSettled(p).then(q),s.signal.aborted||s.abort(new Error(`testkit run interrupted (${o})`)),!!l&&c!==null)throw c},trackGraphContext(e){h(t=>{le(t.runtimeDirs,e.runtimeDir)})},registerService(e,t,o,l){if(k("register application service ownership"),o.pid!==t.pid||(process.platform==="win32"?o.recovery.processGroupId!==null:o.recovery.processGroupId!==o.pid))throw new Error("Application service supervisor returned an invalid ownership handoff");const c={supervisor:t,unsubscribe:()=>{}};y.add(c);const p=ue(e);h(d=>{d.services=d.services.filter(M=>M.pid!==o.pid),d.services.push({serviceName:e.name,runtimeLabel:e.runtimeLabel,command:e.testkit.local.start||null,cwd:l,pid:o.pid,processGroupId:o.recovery.processGroupId,processIdentity:o.recovery.creationIdentity,ports:p,startedAt:new Date().toISOString(),shutdownTimeoutMs:t.shutdownTimeoutMs,shutdownDeadlineAt:t.shutdownDeadlineAt})}),c.unsubscribe=t.onShutdownStarted(d=>{h(M=>{const E=M.services.find(V=>V.pid===o.pid);E&&(E.shutdownDeadlineAt=E.shutdownDeadlineAt==null?d:Math.min(E.shutdownDeadlineAt,d))})})},unregisterService(e){k("unregister application service ownership");for(const t of y)t.supervisor.pid===e&&(t.unsubscribe(),y.delete(t));h(t=>{t.services=t.services.filter(o=>o.pid!==e)})},installSignalHandlers(){if(!(O.length>0)&&!(u!==process.pid||U(u,f.processIdentity)!=="matches")){for(const e of["SIGINT","SIGTERM","SIGHUP"]){const t=I.requestStop.bind(I,e);process.on(e,t),O.push([e,t])}process.platform==="win32"&&(w=setInterval(()=>{const e=A();e!==null&&(clearInterval(w),I.requestStop(e.reason))},100),w.unref(),S.add(w))}},removeSignalHandlers(){w&&(clearInterval(w),S.delete(w),w=void 0);for(const[e,t]of O.splice(0))process.off(e,t)},async removeManifest(){await Q(n,e=>cleanupOwnedRunLifecycleWithinLifecycleFence(e,I))},finalizeForControllerExit:z,dispose(){P=!0;for(const e of y)e.unsubscribe();process.off("exit",F),I.removeSignalHandlers(),L&&clearInterval(L),q(),N()}};return T.set(I,{incarnationId:f.incarnationId,pid:u,processIdentity:f.processIdentity,productDir:n,published:!1,runId:i}),I}function se(n){const r={...n,controller:n.controller===null?null:{...n.controller},runtimeDirs:[...n.runtimeDirs],services:n.services.map(i=>({...i,ports:i.ports.map(a=>({...a}))}))};return n.session!==void 0&&(r.session=n.session===null?null:{...n.session}),r}function ae(n){return!n||typeof n!="object"||Array.isArray(n)?null:Object.fromEntries(Object.entries(n).filter(([,r])=>r!==void 0).map(([r,i])=>[r,i===null?null:oe(i)]))}export function cleanupOwnedRunLifecycleWithinLifecycleFence(n,r){const{manifest:i,ownership:a,productDir:s}=readOwnedRunLifecycleWithinLifecycleFence(n,r);if(!i)return!1;if(i.services.length>0)throw new Error(`Cannot clean Testkit run ${r.runId} service ownership while holding the lifecycle fence`);return G(s,r.runId),a.published=!1,!0}export function readOwnedRunLifecycleWithinLifecycleFence(n,r){const i=K(n),a=T.get(r);if(!a||a.productDir!==i)throw new Error("Cannot clean a Testkit run without matching lifecycle ownership");if(a.runId!==r.runId)throw new Error("Testkit run lifecycle identity has been modified");const s=$(i).find(m=>m.runId===r.runId);if(s!==void 0&&(s.incarnationId!==a.incarnationId||s.pid!==a.pid||s.processIdentity!==a.processIdentity))throw new Error(`Testkit run ${r.runId} ownership no longer matches its manifest`);return{manifest:s??null,ownership:a,productDir:i}}export function findPortOwner(n,{host:r,port:i}){const a=$(n);for(const s of a)for(const m of s.services)for(const u of m.ports)if(C(u.host)===C(r)&&u.port===Number(i))return{manifest:s,service:m,active:B(s)};return null}function ue(n){const r=new Set,i=[];for(const a of[n.testkit.local.baseUrl,n.testkit.local.readyUrl])if(a)try{const s=new URL(a),m=C(s.hostname),u=Number(s.port||(s.protocol==="https:"?443:80)),b=`${m}:${u.toString()}`;if(r.has(b))continue;r.add(b),i.push({host:m,port:u})}catch{}return i}function le(n,r){r&&(n.includes(r)||n.push(r))}function ce(){return`${Date.now().toString()}-${process.pid.toString()}-${H.randomBytes(4).toString("hex")}`}function C(n){return n?n==="::1"?"127.0.0.1":n:"127.0.0.1"}export function disposeFailedRunLifecycle(n){const r=T.get(n);n.dispose(),n.removeSignalHandlers(),r?.published===!0&&G(r.productDir,n.runId)}
1
+ import H from"crypto";import{isTerminalRunStatus as N}from"../process/runs/schema.js";import{observeProcessCreationIdentity as x}from"../process/process-identity.js";export{isRunManifestActive}from"../process/runs/inspection.js";import{normalizeOperationReason as U}from"../domain/operation-reason.js";import{finalizeLiveRunArtifact as W}from"../evidence/index.js";import{captureProcessCreationIdentity as V}from"../process/service-processes.js";import{requireProductLifecycleFenceProductDir as K,withProductLifecycleFence as B}from"../process/lifecycle-fence.js";import{createRunManifest as Y,listRunManifests as J,readRunMaintenanceStopRequest as Q,removeRunManifestFile as _,requireSafeRunId as X,RUN_MANIFEST_SCHEMA_VERSION as Z,runManifestPath as ee,writeRunManifest as te}from"../process/runs/manifest.js";const ne=1e3,re=String,k=new WeakMap;export function createUnpublishedRunLifecycle(n,r={}){const s=r.runId===void 0?ue():X(r.runId,"Testkit run id"),u=ee(n,s),o=new AbortController,I=new AbortController,d=r.pid===void 0?process.pid:r.pid;if(!Number.isSafeInteger(d)||d<0)throw new Error("Testkit run pid must be a non-negative safe integer");const S=d>0?V(d):null;if(d>0&&S===null)throw new Error(`Could not capture the Testkit run process identity for pid ${d.toString()}`);let f={incarnationId:H.randomUUID(),schemaVersion:Z,runId:s,pid:d,processIdentity:typeof S=="string"?S:null,controller:se(r.controller),status:"starting",startedAt:new Date().toISOString(),heartbeatAt:r.heartbeat===!1?null:new Date().toISOString(),interruptReason:null,services:[],runtimeDirs:[]};const D=[];let w,O=null;const y=new Set,b=new Set,M=r.keepAlive===!0?setInterval(()=>{},ne):null;let R=null,g=null,v=null,L=!1;function $(e){const t=k.get(h);if(!t)throw new Error("Testkit run lifecycle ownership is unavailable");if(!t.published){Y(n,e),t.published=!0;return}te(n,e)}function A(){const e=Q(n,s);return e===null||e.targetIncarnationId!==f.incarnationId||e.targetPid!==d||e.targetProcessIdentity!==f.processIdentity||e.coordinatorPid===O?.coordinatorPid&&e.coordinatorProcessIdentity===O.coordinatorProcessIdentity?null:x(e.coordinatorPid,e.coordinatorProcessIdentity)==="different"?(O=e,null):e}function m(e){T("mutate run state");const t=ie(f);e(t),t.heartbeatAt!==null&&(t.heartbeatAt=new Date().toISOString()),$(t),f=t}function T(e){if(g!==null)throw new Error(`Cannot ${e} after Testkit run ${s} finalization is committed`)}function G(){R||(R=setInterval(()=>{},1e3))}function P(){R&&(clearInterval(R),R=null)}function q(){for(const e of b)clearInterval(e);b.clear()}function z(e="controller process exited before Testkit run finalized"){if(L||N(f.status))return!1;const t=U(e,"controller process exited before Testkit run finalized"),i=new Date,a=f.status==="interrupting"||o.signal.aborted?"interrupted":"failed",l=a==="interrupted"?f.interruptReason??v??t:t;return m(p=>{p.status=a,p.finishedAt=i.toISOString(),p.interruptReason=l,p.heartbeatAt!==null&&(p.heartbeatAt=i.toISOString())}),W(n,{runId:s,reason:l,redactKeys:r.redactKeys,redactionTargets:r.redactionTargets?.(),status:a,finishedAt:i}),!0}const F=()=>{z()};process.on("exit",F);const h={runId:s,manifestPath:u,maintenanceStopSignal:I.signal,signal:o.signal,commitFinalization(e="finished"){if(g!==null)return g;const t=A(),i=o.signal.aborted||t!==null||f.status==="interrupting",a=i?f.interruptReason??v??t?.reason??"run interrupted":null,l=Object.freeze({interruptReason:a,interrupted:i});return m(p=>{p.status=i?"interrupted":e,p.finishedAt=new Date().toISOString(),p.interruptReason=a}),g=l,q(),l},getInterruptReason(){return f.interruptReason??v},isMaintenanceStopCoordinated(){return A()!==null},isStopRequested(){return o.signal.aborted||g?.interrupted===!0},markRunning(){m(e=>{e.status="running"})},markFinished(e="finished"){m(t=>{t.status=e,t.finishedAt=new Date().toISOString()})},heartbeat(e={}){m(t=>{t.heartbeatAt=new Date().toISOString(),e&&typeof e=="object"&&!Array.isArray(e)&&(t.session={...t.session||{},...e})})},startHeartbeat(e=5e3,t=null){T("start a run heartbeat");const i=Number.isFinite(Number(e))&&Number(e)>0?Math.floor(Number(e)):5e3,a=setInterval(()=>{let l;try{l=typeof t=="function"?t():{}}catch{l={}}h.heartbeat(l)},i);return a.unref(),b.add(a),()=>{clearInterval(a),b.delete(a)}},requestStop(e="interrupted"){if(g!==null||N(f.status))return;const t=A(),i=t?t.reason:U(e,"interrupted"),a=!o.signal.aborted;a&&(v=i),G();let l=null;if(a)try{m(c=>{c.status="interrupting",c.interruptReason=i})}catch(c){l=c instanceof Error?c:new Error("Failed to persist the Testkit stop request",{cause:c})}t!==null&&!I.signal.aborted&&I.abort(new Error(`Testkit run ${s} is being stopped by external maintenance`));const p=[...y].map(({supervisor:c})=>c.stop(t===null?void 0:Date.parse(t.requestedAt)+c.shutdownTimeoutMs));if(Promise.allSettled(p).then(P),o.signal.aborted||o.abort(new Error(`testkit run interrupted (${i})`)),!!a&&l!==null)throw l},trackGraphContext(e){m(t=>{ae(t.runtimeDirs,e.runtimeDir)})},registerService(e,t,i,a){if(T("register application service ownership"),i.pid!==t.pid||(process.platform==="win32"?i.recovery.processGroupId!==null:i.recovery.processGroupId!==i.pid))throw new Error("Application service supervisor returned an invalid ownership handoff");const l={supervisor:t,unsubscribe:()=>{}};y.add(l);const p=oe(e);m(c=>{c.services=c.services.filter(C=>C.pid!==i.pid),c.services.push({serviceName:e.name,runtimeLabel:e.runtimeLabel,command:e.testkit.local.start||null,cwd:a,pid:i.pid,processGroupId:i.recovery.processGroupId,processIdentity:i.recovery.creationIdentity,ports:p,startedAt:new Date().toISOString(),shutdownTimeoutMs:t.shutdownTimeoutMs,shutdownDeadlineAt:t.shutdownDeadlineAt})}),l.unsubscribe=t.onShutdownStarted(c=>{m(C=>{const E=C.services.find(j=>j.pid===i.pid);E&&(E.shutdownDeadlineAt=E.shutdownDeadlineAt==null?c:Math.min(E.shutdownDeadlineAt,c))})})},unregisterService(e){T("unregister application service ownership");for(const t of y)t.supervisor.pid===e&&(t.unsubscribe(),y.delete(t));m(t=>{t.services=t.services.filter(i=>i.pid!==e)})},installSignalHandlers(){if(!(D.length>0)&&!(d!==process.pid||x(d,f.processIdentity)!=="matches")){for(const e of["SIGINT","SIGTERM","SIGHUP"]){const t=h.requestStop.bind(h,e);process.on(e,t),D.push([e,t])}process.platform==="win32"&&(w=setInterval(()=>{const e=A();e!==null&&(clearInterval(w),h.requestStop(e.reason))},100),w.unref(),b.add(w))}},removeSignalHandlers(){w&&(clearInterval(w),b.delete(w),w=void 0);for(const[e,t]of D.splice(0))process.off(e,t)},async removeManifest(){await B(n,e=>cleanupOwnedRunLifecycleWithinLifecycleFence(e,h))},finalizeForControllerExit:z,dispose(){L=!0;for(const e of y)e.unsubscribe();process.off("exit",F),h.removeSignalHandlers(),M&&clearInterval(M),P(),q()}};return k.set(h,{incarnationId:f.incarnationId,pid:d,processIdentity:f.processIdentity,productDir:n,published:!1,runId:s}),h}function ie(n){const r={...n,controller:n.controller===null?null:{...n.controller},runtimeDirs:[...n.runtimeDirs],services:n.services.map(s=>({...s,ports:s.ports.map(u=>({...u}))}))};return n.session!==void 0&&(r.session=n.session===null?null:{...n.session}),r}function se(n){return!n||typeof n!="object"||Array.isArray(n)?null:Object.fromEntries(Object.entries(n).filter(([,r])=>r!==void 0).map(([r,s])=>[r,s===null?null:re(s)]))}export function cleanupOwnedRunLifecycleWithinLifecycleFence(n,r){const{manifest:s,ownership:u,productDir:o}=readOwnedRunLifecycleWithinLifecycleFence(n,r);if(!s)return!1;if(s.services.length>0)throw new Error(`Cannot clean Testkit run ${r.runId} service ownership while holding the lifecycle fence`);return _(o,r.runId),u.published=!1,!0}export function readOwnedRunLifecycleWithinLifecycleFence(n,r){const s=K(n),u=k.get(r);if(!u||u.productDir!==s)throw new Error("Cannot clean a Testkit run without matching lifecycle ownership");if(u.runId!==r.runId)throw new Error("Testkit run lifecycle identity has been modified");const o=J(s).find(I=>I.runId===r.runId);if(o!==void 0&&(o.incarnationId!==u.incarnationId||o.pid!==u.pid||o.processIdentity!==u.processIdentity))throw new Error(`Testkit run ${r.runId} ownership no longer matches its manifest`);return{manifest:o??null,ownership:u,productDir:s}}function oe(n){const r=new Set,s=[];for(const u of[n.testkit.local.baseUrl,n.testkit.local.readyUrl])if(u)try{const o=new URL(u),I=le(o.hostname),d=Number(o.port||(o.protocol==="https:"?443:80)),S=`${I}:${d.toString()}`;if(r.has(S))continue;r.add(S),s.push({host:I,port:d})}catch{}return s}function ae(n,r){r&&(n.includes(r)||n.push(r))}function ue(){return`${Date.now().toString()}-${process.pid.toString()}-${H.randomBytes(4).toString("hex")}`}function le(n){return n?n==="::1"?"127.0.0.1":n:"127.0.0.1"}export function disposeFailedRunLifecycle(n){const r=k.get(n);n.dispose(),n.removeSignalHandlers(),r?.published===!0&&_(r.productDir,n.runId)}
@@ -1 +1 @@
1
- import{formatRunSummary as w}from"../process/runs/manifest.js";import{cleanupOrphanedLocalInfrastructure as R,cleanupTerminalRunLocalInfrastructure as m}from"../database/lifecycle-cleanup.js";import{resetResultArtifacts as v}from"../evidence/index.js";import{requireProductLifecycleFenceProductDir as d,withProductLifecycleFence as l}from"../process/lifecycle-fence.js";import{listRunManifests as u,removeRunManifestFile as y,requireSafeRunId as I}from"../process/runs/manifest.js";import{stopRunManifest as A}from"./run-stopping.js";import{createUnpublishedRunLifecycle as L,disposeFailedRunLifecycle as k,isRunManifestActive as a,cleanupOwnedRunLifecycleWithinLifecycleFence as S,readOwnedRunLifecycleWithinLifecycleFence as p}from"./lifecycle-controller.js";import{reconcileInactiveRunArtifact as g,reconcileOrphanedLiveRunArtifact as x}from"./lifecycle-artifacts.js";class f extends Error{constructor(n){super(`Stale Testkit run ${n} still owns application services and requires phased cleanup`),this.name="StaleRunServiceCleanupRequiredError"}}export async function startRunLifecycle(e,n={}){for(;;){await cleanupStaleRuns(e);try{return await l(e,t=>startRunLifecycleWithinLifecycleFence(t,n))}catch(t){if(!(t instanceof f))throw t}}}export async function startRunLifecycleWithinLifecycleFence(e,n={}){const t=d(e);h(t),await cleanupStaleRunsWithinLifecycleFence(e);const c=u(t).find(i=>!a(i)&&i.services.length>0);if(c!==void 0)throw new f(c.runId);h(t);const r=L(t,n);try{return r.installSignalHandlers(),n.resetResultsBeforePublish===!0&&v(t),r.markRunning(),r}catch(i){throw k(r),i}}function h(e){const n=u(e).find(a);if(n)throw new Error(`Active Testkit run ${w(n)} already owns this product`)}export async function cleanupRuns(e,{includeActive:n=!1}={}){const t=[],c=[];for(;;){const i=await l(e,()=>u(e).flatMap(s=>{const o=a(s);return n&&o||!o&&s.services.length>0?[{active:o,manifest:s}]:[]}));if(i.length===0)break;for(const s of i)await A(e,s.manifest,{reason:s.active?"cleanup":"stale run process not active"}),s.active?t.push(s.manifest):c.push(s.manifest)}const r=await l(e,i=>cleanupRunsWithinLifecycleFence(i));return{...r,cleaned:[...t,...c,...r.cleaned],stoppedActive:t}}export async function cleanupRunsWithinLifecycleFence(e,{protectedLiveRunIds:n=new Set}={}){const t=d(e),c=u(t),r={cleaned:[],skippedActive:[],stoppedActive:[]};for(const i of c){if(a(i)||i.services.length>0){r.skippedActive.push(i);continue}g(t,i),y(t,O(i)),r.cleaned.push(i)}return x(t,{activeRunIds:new Set([...r.skippedActive.map(i=>i.runId).filter(i=>typeof i=="string"),...n])}),r.resourceCleanup=await R(t),{cleaned:r.cleaned,resourceCleanup:r.resourceCleanup,skippedActive:r.skippedActive,stoppedActive:r.stoppedActive}}export async function cleanupStaleRuns(e){const n=[];for(;;){const t=await cleanupRuns(e);if(n.push(...t.cleaned),!t.skippedActive.some(r=>!a(r)&&r.services.length>0))return n}}export async function cleanupStaleRunsWithinLifecycleFence(e){return(await cleanupRunsWithinLifecycleFence(e)).cleaned}export async function cleanupOwnedRunLifecycleResourcesWithinLifecycleFence(e,n){const t=p(e,n);if(t.manifest===null)throw new Error(`Cannot clean terminal Testkit run ${n.runId} resources without its owned manifest`);if(t.manifest.services.length>0)throw new Error(`Cannot clean terminal Testkit run ${n.runId} resources while service ownership remains published`);const c=C(t.manifest);await m(e,c);const r=p(e,n);if(r.manifest===null||!F(r.manifest,c))throw new Error(`Cannot remove terminal Testkit run ${n.runId} because its manifest changed during resource cleanup`);return S(e,n)}function C(e){if(e.status!=="failed"&&e.status!=="finished"&&e.status!=="interrupted")throw new Error(`Cannot clean Testkit run ${e.runId} database resources before terminal finalization`);if(typeof e.finishedAt!="string"||e.finishedAt.length===0)throw new Error(`Cannot clean terminal Testkit run ${e.runId} database resources without a completion time`);return{finishedAt:e.finishedAt,incarnationId:e.incarnationId,pid:e.pid,processIdentity:e.processIdentity,runId:e.runId,status:e.status}}function F(e,n){return e.runId===n.runId&&e.incarnationId===n.incarnationId&&e.pid===n.pid&&e.processIdentity===n.processIdentity&&e.finishedAt===n.finishedAt&&e.status===n.status&&e.services.length===0}function O(e){return I(e.runId,"Testkit run manifest runId")}export{listRunManifests,RunManifestInventoryError}from"../process/runs/manifest.js";export{stopRunById,stopRunManifest}from"./run-stopping.js";export{cleanupOwnedRunLifecycleWithinLifecycleFence,findPortOwner,isRunManifestActive}from"./lifecycle-controller.js";export{isPidRunning}from"../process/runs/stop.js";export{formatRunSummary}from"../process/runs/manifest.js";
1
+ import{formatRunSummary as w}from"../process/runs/manifest.js";import{cleanupOrphanedLocalInfrastructure as m,cleanupTerminalRunLocalInfrastructure as R}from"../database/lifecycle-cleanup.js";import{resetResultArtifacts as y}from"../evidence/index.js";import{requireProductLifecycleFenceProductDir as p,withProductLifecycleFence as l}from"../process/lifecycle-fence.js";import{listRunManifests as u,removeRunManifestFile as I,requireSafeRunId as A}from"../process/runs/manifest.js";import{stopRunManifest as L}from"./run-stopping.js";import{createUnpublishedRunLifecycle as k,disposeFailedRunLifecycle as g,isRunManifestActive as o,cleanupOwnedRunLifecycleWithinLifecycleFence as S,readOwnedRunLifecycleWithinLifecycleFence as f}from"./lifecycle-controller.js";import{reconcileInactiveRunArtifact as x,reconcileOrphanedLiveRunArtifact as C}from"./lifecycle-artifacts.js";class h extends Error{constructor(n){super(`Stale Testkit run ${n} still owns application services and requires phased cleanup`),this.name="StaleRunServiceCleanupRequiredError"}}export async function startRunLifecycle(e,n={},s={}){for(;;){await cleanupStaleRuns(e,s);try{return await l(e,t=>startRunLifecycleWithinLifecycleFence(t,n,s))}catch(t){if(!(t instanceof h))throw t}}}export async function startRunLifecycleWithinLifecycleFence(e,n={},s={}){const t=p(e);v(t),await cleanupRunsWithinLifecycleFence(e,s);const c=u(t).find(i=>!o(i)&&i.services.length>0);if(c!==void 0)throw new h(c.runId);v(t);const r=k(t,n);try{return r.installSignalHandlers(),n.resetResultsBeforePublish===!0&&y(t),r.markRunning(),r}catch(i){throw g(r),i}}function v(e){const n=u(e).find(o);if(n)throw new Error(`Active Testkit run ${w(n)} already owns this product`)}export async function cleanupRuns(e,{includeActive:n=!1,localInfrastructure:s}={}){const t=[],c=[];for(;;){const i=await l(e,()=>u(e).flatMap(a=>{const d=o(a);return n&&d||!d&&a.services.length>0?[{active:d,manifest:a}]:[]}));if(i.length===0)break;for(const a of i)await L(e,a.manifest,{reason:a.active?"cleanup":"stale run process not active"}),a.active?t.push(a.manifest):c.push(a.manifest)}const r=await l(e,i=>cleanupRunsWithinLifecycleFence(i,{localInfrastructure:s}));return{...r,cleaned:[...t,...c,...r.cleaned],stoppedActive:t}}export async function cleanupRunsWithinLifecycleFence(e,{protectedLiveRunIds:n=new Set,localInfrastructure:s=!0}={}){const t=p(e),c=u(t),r={cleaned:[],skippedActive:[],stoppedActive:[]};for(const i of c){if(o(i)||i.services.length>0){r.skippedActive.push(i);continue}x(t,i),I(t,A(i.runId,"Testkit run manifest runId")),r.cleaned.push(i)}return C(t,{activeRunIds:new Set([...r.skippedActive.map(i=>i.runId).filter(i=>typeof i=="string"),...n])}),r.resourceCleanup=s?await m(t):{kept:[],removed:[],skipped:[],stopped:[],targets:[]},{cleaned:r.cleaned,resourceCleanup:r.resourceCleanup,skippedActive:r.skippedActive,stoppedActive:r.stoppedActive}}export async function cleanupStaleRuns(e,n={}){const s=[];for(;;){const t=await cleanupRuns(e,n);if(s.push(...t.cleaned),!t.skippedActive.some(r=>!o(r)&&r.services.length>0))return s}}export async function cleanupOwnedRunLifecycleResourcesWithinLifecycleFence(e,n,{localInfrastructure:s=!0}={}){const t=f(e,n);if(t.manifest===null)throw new Error(`Cannot clean terminal Testkit run ${n.runId} resources without its owned manifest`);if(t.manifest.services.length>0)throw new Error(`Cannot clean terminal Testkit run ${n.runId} resources while service ownership remains published`);const c=b(t.manifest);s&&await R(e,c);const r=f(e,n);if(r.manifest===null||!E(r.manifest,c))throw new Error(`Cannot remove terminal Testkit run ${n.runId} because its manifest changed during resource cleanup`);return S(e,n)}function b(e){if(e.status!=="failed"&&e.status!=="finished"&&e.status!=="interrupted")throw new Error(`Cannot clean Testkit run ${e.runId} database resources before terminal finalization`);if(typeof e.finishedAt!="string"||e.finishedAt.length===0)throw new Error(`Cannot clean terminal Testkit run ${e.runId} database resources without a completion time`);return{finishedAt:e.finishedAt,incarnationId:e.incarnationId,pid:e.pid,processIdentity:e.processIdentity,runId:e.runId,status:e.status}}function E(e,n){return e.runId===n.runId&&e.incarnationId===n.incarnationId&&e.pid===n.pid&&e.processIdentity===n.processIdentity&&e.finishedAt===n.finishedAt&&e.status===n.status&&e.services.length===0}export{listRunManifests,RunManifestInventoryError}from"../process/runs/manifest.js";export{stopRunById,stopRunManifest}from"./run-stopping.js";export{cleanupOwnedRunLifecycleWithinLifecycleFence,isRunManifestActive}from"./lifecycle-controller.js";export{isPidRunning}from"../process/runs/stop.js";export{formatRunSummary}from"../process/runs/manifest.js";
@@ -0,0 +1 @@
1
+ import l from"node:net";export const SERVICE_START_ATTEMPTS=3;const f=32,p=new Set(["EADDRNOTAVAIL","EAFNOSUPPORT","EPROTONOSUPPORT"]);export async function reservePort(){for(let e=0;e<f;e+=1){const r=await c("127.0.0.1",0),t=await i(r);if(t)return t}throw new Error("The OS assigned no TCP port that is free on both IPv4 and IPv6 loopback")}export async function reserveExactPort(e){let r;try{r=await c("127.0.0.1",e)}catch(t){if(s(t)==="EADDRINUSE"||s(t)==="EACCES")return null;throw t}return i(r)}export async function reservePorts(e){const r=new Map;try{for(const t of e)r.set(t,await reservePort())}catch(t){throw await releasePorts(r.values()),t}return r}export async function releasePorts(e){await Promise.all([...e].map(r=>r.release()))}export function portsOf(e){return new Map([...e].map(([r,t])=>[r,t.port]))}async function i(e){const r=P(e);let t=null;try{t=await c("::1",r)}catch(a){if(!p.has(s(a)??"")){if(await u(e),s(a)==="EADDRINUSE")return null;throw a}}const n=t?[e,t]:[e];let o=null;return{port:r,release(){return o??=Promise.all(n.map(u)).then(()=>{}),o}}}function c(e,r){const t=l.createServer(n=>{n.destroy()});return t.unref(),new Promise((n,o)=>{t.once("error",o),t.listen({host:e,port:r,exclusive:!0,...e==="::1"?{ipv6Only:!0}:{}},()=>{t.off("error",o),n(t)})})}function u(e){return new Promise(r=>{e.close(()=>{r()})})}function P(e){const r=e.address();if(r===null||typeof r=="string")throw new Error("The OS did not assign a TCP port");return r.port}function s(e){const r=typeof e=="object"&&e!==null?Reflect.get(e,"code"):void 0;return typeof r=="string"?r:void 0}
@@ -1 +1 @@
1
- import i from"node:path";import{readDatabaseInfo as m}from"../database/state.js";import{runtimeEngineDirectory as s}from"./runtime-contexts.js";export function createReadyEnvironment(t,a){const r=new Map(t.runtimeConfigs.map(e=>[e.name,m(e.stateDir)]));return{...a,engineCacheDirectory:i.join(s(t),"cache"),engineWorkspaceDirectory:i.join(s(t),"leases",a.leaseId),graphKey:t.graphKey,runtimeId:t.runtimeId,targetNames:[...t.targetNames],services:new Map(t.runtimeConfigs.map(e=>{const n={...e.testkit.templateContext};return delete n.databaseBindingsReader,[e.name,{baseUrl:e.testkit.local?.baseUrl||null,database:r.get(e.name)??null,config:{...e,testkit:{...e.testkit,templateContext:{...n,databaseBindingsByService:r}}}}]}))}}
1
+ export function createReadyEnvironment(e,r){return{leaseId:r,graphKey:e.graphKey,runtimeId:e.runtimeId,targetNames:[...e.targetNames],services:new Map(e.runtimeConfigs.map(a=>[a.name,{baseUrl:a.testkit.local?.baseUrl||null,database:e.databaseBindings.get(a.name)??null,config:a}]))}}
@@ -1 +1 @@
1
- import{cleanupOwnedRunLifecycleResourcesWithinLifecycleFence as R,cleanupRunsWithinLifecycleFence as v,listRunManifests as F,startRunLifecycle as q}from"./lifecycle.js";import{createRuntimeManager as I}from"./runtime-manager.js";import{resolveCommittedRunFinalization as S}from"../evidence/finalization.js";import{withProductLifecycleFence as b}from"../process/lifecycle-fence.js";export function createLocalRunEnvironment(s){return{async start(d){const n=await q(s,d),c=n.startHeartbeat(2e3,()=>({kind:"controller",status:n.isStopRequested()?"interrupting":"running"}));let i=null;const p=new Map,l=()=>{if(i===null)throw new Error("Run runtimes have not been provisioned");return i};let m=null;return{runId:n.runId,signal:n.signal,isStopRequested:()=>n.isStopRequested(),getInterruptReason:()=>n.getInterruptReason(),requestStop:e=>{n.requestStop(e)},beginFinalization:c,dispose(){c(),n.removeSignalHandlers(),n.dispose()},get committedFinalization(){return m},provision(e,t){if(i!==null)throw new Error("Run runtimes are already provisioned");i=I({productDir:s,graphs:e,lifecycle:n,runtimeOptions:t})},async acquire(e,t){const r=await l().acquire(e,t);p.set(r.leaseId,r);const{engineCacheDirectory:o,engineWorkspaceDirectory:u,leaseId:a,leaseDir:h,runtimeId:g,graphKey:f,targetNames:w,services:y}=r;return{engineCacheDirectory:o,engineWorkspaceDirectory:u,leaseId:a,leaseDir:h,runtimeId:g,graphKey:f,targetNames:w,services:y}},canAcquire:e=>l().canAcquire(e),async release(e,t){const r=p.get(e);r!==void 0&&(await l().release(r,t),p.delete(e))},async cleanupAll(){await i?.cleanupAll()},getStats:()=>i?.getStats()??[],getGraph(e){const t=i?.getGraph(e);return t?{key:t.key,targetNames:[...t.targetNames]}:null},getGraphFailure:e=>i?.getGraphFailure(e)??null,markGraphFailed:(e,t)=>{l().markGraphFailed(e,t)},async finish(e,t,r){return c(),b(s,async o=>{const u=F(s).find(a=>a.runId===n.runId);if(u!==void 0&&u.services.length>0)throw new Error(r==="normal"?"Cannot commit a run while application service ownership remains published":"Cannot publish terminal failure while application service ownership remains published");m??=S(e,n.commitFinalization(e==="failed"?"failed":"finished"));try{await v(o,{protectedLiveRunIds:new Set([n.runId])}),await R(o,n)}catch(a){if(r==="normal")throw a}return t(m)})}}}}}
1
+ import{cleanupOwnedRunLifecycleResourcesWithinLifecycleFence as w,cleanupRunsWithinLifecycleFence as y,listRunManifests as R,startRunLifecycle as v}from"./lifecycle.js";import{createRuntimeManager as F}from"./runtime-manager.js";import{resolveCommittedRunFinalization as I}from"../evidence/finalization.js";import{withProductLifecycleFence as q}from"../process/lifecycle-fence.js";export function createLocalRunEnvironment(s){return{async start(f){const c={localInfrastructure:f.localInfrastructure!==!1},n=await v(s,f,c),p=n.startHeartbeat(2e3,()=>({kind:"controller",status:n.isStopRequested()?"interrupting":"running"}));let a=null;const m=new Map,l=()=>{if(a===null)throw new Error("Run runtimes have not been provisioned");return a};let d=null;return{runId:n.runId,signal:n.signal,isStopRequested:()=>n.isStopRequested(),getInterruptReason:()=>n.getInterruptReason(),requestStop:e=>{n.requestStop(e)},beginFinalization:p,dispose(){p(),n.removeSignalHandlers(),n.dispose()},get committedFinalization(){return d},provision(e,t){if(a!==null)throw new Error("Run runtimes are already provisioned");a=F({productDir:s,graphs:e,lifecycle:n,runtimeOptions:t})},async acquire(e,t){const r=await l().acquire(e,t);m.set(r.leaseId,r);const{leaseId:o,runtimeId:u,graphKey:i,targetNames:h,services:g}=r;return{leaseId:o,runtimeId:u,graphKey:i,targetNames:h,services:g}},canAcquire:e=>l().canAcquire(e),async release(e,t){const r=m.get(e);r!==void 0&&(await l().release(r,t),m.delete(e))},async cleanupAll(){await a?.cleanupAll()},getStats:()=>a?.getStats()??[],getGraph(e){const t=a?.getGraph(e);return t?{key:t.key,targetNames:[...t.targetNames]}:null},getGraphFailure:e=>a?.getGraphFailure(e)??null,markGraphFailed:(e,t)=>{l().markGraphFailed(e,t)},async finish(e,t,r){return p(),q(s,async o=>{const u=R(s).find(i=>i.runId===n.runId);if(u!==void 0&&u.services.length>0)throw new Error(r==="normal"?"Cannot commit a run while application service ownership remains published":"Cannot publish terminal failure while application service ownership remains published");d??=I(e,n.commitFinalization(e==="failed"?"failed":"finished"));try{await y(o,{...c,protectedLiveRunIds:new Set([n.runId])}),await w(o,n,c)}catch(i){if(r==="normal")throw i}return t(d)})}}}}}
@@ -1 +1 @@
1
- import{waitForPreparedRunStop as g,drainRunServices as M,requestProcessStop as _,runManifestServiceKey as F,sameRunManifestIncarnation as P}from"../process/runs/stop.js";import{observeProcessCreationIdentity as h,captureProcessCreationIdentity as N}from"../process/index.js";import{normalizeOperationReason as S}from"../domain/operation-reason.js";import{RUN_MAINTENANCE_STOP_REQUEST_SCHEMA_VERSION as L}from"../process/runs/schema.js";import{finalizeLiveRunArtifact as v}from"../evidence/index.js";import{requireProductLifecycleFenceProductDir as q,withProductLifecycleFence as m}from"../process/lifecycle-fence.js";import{listRunManifests as E,readRunMaintenanceStopRequest as T,removeRunMaintenanceStopRequest as y,removeRunManifestFile as O,requireSafeRunId as k,writeRunMaintenanceStopRequest as $,prepareRunShutdownDeadlines as D,persistRunShutdownDeadlines as z}from"../process/runs/manifest.js";export async function stopRunById(r,t,i={}){const n=k(t,"Testkit run id"),e=await m(r,o=>A(o,n,i));if(e===null)return!1;const s=await g(e);return await C(r,e,s),!0}export async function stopRunManifest(r,t,i={}){const n=W(t),e=await m(r,o=>A(o,n,i,t));if(e===null)return{runId:n,pid:t.pid,reason:S(i.reason,"stopped"),stopped:!0};const s=await g(e);return C(r,e,s)}function A(r,t,i={},n=null){const e=q(r);let s=S(i.reason,"stopped");const o=E(e).find(a=>a.runId===t);if(o===void 0){if(n!==null&&n.pid>0&&n.processIdentity===null&&h(n.pid,n.processIdentity)==="unknown")throw new Error(`Cannot establish the creation identity of Testkit run process ${n.pid.toString()}; refusing unsafe stop`);return n!==null&&n.pid===0&&(v(e,{runId:t,reason:s,status:"interrupted"}),y(e,t)),null}if(n!==null&&!P(o,n))throw new Error(`Testkit run ${t} ownership changed before the stop request could be published`);const u=o.pid,f=u>0?h(u,o.processIdentity):"different";if(u===process.pid&&f==="matches")throw new Error(`Cannot stop active Testkit run ${t} from inside its own controller process`);if(f==="unknown")throw new Error(`Cannot establish the creation identity of Testkit run process ${u.toString()}; refusing unsafe stop`);let d=null,p=new Date().toISOString(),l=null;const I=T(e,t),c=I!==null&&I.targetIncarnationId===o.incarnationId&&I.targetPid===u&&I.targetProcessIdentity===o.processIdentity?I:null;c!==null&&(s=c.reason,p=c.requestedAt);let R=null;const w=()=>{if(R!==null)return R;const a=D(o,p);return f==="different"&&z(e,a),R=a,a};if(f==="matches"){if(l=o.processIdentity,l===null)throw new Error(`Testkit run process ${u.toString()} has no creation identity; refusing unsafe stop`);if(c!==null&&h(c.coordinatorPid,c.coordinatorProcessIdentity)!=="different")return d=c.coordinatorProcessIdentity,{controllerActive:!0,coordinatorProcessIdentity:d,graceMs:i.graceMs||2e3,manifest:w(),requestedAt:p,pid:u,productDir:e,reason:s,runId:t,targetProcessIdentity:l};if(d=N(process.pid),d===null)throw new Error("Could not capture the maintenance coordinator process identity");$(e,{coordinatorPid:process.pid,coordinatorProcessIdentity:d,reason:s,requestedAt:p,runId:t,schemaVersion:L,targetIncarnationId:o.incarnationId,targetPid:u,targetProcessIdentity:l}),w();try{process.platform!=="win32"&&_(u,l,"SIGINT")}catch(a){throw y(e,t),a}}return{controllerActive:f==="matches",coordinatorProcessIdentity:d,graceMs:i.graceMs||2e3,manifest:w(),requestedAt:p,pid:u,productDir:e,reason:s,runId:t,targetProcessIdentity:l}}async function C(r,t,i){for(;;){const n=await m(r,e=>U(e,t,i));if(n.result!==null)return n.result;await M(n.services,i)}}function U(r,t,i){const n=q(r),e=E(n).find(o=>o.runId===t.runId);if(e===void 0||!P(e,t.manifest))return V(n,t),{result:b(t),services:null};const s=e.services.filter(o=>!i.has(F(o)));return s.length>0?{result:null,services:s}:(v(n,{runId:t.runId,reason:t.reason,status:"interrupted"}),O(n,t.runId),{result:b(t),services:null})}function b(r){return{runId:r.runId,pid:r.pid,stopped:!0,reason:r.reason}}function V(r,t){const i=T(r,t.runId);i===null||i.coordinatorPid!==process.pid||i.coordinatorProcessIdentity!==t.coordinatorProcessIdentity||i.targetIncarnationId!==t.manifest.incarnationId||i.targetPid!==t.pid||i.targetProcessIdentity!==t.targetProcessIdentity||y(r,t.runId)}function W(r){return k(r.runId,"Testkit run manifest runId")}
1
+ import{waitForPreparedRunStop as g,drainRunServices as M,requestProcessStop as _,runManifestServiceKey as F,sameRunManifestIncarnation as P}from"../process/runs/stop.js";import{observeProcessCreationIdentity as h,captureProcessCreationIdentity as N}from"../process/index.js";import{normalizeOperationReason as S}from"../domain/operation-reason.js";import{RUN_MAINTENANCE_STOP_REQUEST_SCHEMA_VERSION as L}from"../process/runs/schema.js";import{finalizeLiveRunArtifact as v}from"../evidence/index.js";import{requireProductLifecycleFenceProductDir as q,withProductLifecycleFence as m}from"../process/lifecycle-fence.js";import{listRunManifests as E,readRunMaintenanceStopRequest as T,removeRunMaintenanceStopRequest as y,removeRunManifestFile as O,requireSafeRunId as k,writeRunMaintenanceStopRequest as $,prepareRunShutdownDeadlines as D,persistRunShutdownDeadlines as z}from"../process/runs/manifest.js";export async function stopRunById(i,t,r={}){const n=k(t,"Testkit run id"),e=await m(i,o=>A(o,n,r));if(e===null)return!1;const s=await g(e);return await C(i,e,s),!0}export async function stopRunManifest(i,t,r={}){const n=k(t.runId,"Testkit run manifest runId"),e=await m(i,o=>A(o,n,r,t));if(e===null)return{runId:n,pid:t.pid,reason:S(r.reason,"stopped"),stopped:!0};const s=await g(e);return C(i,e,s)}function A(i,t,r={},n=null){const e=q(i);let s=S(r.reason,"stopped");const o=E(e).find(a=>a.runId===t);if(o===void 0){if(n!==null&&n.pid>0&&n.processIdentity===null&&h(n.pid,n.processIdentity)==="unknown")throw new Error(`Cannot establish the creation identity of Testkit run process ${n.pid.toString()}; refusing unsafe stop`);return n!==null&&n.pid===0&&(v(e,{runId:t,reason:s,status:"interrupted"}),y(e,t)),null}if(n!==null&&!P(o,n))throw new Error(`Testkit run ${t} ownership changed before the stop request could be published`);const u=o.pid,f=u>0?h(u,o.processIdentity):"different";if(u===process.pid&&f==="matches")throw new Error(`Cannot stop active Testkit run ${t} from inside its own controller process`);if(f==="unknown")throw new Error(`Cannot establish the creation identity of Testkit run process ${u.toString()}; refusing unsafe stop`);let l=null,p=new Date().toISOString(),d=null;const I=T(e,t),c=I!==null&&I.targetIncarnationId===o.incarnationId&&I.targetPid===u&&I.targetProcessIdentity===o.processIdentity?I:null;c!==null&&(s=c.reason,p=c.requestedAt);let w=null;const R=()=>{if(w!==null)return w;const a=D(o,p);return f==="different"&&z(e,a),w=a,a};if(f==="matches"){if(d=o.processIdentity,d===null)throw new Error(`Testkit run process ${u.toString()} has no creation identity; refusing unsafe stop`);if(c!==null&&h(c.coordinatorPid,c.coordinatorProcessIdentity)!=="different")return l=c.coordinatorProcessIdentity,{controllerActive:!0,coordinatorProcessIdentity:l,graceMs:r.graceMs||2e3,manifest:R(),requestedAt:p,pid:u,productDir:e,reason:s,runId:t,targetProcessIdentity:d};if(l=N(process.pid),l===null)throw new Error("Could not capture the maintenance coordinator process identity");$(e,{coordinatorPid:process.pid,coordinatorProcessIdentity:l,reason:s,requestedAt:p,runId:t,schemaVersion:L,targetIncarnationId:o.incarnationId,targetPid:u,targetProcessIdentity:d}),R();try{process.platform!=="win32"&&_(u,d,"SIGINT")}catch(a){throw y(e,t),a}}return{controllerActive:f==="matches",coordinatorProcessIdentity:l,graceMs:r.graceMs||2e3,manifest:R(),requestedAt:p,pid:u,productDir:e,reason:s,runId:t,targetProcessIdentity:d}}async function C(i,t,r){for(;;){const n=await m(i,e=>U(e,t,r));if(n.result!==null)return n.result;await M(n.services,r)}}function U(i,t,r){const n=q(i),e=E(n).find(o=>o.runId===t.runId);if(e===void 0||!P(e,t.manifest))return V(n,t),{result:b(t),services:null};const s=e.services.filter(o=>!r.has(F(o)));return s.length>0?{result:null,services:s}:(v(n,{runId:t.runId,reason:t.reason,status:"interrupted"}),O(n,t.runId),{result:b(t),services:null})}function b(i){return{runId:i.runId,pid:i.pid,stopped:!0,reason:i.reason}}function V(i,t){const r=T(i,t.runId);r===null||r.coordinatorPid!==process.pid||r.coordinatorProcessIdentity!==t.coordinatorProcessIdentity||r.targetIncarnationId!==t.manifest.incarnationId||r.targetPid!==t.pid||r.targetProcessIdentity!==t.targetProcessIdentity||y(i,t.runId)}
@@ -1 +1 @@
1
- import o from"fs";import n from"path";import{prepareRuntimeServices as m}from"./runtime-preparation.js";import{writeGraphMetadata as p}from"./state.js";import{startLocalServices as u,stopLocalServices as f}from"./services.js";import{resolveRuntimeInstanceConfigs as c}from"./template.js";export function runtimeEngineDirectory(r){return n.join(r.graphDir,"node_modules","testkit-engine",r.runtimeId)}export function createRuntimeInstanceContext(r,e,i){const a=n.join(i,".testkit","_graphs",e.dirName),t=n.join(a,"runtimes",r);o.mkdirSync(t,{recursive:!0}),p(a,e);const s=c(e.runtimeConfigs,r,t,{graphDirName:e.dirName,portNamespaceIndex:e.portNamespaceIndex,portNamespaceStride:e.portNamespaceStride});return{graphKey:e.key,targetNames:[...e.targetNames],graphDir:a,runtimeDir:t,runtimeId:r,runtimeConfigs:s,prepared:!1,preparationPromise:null,started:!1,startupPromise:null,startedServices:[]}}export async function ensureRuntimeInstanceReady(r,e,i,a={}){return r.prepared||(r.preparationPromise||(r.preparationPromise=(async()=>{await prepareDatabases(r.runtimeConfigs,{...a,signal:i.signal}),await m(r.runtimeConfigs,{...a,signal:i.signal}),r.prepared=!0})().finally(()=>{r.preparationPromise=null})),await r.preparationPromise),e&&!r.started&&(r.startupPromise||(r.startupPromise=(async()=>{r.startedServices=await u(r.runtimeConfigs,i,a),r.started=!0})().finally(()=>{r.startupPromise=null})),await r.startupPromise),r}async function d(r,e){r?.started&&(await f(r.startedServices,e),r.started=!1,r.startedServices=[])}export async function cleanupRuntimeInstanceContext(r,e){if(!r)return;await d(r,e);const i=runtimeEngineDirectory(r);o.rmSync(n.join(i,"cache"),{recursive:!0,force:!0});for(const a of[n.join(i,"leases"),i])try{o.rmdirSync(a)}catch(t){const s=t.code;if(s!=="ENOENT"&&s!=="ENOTEMPTY"&&s!=="EEXIST")throw t}}export async function prepareDatabases(r,e={}){if(!r.some(a=>a.testkit.database))return;const{provisionDatabase:i}=await import("../database/index.js");for(const a of r)await i(a,{progress:{reporter:e.reporter,setupRegistry:e.setupRegistry},signal:e.signal,skipSchemaSourceVerify:e.skipSchemaSourceVerify})}
1
+ import P from"fs";import p from"path";import{bindDatabaseUrl as S,lendDatabases as m}from"../database/bindings.js";import{prepareRuntimeServices as l}from"./runtime-preparation.js";import{writeGraphMetadata as D}from"./state.js";import{startLocalServices as C,stopLocalServices as T}from"./services.js";import{resolveRuntimeInstanceConfigs as k}from"./template.js";import{withEnvFileValues as E}from"../config/loader/env.js";import{portsOf as M,releasePorts as u,reserveExactPort as U,reservePort as I,reservePorts as j}from"./ports.js";import{buildExecutionEnv as B,buildTemplateContext as K,buildTemplateExecutionEnv as c,finalizeString as O,withDatabaseBindings as A}from"../steps/index.js";import{sourceSchemaCredentialEnvNames as N}from"../database/source-schema-env.js";import{envRedactionTargets as $,jsonRedactionTargets as F,sensitiveKeyMatcher as g,urlRedactionTargets as L}from"../kernel/redaction-targets.js";const v=/\{[a-zA-Z]+(?::[^}]+)?\}/u;export function createRuntimeInstanceContext(r,e,t){const a=p.join(t,".testkit","_graphs",e.dirName),s=p.join(a,"runtimes",r);return P.mkdirSync(s,{recursive:!0}),D(a,e),{databaseBindings:new Map,graphKey:e.key,targetNames:[...e.targetNames],graphDir:a,graphDirName:e.dirName,runtimeDir:s,runtimeId:r,sourceConfigs:e.runtimeConfigs.map(E),ports:null,portReservations:new Map,triedPortReservations:[],triedPorts:new Map,runtimeConfigs:[],ready:!1,readyPromise:null,startedServices:[]}}export async function ensureRuntimeInstanceReady(r,e,t={}){return r.ready||(r.readyPromise??=V(r,e,t).finally(()=>{r.readyPromise=null}),await r.readyPromise),r}async function V(r,e,t){const a={...t,signal:e.signal},s=await _(r);z(r,t.environmentRecord),r.databaseBindings=await prepareDatabases(r.runtimeConfigs,a),f(r,s),y(r,t.environmentRecord),await l(r.runtimeConfigs,a),r.startedServices=await C(G(r,a),e,t),r.ready=!0}function z(r,e){if(!e)return;const t=g(e.redactKeys);for(const a of r.runtimeConfigs){const s=c(a,{},null);for(const i of[...w(a,s,null,t),...R(a,t)])v.test(i)||e.addRedactionTarget(i)}}function y(r,e){if(!e)return;const t=g(e.redactKeys);for(const a of r.runtimeConfigs){const s=B(a,{},null),i=r.databaseBindings.get(a.name)?.url??null;for(const n of w(a,s,i,t))e.addRedactionTarget(n);for(const n of R(a,t))v.test(n)||e.addRedactionTarget(n)}}function R(r,e){return F("ui",d(r.testkit.ui??{},K(r,null)),e)}function d(r,e){if(typeof r=="string")try{return O(r,e)}catch{return r}return Array.isArray(r)?r.map(t=>d(t,e)):r!==null&&typeof r=="object"?Object.fromEntries(Object.entries(r).map(([t,a])=>[t,d(a,e)])):r}function w(r,e,t,a){const s=r.testkit.local,i=[s?.baseUrl,typeof s?.readyUrl=="string"?s.readyUrl:null,t,...N(r).map(n=>e[n]??process.env[n])];return[...$(e,a),...i.flatMap(n=>n?L(n):[])]}async function _(r){if(r.ports)return r.ports;const e=r.sourceConfigs.filter(s=>s.testkit.local).map(s=>s.name),t=await j(e),a=M(t);try{f(r,a)}catch(s){throw await u(t.values()),s}return r.portReservations=t,a}function f(r,e){r.runtimeConfigs=k(r.sourceConfigs,r.runtimeId,r.runtimeDir,{databaseBindings:r.databaseBindings,graphDirName:r.graphDirName,ports:e}),r.ports=e}function G(r,e){return{get configs(){return r.runtimeConfigs},async releasePort(t){const a=r.portReservations.get(t);r.portReservations.delete(t),await a?.release()},async reassignPort(t,a){const s=r.triedPorts.get(t)??new Set,i=r.ports?.get(t);if(i!==void 0){s.add(i);const o=await U(i);o&&r.triedPortReservations.push(o)}r.triedPorts.set(t,s),await r.portReservations.get(t)?.release();const n=await J(s);r.portReservations.set(t,n);const h=new Map(r.runtimeConfigs.map(o=>[o.name,b(o)]));return f(r,new Map([...r.ports??[],[t,n.port]])),y(r,e.environmentRecord),r.runtimeConfigs.filter(o=>a.has(o.name)&&b(o)!==h.get(o.name)).map(o=>o.name)},async prepare(t){await l(r.runtimeConfigs.filter(a=>t.has(a.name)),e)}}}async function J(r){const e=[];try{for(;;){const t=await I();if(!r.has(t.port))return t;e.push(t)}}finally{await u(e)}}function b(r){return JSON.stringify({env:c(r,{},{},{includeTestkitControls:!1}),prepare:r.testkit.runtime.prepare,readyUrl:r.testkit.local?.readyUrl??null,start:r.testkit.local?.start??null})}async function Z(r,e){r?.ready&&(await T(r.startedServices,e),r.ready=!1,r.startedServices=[])}export async function cleanupRuntimeInstanceContext(r,e){if(!r)return;await Z(r,e),await u([...r.portReservations.values(),...r.triedPortReservations]),r.portReservations.clear(),r.triedPortReservations=[];const t=r.runtimeConfigs.filter(s=>s.testkit.database);if(t.length===0)return;const{dropRecordedTaskDatabases:a}=await import("../database/index.js");for(const s of t)await a({productDir:s.productDir,stateDir:s.stateDir})}export async function prepareDatabases(r,e={}){const t=new Map;if(r.some(a=>a.testkit.database)){const{provisionDatabase:a}=await import("../database/index.js");for(const s of r){const i=await a(A(s,m(r,t)),{progress:{reporter:e.reporter,setupRegistry:e.setupRegistry},provisionedSharedDatabases:e.provisionedSharedDatabases,signal:e.signal,skipSchemaSourceVerify:e.skipSchemaSourceVerify});i&&t.set(s.name,S(i.url))}}return q(r,t)}function q(r,e){const t=m(r,e);for(const a of r){const s=a.testkit.databaseFrom;if(s&&!t.has(a.name))throw H(a.name,s,r)}return t}function H(r,e,t){const a=t.some(s=>s.name===e)?`"${e}" declares no database`:`"${e}" is not in this runtime; add it to dependsOn`;return new Error(`Service "${r}" databaseFrom "${e}" has no database to use: ${a}`)}