@gfdelarue/testkit 0.4.4 → 0.4.5

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 (276) hide show
  1. package/README.md +108 -21
  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/draft.js +3 -3
  6. package/dist/app/bugs/facts.d.ts +3 -2
  7. package/dist/app/bugs/facts.js +2 -2
  8. package/dist/app/bugs/guide.js +1 -1
  9. package/dist/app/bugs/run-reading.js +1 -1
  10. package/dist/app/db-schema/prepare.js +1 -1
  11. package/dist/app/destroy/index.js +1 -1
  12. package/dist/app/doctor/index.js +1 -1
  13. package/dist/app/environments/config-driven.d.ts +5 -0
  14. package/dist/app/environments/config-driven.js +1 -0
  15. package/dist/app/environments/routing.d.ts +6 -0
  16. package/dist/app/environments/routing.js +1 -0
  17. package/dist/app/environments/supplied.d.ts +3 -0
  18. package/dist/app/environments/supplied.js +1 -0
  19. package/dist/app/file-selection.js +1 -1
  20. package/dist/app/lint/native.js +1 -1
  21. package/dist/app/lint/options.d.ts +0 -1
  22. package/dist/app/lint/options.js +1 -1
  23. package/dist/app/lint/shared.d.ts +0 -2
  24. package/dist/app/lint/shared.js +1 -1
  25. package/dist/app/package-inspection.js +1 -1
  26. package/dist/app/reports/files.d.ts +13 -0
  27. package/dist/app/reports/files.js +1 -0
  28. package/dist/app/reports/prepare.d.ts +20 -0
  29. package/dist/app/reports/prepare.js +2 -0
  30. package/dist/app/reports/publish.d.ts +21 -0
  31. package/dist/app/reports/publish.js +1 -0
  32. package/dist/app/run/engine-evidence-persistence.js +1 -1
  33. package/dist/app/run/engine-execution-cleanup.js +1 -1
  34. package/dist/app/run/engine-execution-failures.js +1 -1
  35. package/dist/app/run/engine-execution.d.ts +10 -8
  36. package/dist/app/run/engine-execution.js +1 -1
  37. package/dist/app/run/engine-orchestration.d.ts +15 -34
  38. package/dist/app/run/engine-orchestration.js +1 -1
  39. package/dist/app/run/environment.d.ts +33 -0
  40. package/dist/app/run/environment.js +1 -0
  41. package/dist/app/run/failure-details.js +1 -1
  42. package/dist/app/run/live-run.d.ts +3 -1
  43. package/dist/app/run/live-run.js +1 -1
  44. package/dist/app/run/orchestrator.d.ts +8 -1
  45. package/dist/app/run/orchestrator.js +1 -1
  46. package/dist/app/run/planning.d.ts +1 -2
  47. package/dist/app/run/planning.js +1 -1
  48. package/dist/app/run/results.d.ts +1 -1
  49. package/dist/app/run/results.js +1 -1
  50. package/dist/app/run/run-finalization.d.ts +6 -2
  51. package/dist/app/run/run-finalization.js +1 -1
  52. package/dist/app/run/runtime-fixtures.js +1 -1
  53. package/dist/app/run/runtime-task-types.d.ts +1 -1
  54. package/dist/app/run/scheduler/index.js +1 -1
  55. package/dist/app/run/scheduler/locks.d.ts +6 -0
  56. package/dist/app/run/scheduler/locks.js +1 -0
  57. package/dist/app/run/selection.d.ts +0 -1
  58. package/dist/app/run/selection.js +1 -1
  59. package/dist/app/run/setup/runtime-node-setup-protocol.js +1 -1
  60. package/dist/app/run/setup/runtime-node-setup-worker.js +1 -1
  61. package/dist/app/run/task-leases.d.ts +15 -0
  62. package/dist/app/run/task-leases.js +1 -0
  63. package/dist/app/run/worker-loop.d.ts +13 -4
  64. package/dist/app/run/worker-loop.js +1 -1
  65. package/dist/app/tracker/index.d.ts +6 -1
  66. package/dist/app/tracker/index.js +1 -1
  67. package/dist/app/typecheck/index.js +4 -4
  68. package/dist/cli/command-catalog.d.ts +19 -0
  69. package/dist/cli/command-catalog.js +1 -1
  70. package/dist/cli/command-registry.js +1 -1
  71. package/dist/cli/commands/report/prepare.d.ts +12 -0
  72. package/dist/cli/commands/report/prepare.js +5 -0
  73. package/dist/cli/commands/report/publish.d.ts +13 -0
  74. package/dist/cli/commands/report/publish.js +2 -0
  75. package/dist/cli/json-errors.js +1 -1
  76. package/dist/cli/operations/run/operation.d.ts +3 -1
  77. package/dist/cli/operations/run/operation.js +2 -2
  78. package/dist/cli/renderers/doctor/text.js +1 -1
  79. package/dist/cli/renderers/run/formatting.js +1 -1
  80. package/dist/config/authoring/index.d.ts +4 -13
  81. package/dist/config/authoring/index.js +1 -1
  82. package/dist/config/authoring/preset-env.js +1 -1
  83. package/dist/config/loader/config-loader.js +1 -1
  84. package/dist/config/loader/database.js +1 -1
  85. package/dist/config/loader/decode-execution.d.ts +0 -2
  86. package/dist/config/loader/decode-execution.js +1 -1
  87. package/dist/config/loader/discover-tests.js +1 -1
  88. package/dist/config/loader/discovery.d.ts +0 -1
  89. package/dist/config/loader/discovery.js +2 -2
  90. package/dist/config/loader/env.js +1 -1
  91. package/dist/config/loader/execution-model.d.ts +0 -1
  92. package/dist/config/loader/execution-model.js +1 -1
  93. package/dist/config/loader/file-metadata.d.ts +1 -1
  94. package/dist/config/loader/file-metadata.js +1 -1
  95. package/dist/config/loader/groups.d.ts +33 -0
  96. package/dist/config/loader/groups.js +1 -0
  97. package/dist/config/loader/load.d.ts +0 -2
  98. package/dist/config/loader/load.js +1 -1
  99. package/dist/config/loader/runtime-isolation.js +1 -1
  100. package/dist/config/loader/runtime.d.ts +0 -9
  101. package/dist/config/loader/runtime.js +1 -1
  102. package/dist/config/loader/skip-config.js +1 -1
  103. package/dist/config/loader/validation.d.ts +1 -2
  104. package/dist/config/loader/validation.js +1 -1
  105. package/dist/config/loader/values.d.ts +0 -1
  106. package/dist/config/loader/values.js +1 -1
  107. package/dist/database/activity-gate.js +1 -1
  108. package/dist/database/admin.js +2 -2
  109. package/dist/database/lifecycle-cleanup.d.ts +1 -0
  110. package/dist/database/lifecycle-cleanup.js +1 -1
  111. package/dist/database/local-postgres.js +1 -1
  112. package/dist/database/naming.js +1 -1
  113. package/dist/database/schema-operations.d.ts +1 -1
  114. package/dist/database/schema-operations.js +1 -1
  115. package/dist/database/schema-source.js +3 -3
  116. package/dist/database/source-url.d.ts +0 -1
  117. package/dist/database/source-url.js +2 -2
  118. package/dist/database/state.js +1 -1
  119. package/dist/database/steps.js +3 -3
  120. package/dist/domain/file-timeout.d.ts +0 -3
  121. package/dist/domain/file-timeout.js +1 -1
  122. package/dist/domain/operation-display.js +1 -1
  123. package/dist/domain/test-outcomes.d.ts +0 -1
  124. package/dist/domain/test-outcomes.js +1 -1
  125. package/dist/engines/adapters/evidence-identity.js +1 -1
  126. package/dist/engines/adapters/execution.d.ts +0 -1
  127. package/dist/engines/adapters/execution.js +1 -1
  128. package/dist/engines/api/capabilities.d.ts +0 -10
  129. package/dist/engines/api/capabilities.js +1 -1
  130. package/dist/engines/api/execution-scope.js +1 -1
  131. package/dist/engines/api/k6-runtime-input.js +1 -1
  132. package/dist/engines/bundle-cache.js +1 -1
  133. package/dist/engines/contracts/fixture-manifest.js +1 -1
  134. package/dist/engines/definitions.d.ts +1 -0
  135. package/dist/engines/definitions.js +1 -1
  136. package/dist/engines/installations/playwright-resolution-child.js +1 -1
  137. package/dist/engines/installations/playwright.js +1 -1
  138. package/dist/engines/k6/adapter/evidence.js +4 -4
  139. package/dist/engines/k6/adapter/executor.js +1 -1
  140. package/dist/engines/k6/adapter/native-summary.js +1 -1
  141. package/dist/engines/k6/runtime/checks.js +1 -1
  142. package/dist/engines/k6/runtime/dal-fixtures.js +1 -1
  143. package/dist/engines/k6/runtime/dal-suite.js +1 -1
  144. package/dist/engines/k6/runtime/http-suite-runtime.js +1 -1
  145. package/dist/engines/k6/runtime/http.js +1 -1
  146. package/dist/engines/k6/runtime/shared/db-normalization.js +1 -1
  147. package/dist/engines/k6/runtime/shared/fixture-engine.js +2 -2
  148. package/dist/engines/k6/runtime/shared/http-parsing.js +3 -3
  149. package/dist/engines/managed-module-resolution-policy-input.d.ts +0 -1
  150. package/dist/engines/managed-module-resolution-policy-input.js +1 -1
  151. package/dist/engines/managed-module-resolution-policy.js +1 -1
  152. package/dist/engines/node-vitest/adapter/adapter.js +1 -1
  153. package/dist/engines/node-vitest/adapter/evidence.js +2 -2
  154. package/dist/engines/node-vitest/adapter/workspace.js +22 -21
  155. package/dist/engines/node-vitest/runtime/contract/index.js +1 -1
  156. package/dist/engines/node-vitest/runtime/data/http.js +1 -1
  157. package/dist/engines/node-vitest/runtime/data/index.d.ts +2 -2
  158. package/dist/engines/node-vitest/runtime/data/index.js +1 -1
  159. package/dist/engines/node-vitest/runtime/data/report.js +5 -5
  160. package/dist/engines/node-vitest/runtime/data/scenario.d.ts +0 -1
  161. package/dist/engines/node-vitest/runtime/data/scenario.js +2 -2
  162. package/dist/engines/node-vitest/runtime/data/types.d.ts +1 -29
  163. package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
  164. package/dist/engines/playwright/adapter/adapter.js +1 -1
  165. package/dist/engines/playwright/adapter/config.d.ts +1 -1
  166. package/dist/engines/playwright/adapter/config.js +4 -4
  167. package/dist/engines/playwright/adapter/evidence-validation.d.ts +0 -3
  168. package/dist/engines/playwright/adapter/evidence-validation.js +1 -1
  169. package/dist/engines/playwright/adapter/evidence.js +1 -1
  170. package/dist/engines/playwright/runtime/config-file.js +1 -1
  171. package/dist/engines/playwright/runtime/config.js +1 -1
  172. package/dist/engines/playwright/runtime/runtime-input.d.ts +2 -2
  173. package/dist/engines/playwright/runtime/runtime-input.js +16 -12
  174. package/dist/environment/lifecycle-artifacts.js +1 -1
  175. package/dist/environment/lifecycle-controller.d.ts +1 -11
  176. package/dist/environment/lifecycle-controller.js +1 -1
  177. package/dist/environment/lifecycle.d.ts +14 -11
  178. package/dist/environment/lifecycle.js +1 -1
  179. package/dist/environment/planning-types.d.ts +0 -2
  180. package/dist/environment/ports.d.ts +10 -0
  181. package/dist/environment/ports.js +1 -0
  182. package/dist/environment/ready-environment.d.ts +2 -5
  183. package/dist/environment/ready-environment.js +1 -1
  184. package/dist/environment/run-environment.d.ts +1 -0
  185. package/dist/environment/run-environment.js +1 -1
  186. package/dist/environment/runtime-contexts.d.ts +11 -7
  187. package/dist/environment/runtime-contexts.js +1 -1
  188. package/dist/environment/runtime-manager.d.ts +1 -9
  189. package/dist/environment/runtime-manager.js +1 -1
  190. package/dist/environment/runtime-planning.js +1 -1
  191. package/dist/environment/runtime-preparation.js +1 -1
  192. package/dist/environment/runtime-service.d.ts +0 -6
  193. package/dist/environment/services.d.ts +11 -3
  194. package/dist/environment/services.js +3 -1
  195. package/dist/environment/state.d.ts +1 -4
  196. package/dist/environment/state.js +1 -1
  197. package/dist/environment/template.d.ts +6 -22
  198. package/dist/environment/template.js +1 -1
  199. package/dist/evidence/artifact-config.js +1 -1
  200. package/dist/evidence/artifact-validation.d.ts +1 -2
  201. package/dist/evidence/artifact-validation.js +1 -1
  202. package/dist/evidence/artifacts.js +2 -2
  203. package/dist/evidence/bundles.js +1 -1
  204. package/dist/evidence/environment-record.d.ts +22 -0
  205. package/dist/evidence/environment-record.js +1 -0
  206. package/dist/evidence/index.d.ts +1 -1
  207. package/dist/evidence/logs.js +2 -2
  208. package/dist/evidence/operation-timings.js +1 -1
  209. package/dist/evidence/read-fields.d.ts +0 -1
  210. package/dist/evidence/read-fields.js +1 -1
  211. package/dist/evidence/read-run.js +1 -1
  212. package/dist/evidence/reading.js +1 -1
  213. package/dist/evidence/reporting-types.d.ts +19 -0
  214. package/dist/evidence/reporting.d.ts +2 -2
  215. package/dist/evidence/reporting.js +1 -1
  216. package/dist/evidence/storage.d.ts +0 -2
  217. package/dist/evidence/storage.js +2 -2
  218. package/dist/evidence/timing.js +1 -1
  219. package/dist/kernel/error-serialization.d.ts +2 -0
  220. package/dist/kernel/error-serialization.js +1 -1
  221. package/dist/kernel/unknown-values.d.ts +5 -0
  222. package/dist/kernel/unknown-values.js +1 -1
  223. package/dist/process/environment.js +1 -1
  224. package/dist/process/execa-bundle.json +3 -3
  225. package/dist/process/files/json-file.d.ts +0 -1
  226. package/dist/process/files/json-file.js +1 -1
  227. package/dist/process/files/paths.d.ts +2 -0
  228. package/dist/process/files/paths.js +1 -1
  229. package/dist/process/host/metadata.js +1 -1
  230. package/dist/process/host/platform.js +1 -1
  231. package/dist/process/host-process.js +1 -1
  232. package/dist/process/lifecycle-fence.d.ts +1 -2
  233. package/dist/process/lifecycle-fence.js +1 -1
  234. package/dist/process/locks.js +2 -2
  235. package/dist/process/process-group.js +1 -1
  236. package/dist/process/process-identity.js +1 -1
  237. package/dist/process/process.js +30 -30
  238. package/dist/process/readiness.d.ts +7 -1
  239. package/dist/process/readiness.js +1 -1
  240. package/dist/process/recovery.js +1 -1
  241. package/dist/process/runs/manifest.js +1 -1
  242. package/dist/process/runs/ownership.js +1 -1
  243. package/dist/process/runs/product-state.js +1 -1
  244. package/dist/process/runs/stop.js +1 -1
  245. package/dist/process/stoppable-settlement.d.ts +26 -0
  246. package/dist/process/stoppable-settlement.js +1 -0
  247. package/dist/process/url-redaction.d.ts +1 -0
  248. package/dist/process/url-redaction.js +1 -0
  249. package/dist/process/windows-native.d.ts +6 -0
  250. package/dist/process/windows-native.js +1 -1
  251. package/dist/repo/ci-environment.js +1 -1
  252. package/dist/repo/fingerprint-policy.d.ts +0 -2
  253. package/dist/repo/fingerprint-policy.js +1 -1
  254. package/dist/repo/physical-tree.js +1 -1
  255. package/dist/repo/publish-directory.d.ts +20 -0
  256. package/dist/repo/publish-directory.js +3 -0
  257. package/dist/repo/state.js +4 -4
  258. package/dist/steps/build-config.d.ts +0 -1
  259. package/dist/steps/build-config.js +1 -1
  260. package/dist/steps/configured-steps.js +1 -1
  261. package/dist/steps/environment.d.ts +0 -2
  262. package/dist/steps/environment.js +1 -1
  263. package/dist/steps/index.d.ts +1 -1
  264. package/dist/steps/run.js +2 -2
  265. package/dist/toolchains/archive.js +1 -1
  266. package/dist/toolchains/index.js +3 -3
  267. package/dist/toolchains/node-provisioning.js +2 -2
  268. package/dist/toolchains/vitest/index.js +1 -1
  269. package/docs/bug-records.md +54 -52
  270. package/docs/engine-architecture.md +39 -11
  271. package/package.json +1 -1
  272. package/testkit-config-schema.md +43 -5
  273. package/dist/app/run/playwright-configuration.d.ts +0 -2
  274. package/dist/app/run/playwright-configuration.js +0 -1
  275. package/dist/environment/readiness.d.ts +0 -12
  276. package/dist/environment/readiness.js +0 -1
@@ -1,2 +1,2 @@
1
- import w from"node:fs/promises";import y from"node:path";import{evidenceFileAccess as B,readStableEvidenceFile as V,writeOwnedEvidenceFile as $}from"../../adapters/evidence-files.js";import{NODE_VITEST_DATA_BUDGET_FAILURE_DETAIL_KIND as b,NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_KIND as _,NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_NAME as F}from"../runtime/runtime-input.js";import{vitestErrorDetails as L,vitestTestFailureDetails as M}from"./failure-details.js";import{readNativeReport as z,requireNativeEvidenceJson as C}from"../../adapters/native-report.js";const J=16*1024*1024,N=1024;export const NODE_VITEST_DATA_ARTIFACT_MAX_BYTES=16*1024*1024,NODE_VITEST_DATA_EVIDENCE_MAX_BYTES=64*1024*1024;const U=".testkit-owned-evidence";export async function collectNodeVitestEvidence(t,e=B){await w.mkdir(t.artifactDirectory,{recursive:!0});const r=await w.realpath(t.artifactDirectory),s=y.join(r,U);await w.mkdir(s,{mode:448,recursive:!1});const n=[],a=[];t.stdout.length>0&&(a.push({stream:"stdout",text:t.stdout}),n.push(await I(r,"stdout.log","node-vitest-stdout",t.stdout))),t.stderr.length>0&&(a.push({stream:"stderr",text:t.stderr}),n.push(await I(r,"stderr.log","node-vitest-stderr",t.stderr)));const i=await X(t.reportFile,t.identity,t.rootDirectory,s,e);n.push(...i.artifacts);const f=t.profileId==="node-vitest-data"?await K(r,s,t.dataManifestFile,e):{artifacts:[],error:null};return n.push(...f.artifacts),{dataEvidenceError:f.error,evidence:{artifacts:n,logs:a,metrics:[],...i.summary===null?{}:{native:{vitest:i.summary}}},reportError:i.error,reportFailureMessage:i.failureMessage,reportSummary:i.summary}}async function X(t,e,r,s,n){try{const a=await v(t,n);if(!a.exists||a.contents===null)throw new Error("Vitest did not produce its Testkit native report");const i=z(a.value,e).result;if(!T(i)||!T(i.summary))throw new Error("Vitest native report must contain result and summary objects");const f=Q(i.summary),c=M(i.failures,r);if(f.numFailedTests!==c.length)throw new Error("Vitest native report failure count does not match its summary");if(!Array.isArray(i.errors)||!i.errors.every(m=>typeof m=="string"))throw new Error("Vitest native report errors must contain strings");if(f.success&&i.errors.length>0)throw new Error("Vitest native report success conflicts with runtime errors");const u=await $(s,"testkit-vitest-report.json",a.contents),o=await S(u,"application/json","engine.testkit-vitest-report","testkit-vitest-report","Testkit native Vitest report"),d=await Y(s,c,L(i.errors));return{artifacts:[o,...d===null?[]:[d]],error:null,failureMessage:typeof c[0]?.message=="string"?c[0].message:i.errors.find(m=>m.trim().length>0)??null,summary:f}}catch(a){return{artifacts:[],error:D(a),failureMessage:null,summary:null}}}async function Y(t,e,r){if(e.length+r.length===0)return null;const s={failures:[...e,...r],phase:"exec"},n=await $(t,"vitest-failure-details.json",Buffer.from(`${JSON.stringify(s,null,2)}
2
- `,"utf8"));return{...await S(n,"application/json","testkit.failure-details","vitest-failure-details",[...e.length===0?[]:[k(e.length,"failed Vitest test")],...r.length===0?[]:[`${k(r.length,"Vitest error")} outside a test`]].join(" and ")),data:s}}function k(t,e){return`${t.toString()} ${e}${t===1?"":"s"}`}async function K(t,e,r,s){let n;try{n=await v(r,s)}catch(c){return{artifacts:[],error:D(c)}}if(!n.exists)return{artifacts:[],error:new Error("Data profile did not produce an artifact manifest")};let a;try{a=W(n.value)}catch(c){return{artifacts:[],error:D(c)}}const i=[],f=new Set;try{if(n.contents===null)throw new Error("Data artifact manifest bytes are unavailable");let c=n.contents.byteLength;if(c>NODE_VITEST_DATA_EVIDENCE_MAX_BYTES)throw new Error(`Data evidence exceeds its ${NODE_VITEST_DATA_EVIDENCE_MAX_BYTES.toString()} byte aggregate limit`);for(const[o,d]of a.artifacts.entries()){const m=await G(t,e,d,o,NODE_VITEST_DATA_EVIDENCE_MAX_BYTES-c,s),{artifact:l}=m,p=`${l.kind}\0${l.name}\0${m.sourcePath}`;if(f.has(p))throw new Error(`Data artifact manifest contains duplicate artifact ${l.name}`);f.add(p);const E=et(l.metadata?.sizeBytes,`Data artifact manifest artifacts[${o.toString()}]`);c+=E,i.push(l)}const u=await $(e,"manifest.json",n.contents);i.push(await S(u,"application/json","engine.data-manifest","data-artifact-manifest",`${i.length.toString()} data artifact(s)`))}catch(c){return{artifacts:i,error:D(c)}}return{artifacts:i,error:null}}function W(t){if(!T(t))throw new Error("Data artifact manifest must contain an object");if(t.schemaVersion!==1)throw new Error("Data artifact manifest schemaVersion must be 1");if(!Array.isArray(t.artifacts))throw new Error("Data artifact manifest artifacts must be an array");if(t.artifacts.length===0)throw new Error("Data artifact manifest must contain at least one artifact");if(t.artifacts.length>N)throw new Error(`Data artifact manifest exceeds the ${N.toString()} artifact limit`);return{artifacts:t.artifacts,schemaVersion:t.schemaVersion}}async function G(t,e,r,s,n,a){const i=`Data artifact manifest artifacts[${s.toString()}]`;if(!T(r))throw new Error(`${i} must contain an object`);const f=g(r.kind,`${i}.kind`),c=g(r.name,`${i}.name`),u=g(r.path,`${i}.path`),o=await Z(t,u,`${i}.path`),d=O(r.contentType,`${i}.contentType`),m=O(r.summary,`${i}.summary`),l=r.metadata===void 0?void 0:A(r.metadata,`${i}.metadata`),{contents:p}=await V(o,NODE_VITEST_DATA_ARTIFACT_MAX_BYTES,i,a);if(p.byteLength>n)throw new Error(`Data evidence exceeds its ${NODE_VITEST_DATA_EVIDENCE_MAX_BYTES.toString()} byte aggregate limit`);const E=H(f,c,d,p,i),R=await $(e,`${s.toString().padStart(4,"0")}-${q(c)}${tt(o)}`,p);return{artifact:{kind:f,name:c,path:R,...d===void 0?{}:{contentType:d},...E===void 0?{}:{data:E},...m===void 0?{}:{summary:m},metadata:{...l??{},sizeBytes:p.byteLength}},sourcePath:o}}function H(t,e,r,s,n){if(t!==_)return;if(e!==F)throw new Error(`${n}.name must be ${JSON.stringify(F)} for ${_}`);if(r!=="application/json")throw new Error(`${n}.contentType must be "application/json" for ${_}`);const a=x(s,n),i=A(a,n);if(P(i,["failures","phase"],n),i.phase!=="exec")throw new Error(`${n}.phase must be "exec"`);if(!Array.isArray(i.failures)||i.failures.length===0)throw new Error(`${n}.failures must be a non-empty array`);for(const[f,c]of i.failures.entries()){const u=`${n}.failures[${f.toString()}]`,o=A(c,u);if(P(o,["actual","checkName","count","expected","groupPath","key","kind","message","title"],u),o.kind!==b)throw new Error(`${u}.kind must be ${JSON.stringify(b)}`);if(o.count!==1)throw new Error(`${u}.count must be 1`);const d=g(o.checkName,`${u}.checkName`),m=g(o.key,`${u}.key`),l=g(o.title,`${u}.title`);if(g(o.message,`${u}.message`),!Array.isArray(o.groupPath)||o.groupPath.length!==1||typeof o.groupPath[0]!="string"||o.groupPath[0].trim().length===0)throw new Error(`${u}.groupPath must contain one scenario name`);if(m!==`${o.groupPath[0]} > ${l}`)throw new Error(`${u}.key does not match its scenario and title`);if(!l.includes(`"${d}"`))throw new Error(`${u}.title does not identify its checkName`)}return i}async function I(t,e,r,s){const n=y.join(t,e);return await w.writeFile(n,s,"utf8"),S(n,"text/plain; charset=utf-8","engine.output",r,nt(s)??"captured output")}async function S(t,e,r,s,n){const a=await w.stat(t);if(!a.isFile())throw new Error(`${s} artifact is not a regular file`);return{contentType:e,kind:r,metadata:{sizeBytes:a.size},name:s,path:t,summary:n}}async function v(t,e){let r;try{({contents:r}=await V(t,J,t,e))}catch(n){if(st(n)&&n.code==="ENOENT")return{contents:null,exists:!1,value:null};throw n}const s=x(r,t);return{contents:r,exists:!0,value:s}}function x(t,e){const r=JSON.parse(t.toString("utf8"));return C(r,e),r}function Q(t){const e={numFailedTests:h(t.numFailedTests,"Vitest native report.summary.numFailedTests"),numPassedTests:h(t.numPassedTests,"Vitest native report.summary.numPassedTests"),numPendingTests:h(t.numPendingTests,"Vitest native report.summary.numPendingTests"),numTodoTests:h(t.numTodoTests,"Vitest native report.summary.numTodoTests"),numTotalTests:h(t.numTotalTests,"Vitest native report.summary.numTotalTests"),numFailedTestSuites:h(t.numFailedTestSuites,"Vitest native report.summary.numFailedTestSuites"),numPassedTestSuites:h(t.numPassedTestSuites,"Vitest native report.summary.numPassedTestSuites"),numPendingTestSuites:h(t.numPendingTestSuites,"Vitest native report.summary.numPendingTestSuites"),numTotalTestSuites:h(t.numTotalTestSuites,"Vitest native report.summary.numTotalTestSuites"),success:rt(t.success,"Vitest native report.summary.success")};if(e.numTotalTests!==e.numFailedTests+e.numPassedTests+e.numPendingTests+e.numTodoTests||e.numTotalTestSuites!==e.numFailedTestSuites+e.numPassedTestSuites+e.numPendingTestSuites||e.success&&(e.numFailedTests>0||e.numFailedTestSuites>0||e.numTotalTestSuites===0))throw new Error("Vitest native report summary contains inconsistent counts or success");return e}async function Z(t,e,r){const s=y.isAbsolute(e)?e:y.resolve(t,e),n=await w.lstat(s);if(!n.isFile()||n.isSymbolicLink())throw new Error(`${r} must be a regular non-symbolic-link file`);const a=await w.realpath(s);if(!it(t,a))throw new Error(`${r} must stay within the task artifact directory`);return a}function q(t){const e=t.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,80);return e.length===0?"artifact":e}function tt(t){const e=y.extname(t).toLowerCase();return/^\.[a-z0-9]{1,12}$/u.test(e)?e:".bin"}function et(t,e){if(typeof t!="number"||!Number.isSafeInteger(t)||t<0)throw new Error(`${e} did not produce a valid sizeBytes identity`);return t}function A(t,e){if(!T(t))throw new Error(`${e} must contain an object`);const r={};for(const[s,n]of Object.entries(t))r[s]=j(n,`${e}.${s}`);return r}function P(t,e,r){const s=Object.keys(t).sort(),n=[...e].sort();if(s.length!==n.length||s.some((a,i)=>a!==n[i]))throw new Error(`${r} must contain exactly ${n.join(", ")}`)}function j(t,e){if(t===null||typeof t=="boolean"||typeof t=="string")return t;if(typeof t=="number"){if(!Number.isFinite(t))throw new Error(`${e} must be finite`);return t}return Array.isArray(t)?t.map((r,s)=>j(r,`${e}[${s.toString()}]`)):A(t,e)}function O(t,e){if(t!==void 0){if(typeof t!="string")throw new Error(`${e} must be a string`);return t}}function g(t,e){if(typeof t!="string"||t.trim().length===0)throw new Error(`${e} must be a non-empty string`);return t}function h(t,e){if(typeof t!="number"||!Number.isSafeInteger(t)||t<0)throw new Error(`${e} must be a non-negative safe integer`);return t}function rt(t,e){if(typeof t!="boolean")throw new Error(`${e} must be boolean`);return t}function nt(t){return t.split(/\r?\n/u).map(e=>e.trim()).find(Boolean)??null}function it(t,e){const r=y.relative(t,e);return r===""||!r.startsWith("..")&&!y.isAbsolute(r)}function T(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function st(t){return t instanceof Error}function D(t){return t instanceof Error?t:new Error(String(t))}
1
+ import w from"node:fs/promises";import g from"node:path";import{evidenceFileAccess as B,readStableEvidenceFile as V,writeOwnedEvidenceFile as $}from"../../adapters/evidence-files.js";import{NODE_VITEST_DATA_BUDGET_FAILURE_DETAIL_KIND as F,NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_KIND as _,NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_NAME as N}from"../runtime/runtime-input.js";import{vitestErrorDetails as L,vitestTestFailureDetails as M}from"./failure-details.js";import{readNativeReport as z,requireNativeEvidenceJson as C}from"../../adapters/native-report.js";import{isUnknownRecord as T}from"../../../kernel/unknown-values.js";import{toError as S}from"../../../kernel/error-serialization.js";import{isPathWithin as J}from"../../../process/files/paths.js";const U=16*1024*1024,b=1024;export const NODE_VITEST_DATA_ARTIFACT_MAX_BYTES=16*1024*1024,NODE_VITEST_DATA_EVIDENCE_MAX_BYTES=64*1024*1024;const X=".testkit-owned-evidence";export async function collectNodeVitestEvidence(t,e=B){await w.mkdir(t.artifactDirectory,{recursive:!0});const r=await w.realpath(t.artifactDirectory),s=g.join(r,X);await w.mkdir(s,{mode:448,recursive:!1});const n=[],a=[];t.stdout.length>0&&(a.push({stream:"stdout",text:t.stdout}),n.push(await I(r,"stdout.log","node-vitest-stdout",t.stdout))),t.stderr.length>0&&(a.push({stream:"stderr",text:t.stderr}),n.push(await I(r,"stderr.log","node-vitest-stderr",t.stderr)));const i=await Y(t.reportFile,t.identity,t.rootDirectory,s,e);n.push(...i.artifacts);const f=t.profileId==="node-vitest-data"?await W(r,s,t.dataManifestFile,e):{artifacts:[],error:null};return n.push(...f.artifacts),{dataEvidenceError:f.error,evidence:{artifacts:n,logs:a,metrics:[],...i.summary===null?{}:{native:{vitest:i.summary}}},reportError:i.error,reportFailureMessage:i.failureMessage,reportSummary:i.summary}}async function Y(t,e,r,s,n){try{const a=await v(t,n);if(!a.exists||a.contents===null)throw new Error("Vitest did not produce its Testkit native report");const i=z(a.value,e).result;if(!T(i)||!T(i.summary))throw new Error("Vitest native report must contain result and summary objects");const f=Z(i.summary),c=M(i.failures,r);if(f.numFailedTests!==c.length)throw new Error("Vitest native report failure count does not match its summary");if(!Array.isArray(i.errors)||!i.errors.every(m=>typeof m=="string"))throw new Error("Vitest native report errors must contain strings");if(f.success&&i.errors.length>0)throw new Error("Vitest native report success conflicts with runtime errors");const u=await $(s,"testkit-vitest-report.json",a.contents),o=await A(u,"application/json","engine.testkit-vitest-report","testkit-vitest-report","Testkit native Vitest report"),d=await K(s,c,L(i.errors));return{artifacts:[o,...d===null?[]:[d]],error:null,failureMessage:typeof c[0]?.message=="string"?c[0].message:i.errors.find(m=>m.trim().length>0)??null,summary:f}}catch(a){return{artifacts:[],error:S(a),failureMessage:null,summary:null}}}async function K(t,e,r){if(e.length+r.length===0)return null;const s={failures:[...e,...r],phase:"exec"},n=await $(t,"vitest-failure-details.json",Buffer.from(`${JSON.stringify(s,null,2)}
2
+ `,"utf8"));return{...await A(n,"application/json","testkit.failure-details","vitest-failure-details",[...e.length===0?[]:[k(e.length,"failed Vitest test")],...r.length===0?[]:[`${k(r.length,"Vitest error")} outside a test`]].join(" and ")),data:s}}function k(t,e){return`${t.toString()} ${e}${t===1?"":"s"}`}async function W(t,e,r,s){let n;try{n=await v(r,s)}catch(c){return{artifacts:[],error:S(c)}}if(!n.exists)return{artifacts:[],error:new Error("Data profile did not produce an artifact manifest")};let a;try{a=G(n.value)}catch(c){return{artifacts:[],error:S(c)}}const i=[],f=new Set;try{if(n.contents===null)throw new Error("Data artifact manifest bytes are unavailable");let c=n.contents.byteLength;if(c>NODE_VITEST_DATA_EVIDENCE_MAX_BYTES)throw new Error(`Data evidence exceeds its ${NODE_VITEST_DATA_EVIDENCE_MAX_BYTES.toString()} byte aggregate limit`);for(const[o,d]of a.artifacts.entries()){const m=await H(t,e,d,o,NODE_VITEST_DATA_EVIDENCE_MAX_BYTES-c,s),{artifact:l}=m,p=`${l.kind}\0${l.name}\0${m.sourcePath}`;if(f.has(p))throw new Error(`Data artifact manifest contains duplicate artifact ${l.name}`);f.add(p);const E=rt(l.metadata?.sizeBytes,`Data artifact manifest artifacts[${o.toString()}]`);c+=E,i.push(l)}const u=await $(e,"manifest.json",n.contents);i.push(await A(u,"application/json","engine.data-manifest","data-artifact-manifest",`${i.length.toString()} data artifact(s)`))}catch(c){return{artifacts:i,error:S(c)}}return{artifacts:i,error:null}}function G(t){if(!T(t))throw new Error("Data artifact manifest must contain an object");if(t.schemaVersion!==1)throw new Error("Data artifact manifest schemaVersion must be 1");if(!Array.isArray(t.artifacts))throw new Error("Data artifact manifest artifacts must be an array");if(t.artifacts.length===0)throw new Error("Data artifact manifest must contain at least one artifact");if(t.artifacts.length>b)throw new Error(`Data artifact manifest exceeds the ${b.toString()} artifact limit`);return{artifacts:t.artifacts,schemaVersion:t.schemaVersion}}async function H(t,e,r,s,n,a){const i=`Data artifact manifest artifacts[${s.toString()}]`;if(!T(r))throw new Error(`${i} must contain an object`);const f=y(r.kind,`${i}.kind`),c=y(r.name,`${i}.name`),u=y(r.path,`${i}.path`),o=await q(t,u,`${i}.path`),d=O(r.contentType,`${i}.contentType`),m=O(r.summary,`${i}.summary`),l=r.metadata===void 0?void 0:D(r.metadata,`${i}.metadata`),{contents:p}=await V(o,NODE_VITEST_DATA_ARTIFACT_MAX_BYTES,i,a);if(p.byteLength>n)throw new Error(`Data evidence exceeds its ${NODE_VITEST_DATA_EVIDENCE_MAX_BYTES.toString()} byte aggregate limit`);const E=Q(f,c,d,p,i),R=await $(e,`${s.toString().padStart(4,"0")}-${tt(c)}${et(o)}`,p);return{artifact:{kind:f,name:c,path:R,...d===void 0?{}:{contentType:d},...E===void 0?{}:{data:E},...m===void 0?{}:{summary:m},metadata:{...l??{},sizeBytes:p.byteLength}},sourcePath:o}}function Q(t,e,r,s,n){if(t!==_)return;if(e!==N)throw new Error(`${n}.name must be ${JSON.stringify(N)} for ${_}`);if(r!=="application/json")throw new Error(`${n}.contentType must be "application/json" for ${_}`);const a=x(s,n),i=D(a,n);if(P(i,["failures","phase"],n),i.phase!=="exec")throw new Error(`${n}.phase must be "exec"`);if(!Array.isArray(i.failures)||i.failures.length===0)throw new Error(`${n}.failures must be a non-empty array`);for(const[f,c]of i.failures.entries()){const u=`${n}.failures[${f.toString()}]`,o=D(c,u);if(P(o,["actual","checkName","count","expected","groupPath","key","kind","message","title"],u),o.kind!==F)throw new Error(`${u}.kind must be ${JSON.stringify(F)}`);if(o.count!==1)throw new Error(`${u}.count must be 1`);const d=y(o.checkName,`${u}.checkName`),m=y(o.key,`${u}.key`),l=y(o.title,`${u}.title`);if(y(o.message,`${u}.message`),!Array.isArray(o.groupPath)||o.groupPath.length!==1||typeof o.groupPath[0]!="string"||o.groupPath[0].trim().length===0)throw new Error(`${u}.groupPath must contain one scenario name`);if(m!==`${o.groupPath[0]} > ${l}`)throw new Error(`${u}.key does not match its scenario and title`);if(!l.includes(`"${d}"`))throw new Error(`${u}.title does not identify its checkName`)}return i}async function I(t,e,r,s){const n=g.join(t,e);return await w.writeFile(n,s,"utf8"),A(n,"text/plain; charset=utf-8","engine.output",r,it(s)??"captured output")}async function A(t,e,r,s,n){const a=await w.stat(t);if(!a.isFile())throw new Error(`${s} artifact is not a regular file`);return{contentType:e,kind:r,metadata:{sizeBytes:a.size},name:s,path:t,summary:n}}async function v(t,e){let r;try{({contents:r}=await V(t,U,t,e))}catch(n){if(st(n)&&n.code==="ENOENT")return{contents:null,exists:!1,value:null};throw n}const s=x(r,t);return{contents:r,exists:!0,value:s}}function x(t,e){const r=JSON.parse(t.toString("utf8"));return C(r,e),r}function Z(t){const e={numFailedTests:h(t.numFailedTests,"Vitest native report.summary.numFailedTests"),numPassedTests:h(t.numPassedTests,"Vitest native report.summary.numPassedTests"),numPendingTests:h(t.numPendingTests,"Vitest native report.summary.numPendingTests"),numTodoTests:h(t.numTodoTests,"Vitest native report.summary.numTodoTests"),numTotalTests:h(t.numTotalTests,"Vitest native report.summary.numTotalTests"),numFailedTestSuites:h(t.numFailedTestSuites,"Vitest native report.summary.numFailedTestSuites"),numPassedTestSuites:h(t.numPassedTestSuites,"Vitest native report.summary.numPassedTestSuites"),numPendingTestSuites:h(t.numPendingTestSuites,"Vitest native report.summary.numPendingTestSuites"),numTotalTestSuites:h(t.numTotalTestSuites,"Vitest native report.summary.numTotalTestSuites"),success:nt(t.success,"Vitest native report.summary.success")};if(e.numTotalTests!==e.numFailedTests+e.numPassedTests+e.numPendingTests+e.numTodoTests||e.numTotalTestSuites!==e.numFailedTestSuites+e.numPassedTestSuites+e.numPendingTestSuites||e.success&&(e.numFailedTests>0||e.numFailedTestSuites>0||e.numTotalTestSuites===0))throw new Error("Vitest native report summary contains inconsistent counts or success");return e}async function q(t,e,r){const s=g.isAbsolute(e)?e:g.resolve(t,e),n=await w.lstat(s);if(!n.isFile()||n.isSymbolicLink())throw new Error(`${r} must be a regular non-symbolic-link file`);const a=await w.realpath(s);if(!J(t,a))throw new Error(`${r} must stay within the task artifact directory`);return a}function tt(t){const e=t.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu,"-").replace(/^-+|-+$/gu,"").slice(0,80);return e.length===0?"artifact":e}function et(t){const e=g.extname(t).toLowerCase();return/^\.[a-z0-9]{1,12}$/u.test(e)?e:".bin"}function rt(t,e){if(typeof t!="number"||!Number.isSafeInteger(t)||t<0)throw new Error(`${e} did not produce a valid sizeBytes identity`);return t}function D(t,e){if(!T(t))throw new Error(`${e} must contain an object`);const r={};for(const[s,n]of Object.entries(t))r[s]=j(n,`${e}.${s}`);return r}function P(t,e,r){const s=Object.keys(t).sort(),n=[...e].sort();if(s.length!==n.length||s.some((a,i)=>a!==n[i]))throw new Error(`${r} must contain exactly ${n.join(", ")}`)}function j(t,e){if(t===null||typeof t=="boolean"||typeof t=="string")return t;if(typeof t=="number"){if(!Number.isFinite(t))throw new Error(`${e} must be finite`);return t}return Array.isArray(t)?t.map((r,s)=>j(r,`${e}[${s.toString()}]`)):D(t,e)}function O(t,e){if(t!==void 0){if(typeof t!="string")throw new Error(`${e} must be a string`);return t}}function y(t,e){if(typeof t!="string"||t.trim().length===0)throw new Error(`${e} must be a non-empty string`);return t}function h(t,e){if(typeof t!="number"||!Number.isSafeInteger(t)||t<0)throw new Error(`${e} must be a non-negative safe integer`);return t}function nt(t,e){if(typeof t!="boolean")throw new Error(`${e} must be boolean`);return t}function it(t){return t.split(/\r?\n/u).map(e=>e.trim()).find(Boolean)??null}function st(t){return t instanceof Error}
@@ -1,8 +1,8 @@
1
- import o from"node:fs/promises";import i from"node:path";import{fileURLToPath as g,pathToFileURL as a}from"node:url";import{NODE_VITEST_RUNTIME_INPUT_SYMBOL as p}from"../runtime/runtime-input.js";import{NODE_VITEST_PACKAGE_REQUIREMENTS as R}from"../../installations/package-requirements.js";import{resolveNodeVitestManagedRuntimeResolution as y}from"./resolution.js";import{nativeReporterFile as S}from"../../adapters/native-report.js";const u="elench.testkit.node-vitest.config-runtime.v1",l=g(new URL("../../../../dist/engines/node-vitest/",import.meta.url)),f=i.join(l,"adapter/consumer-typescript-paths.js"),m=i.join(l,"runtime/data/runner.js"),d=i.join(l,"runtime/runtime-input.js");export async function writeNodeVitestWorkspace(e){await o.mkdir(i.dirname(e.setupFile),{recursive:!0});const t=y(e.entrypoints,{consumerRoots:[e.rootDirectory],trustedImporterFiles:[e.inputBootstrapFile,e.setupFile,e.vitestConfigFile],trustedInternalEntrypoints:[f,d]});await Promise.all([o.writeFile(e.setupFile,I(e.configFile,e.runtimeInput.expectedProfileId),"utf8"),o.writeFile(e.inputBootstrapFile,N(e.runtimeInput),"utf8"),o.writeFile(e.resolutionBootstrapFile,t.bootstrapSource,{encoding:"utf8",flag:"wx",mode:384}),o.writeFile(e.vitestConfigFile,O(e,t),"utf8")])}function N(e){const t=a(d).href,n=a(f).href;return`
1
+ import o from"node:fs/promises";import i from"node:path";import{fileURLToPath as g,pathToFileURL as a}from"node:url";import{NODE_VITEST_RUNTIME_INPUT_SYMBOL as c}from"../runtime/runtime-input.js";import{NODE_VITEST_PACKAGE_REQUIREMENTS as R}from"../../installations/package-requirements.js";import{resolveNodeVitestManagedRuntimeResolution as y}from"./resolution.js";import{nativeReporterFile as S}from"../../adapters/native-report.js";const p="elench.testkit.node-vitest.config-runtime.v1",l=g(new URL("../../../../dist/engines/node-vitest/",import.meta.url)),u=i.join(l,"adapter/consumer-typescript-paths.js"),f=i.join(l,"runtime/data/runner.js"),m=i.join(l,"runtime/runtime-input.js");export async function writeNodeVitestWorkspace(e){await o.mkdir(i.dirname(e.setupFile),{recursive:!0});const t=y(e.entrypoints,{consumerRoots:[e.rootDirectory],trustedImporterFiles:[e.inputBootstrapFile,e.setupFile,e.vitestConfigFile],trustedInternalEntrypoints:[u,m]});await Promise.all([o.writeFile(e.setupFile,I(e.configFile,e.runtimeInput.expectedProfileId),"utf8"),o.writeFile(e.inputBootstrapFile,N(e.runtimeInput),"utf8"),o.writeFile(e.resolutionBootstrapFile,t.bootstrapSource,{encoding:"utf8",flag:"wx",mode:384}),o.writeFile(e.vitestConfigFile,v(e,t),"utf8")])}function N(e){const t=a(m).href,n=a(u).href;return`
2
2
  const inputRuntime = await import(${JSON.stringify(t)});
3
3
  const { installNodeVitestRuntimeInput } = inputRuntime;
4
4
  await installNodeVitestRuntimeInput(${JSON.stringify(e)});
5
- const configRuntimeSymbol = Symbol.for(${JSON.stringify(u)});
5
+ const configRuntimeSymbol = Symbol.for(${JSON.stringify(p)});
6
6
  if (Object.hasOwn(globalThis, configRuntimeSymbol))
7
7
  throw new Error("Managed Node/Vitest config runtime is already installed");
8
8
  // Only the Vitest parent requests config policy. Fork workers still validate
@@ -44,35 +44,36 @@ Object.defineProperty(
44
44
  );
45
45
  `}function I(e,t){const n=`
46
46
  const installedRuntimeInput = globalThis[
47
- Symbol.for(${JSON.stringify(p)})
47
+ Symbol.for(${JSON.stringify(c)})
48
48
  ];
49
49
  if (installedRuntimeInput === undefined)
50
50
  throw new Error("Node/Vitest runtime input is not installed");
51
51
  const baseUrl = installedRuntimeInput.context?.baseUrl;
52
52
  if (typeof baseUrl === "string") process.env.BASE_URL = baseUrl;
53
53
  else delete process.env.BASE_URL;
54
- `,s=e===null?"const testkitRepositoryConfiguration = null;":`const testkitConfigModule = await import(${JSON.stringify(a(e).href)});
55
- const testkitRepositoryConfiguration =
56
- testkitConfigModule.default ??
57
- testkitConfigModule.config ??
58
- testkitConfigModule;`;return`
59
- ${n}
60
- const { registerRepoConfig } = await import("@gfdelarue/testkit/config");
61
- ${s}
62
- registerRepoConfig(testkitRepositoryConfiguration);${t==="node-vitest-data"?`
54
+ `,s=t==="node-vitest-data"?`
55
+ ${O(e)}
56
+ registerRepoConfig(testkitRepositoryConfiguration);
63
57
  const { __testkitRegisterNodeVitestRepositoryConfiguration } =
64
58
  await import("@gfdelarue/testkit/node-vitest/data");
65
59
  __testkitRegisterNodeVitestRepositoryConfiguration(
66
60
  testkitRepositoryConfiguration,
67
- );`:""}
68
- `}function O(e,t){const n=`const installedRuntimeInput = globalThis[
69
- Symbol.for(${JSON.stringify(p)})
61
+ );`:"registerRepoConfig(null);";return`
62
+ ${n}
63
+ const { registerRepoConfig } = await import("@gfdelarue/testkit/config");
64
+ ${s}
65
+ `}function O(e){return e===null?"const testkitRepositoryConfiguration = null;":`const testkitConfigModule = await import(${JSON.stringify(a(e).href)});
66
+ const testkitRepositoryConfiguration =
67
+ testkitConfigModule.default ??
68
+ testkitConfigModule.config ??
69
+ testkitConfigModule;`}function v(e,t){const n=`const installedRuntimeInput = globalThis[
70
+ Symbol.for(${JSON.stringify(c)})
70
71
  ];
71
72
  if (installedRuntimeInput?.invocationId !== ${JSON.stringify(e.runtimeInput.expectedInvocationId)}
72
73
  || installedRuntimeInput.profileId !== ${JSON.stringify(e.runtimeInput.expectedProfileId)}
73
74
  || installedRuntimeInput.taskId !== ${JSON.stringify(e.runtimeInput.expectedTaskId)})
74
75
  throw new Error("Managed Node/Vitest input bootstrap was not installed in the Vitest parent");`,s=`const configRuntimeSupplier = globalThis[
75
- Symbol.for(${JSON.stringify(u)})
76
+ Symbol.for(${JSON.stringify(p)})
76
77
  ];
77
78
  if (
78
79
  typeof configRuntimeSupplier !== "object" ||
@@ -114,7 +115,7 @@ const {
114
115
  managedTypeScriptFile,
115
116
  } = configRuntime;
116
117
  if (managedTypeScriptFile !== ${JSON.stringify(e.entrypoints.packages.typescript.entrypoint)})
117
- throw new Error("Managed Node/Vitest TypeScript plugin resolved outside its selected installation");`,c=e.tsconfigFile===null?"":`createConsumerTypeScriptPathsPlugin(${JSON.stringify(e.tsconfigFile)}, consumerResolutionPolicy),`;return`
118
+ throw new Error("Managed Node/Vitest TypeScript plugin resolved outside its selected installation");`,d=e.tsconfigFile===null?"":`createConsumerTypeScriptPathsPlugin(${JSON.stringify(e.tsconfigFile)}, consumerResolutionPolicy),`;return`
118
119
  ${n}
119
120
  ${s}
120
121
  const managedAliases = Object.freeze(${JSON.stringify(t.aliases)});
@@ -164,7 +165,7 @@ export default {
164
165
  return id === resolved.id ? resolved : { ...resolved, id };
165
166
  },
166
167
  },
167
- ${c}
168
+ ${d}
168
169
  ],
169
170
  root: ${JSON.stringify(e.rootDirectory)},
170
171
  cacheDir: ${JSON.stringify(i.join(i.dirname(e.vitestConfigFile),"cache"))},
@@ -175,10 +176,10 @@ export default {
175
176
  })),
176
177
  },
177
178
  test: {
178
- ${e.runtimeInput.expectedProfileId==="node-vitest-data"?`runner: ${JSON.stringify(m)},`:""}
179
+ ${e.runtimeInput.expectedProfileId==="node-vitest-data"?`runner: ${JSON.stringify(f)},`:""}
179
180
  // The installed SDK is compiled JavaScript. Use its native module instance
180
181
  // for setup and consumer imports instead of transforming a second instance.
181
- server: { deps: { external: ${JSON.stringify([e.entrypoints.config,...e.runtimeInput.expectedProfileId==="node-vitest-data"?[m,e.entrypoints.data]:[]].map(r=>r.replaceAll(i.sep,"/")))}.map(exactSpecifierPattern) } },
182
+ server: { deps: { external: ${JSON.stringify([e.entrypoints.config,...e.runtimeInput.expectedProfileId==="node-vitest-data"?[f,e.entrypoints.data]:[]].map(r=>r.replaceAll(i.sep,"/")))}.map(exactSpecifierPattern) } },
182
183
  reporters: [[${JSON.stringify(S("node-vitest"))}, ${JSON.stringify(e.report)}]],
183
184
  allowOnly: false,
184
185
  disableConsoleIntercept: true,
@@ -198,4 +199,4 @@ export default {
198
199
  watch: false,
199
200
  },
200
201
  };
201
- `}const v=new Set(["!","(",")","*","+","?","@","[","\\","]","{","}"]);export function toVitestIncludePattern(e){return Array.from(e.replaceAll(i.sep,"/"),t=>v.has(t)?`\\${t}`:t).join("")}
202
+ `}const h=new Set(["!","(",")","*","+","?","@","[","\\","]","{","}"]);export function toVitestIncludePattern(e){return Array.from(e.replaceAll(i.sep,"/"),t=>h.has(t)?`\\${t}`:t).join("")}
@@ -1 +1 @@
1
- import{createHttpMethods as b}from"../../../../config/authoring/http-methods.js";import x from"node:fs";import{parseRuntimeFixtureManifestEntries as g,resolveRuntimeFixtureEntry as N}from"../../../contracts/fixture-manifest.js";import{readNodeVitestRuntimeInput as d}from"../runtime-input.js";import{expect as T,test as C}from"vitest";export{T as expect};const w=Object.freeze({}),E=Object.freeze({env:w});export function contractScenario(t,e,n){const{options:r,run:i}=A(e,n);C(t,async()=>{await i(O())},r.timeoutMs||r.timeout)}export function readContractContext(){const t=d();if(t===null)return E;if(t.profileId!=="node-vitest-contract")throw new Error("Node/Vitest contract API requires node-vitest-contract runtime input");const e={...t.context,env:t.environment,...Object.hasOwn(t,"setupData")?{setupData:t.setupData}:{}};if(!q(e))throw new Error("Node/Vitest contract runtime context is invalid");return Object.freeze(e)}export function createHttpClient(t={}){const e=(t.baseUrl||readContractContext().baseUrl||"").replace(/\/+$/u,"");if(!e)throw new Error("createHttpClient(...) requires baseUrl or the managed Node/Vitest contract context baseUrl");const n=t.defaultHeaders||{"Content-Type":"application/json"};async function r(i,c,y,h={},a={}){const u=i.toUpperCase()||"GET",f=j(y,{contentTypeJson:a.contentTypeJson!==!1}),o=await fetch(`${e}${l(c)}`,{method:u,headers:{...f.body==null?{}:n,...h},body:f.body,signal:a.signal}),p=await o.text();return{body:p,headers:R(o.headers),json(){return JSON.parse(p)},method:u,path:l(c),status:o.status,url:o.url}}return{baseUrl:e,...b(r,void 0),request:r}}function O(){const t=readContractContext();return Object.freeze({...t,fixture(e){return S(e)},http(e={}){return createHttpClient(e)}})}function S(t){const e=z(t),n=x.readFileSync(e.absolutePath);return{buffer(){return Buffer.from(n)},contentType:e.contentType,filename:e.filename,json(){return JSON.parse(n.toString("utf8"))},path:e.path,sha256:e.sha256,sizeBytes:e.sizeBytes,text(r="utf8"){return n.toString(r)}}}function z(t){const e=M(t,"fixture name"),n=U();return N(n.entries,e)}function U(){const t=d();return t===null?{entries:[]}:{entries:g(t.fixtures,"Node/Vitest contract fixture manifest")}}function j(t,e){if(t==null)return{body:void 0};if(typeof t=="string")return{body:t};if(t instanceof Uint8Array){const n=new Uint8Array(t.byteLength);return n.set(t),{body:n}}if(e.contentTypeJson)return{body:JSON.stringify(t)};throw new TypeError("Non-JSON contract request bodies must be strings or Uint8Array values")}function l(t){const e=t||"/";return e.startsWith("/")?e:`/${e}`}function R(t){const e={};for(const[n,r]of t.entries())e[n.toLowerCase()]=r;return e}function A(t,e){if(typeof t=="function")return{options:{},run:t};if(typeof e!="function")throw new Error("contractScenario(name, options?, run) requires a callback");return{options:t,run:e}}function M(t,e){const n=typeof t=="string"?t.trim():"";if(!n)throw new Error(`${e} is required`);return n}function q(t){return!s(t)||t.engineId!=="node-vitest"||t.profileId!=="node-vitest-contract"||!F(t.env)||"runner"in t||t.baseUrl!==void 0&&t.baseUrl!==null&&typeof t.baseUrl!="string"||t.serviceName!==void 0&&typeof t.serviceName!="string"?!1:I(t.task)}function I(t){return s(t)?!("type"in t)&&t.testType==="contract"&&m(t.file)&&J(t.id)&&m(t.suiteName):!1}function m(t){return t===void 0||typeof t=="string"}function J(t){return t===void 0||typeof t=="string"||typeof t=="number"}function s(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function F(t){return s(t)&&Object.values(t).every(e=>typeof e=="string")}
1
+ import{createHttpMethods as x}from"../../../../config/authoring/http-methods.js";import b from"node:fs";import{parseRuntimeFixtureManifestEntries as g,resolveRuntimeFixtureEntry as N}from"../../../contracts/fixture-manifest.js";import{readNodeVitestRuntimeInput as d}from"../runtime-input.js";import{expect as T,test as C}from"vitest";import{isUnknownRecord as s}from"../../../../kernel/unknown-values.js";export{T as expect};const w=Object.freeze({}),E=Object.freeze({env:w});export function contractScenario(t,e,n){const{options:r,run:i}=M(e,n);C(t,async()=>{await i(O())},r.timeoutMs||r.timeout)}export function readContractContext(){const t=d();if(t===null)return E;if(t.profileId!=="node-vitest-contract")throw new Error("Node/Vitest contract API requires node-vitest-contract runtime input");const e={...t.context,env:t.environment,...Object.hasOwn(t,"setupData")?{setupData:t.setupData}:{}};if(!A(e))throw new Error("Node/Vitest contract runtime context is invalid");return Object.freeze(e)}export function createHttpClient(t={}){const e=(t.baseUrl||readContractContext().baseUrl||"").replace(/\/+$/u,"");if(!e)throw new Error("createHttpClient(...) requires baseUrl or the managed Node/Vitest contract context baseUrl");const n=t.defaultHeaders||{"Content-Type":"application/json"};async function r(i,c,y,h={},a={}){const u=i.toUpperCase()||"GET",f=j(y,{contentTypeJson:a.contentTypeJson!==!1}),o=await fetch(`${e}${l(c)}`,{method:u,headers:{...f.body==null?{}:n,...h},body:f.body,signal:a.signal}),p=await o.text();return{body:p,headers:R(o.headers),json(){return JSON.parse(p)},method:u,path:l(c),status:o.status,url:o.url}}return{baseUrl:e,...x(r,void 0),request:r}}function O(){const t=readContractContext();return Object.freeze({...t,fixture(e){return S(e)},http(e={}){return createHttpClient(e)}})}function S(t){const e=U(t),n=b.readFileSync(e.absolutePath);return{buffer(){return Buffer.from(n)},contentType:e.contentType,filename:e.filename,json(){return JSON.parse(n.toString("utf8"))},path:e.path,sha256:e.sha256,sizeBytes:e.sizeBytes,text(r="utf8"){return n.toString(r)}}}function U(t){const e=q(t,"fixture name"),n=z();return N(n.entries,e)}function z(){const t=d();return t===null?{entries:[]}:{entries:g(t.fixtures,"Node/Vitest contract fixture manifest")}}function j(t,e){if(t==null)return{body:void 0};if(typeof t=="string")return{body:t};if(t instanceof Uint8Array){const n=new Uint8Array(t.byteLength);return n.set(t),{body:n}}if(e.contentTypeJson)return{body:JSON.stringify(t)};throw new TypeError("Non-JSON contract request bodies must be strings or Uint8Array values")}function l(t){const e=t||"/";return e.startsWith("/")?e:`/${e}`}function R(t){const e={};for(const[n,r]of t.entries())e[n.toLowerCase()]=r;return e}function M(t,e){if(typeof t=="function")return{options:{},run:t};if(typeof e!="function")throw new Error("contractScenario(name, options?, run) requires a callback");return{options:t,run:e}}function q(t,e){const n=typeof t=="string"?t.trim():"";if(!n)throw new Error(`${e} is required`);return n}function A(t){return!s(t)||t.engineId!=="node-vitest"||t.profileId!=="node-vitest-contract"||!k(t.env)||"runner"in t||t.baseUrl!==void 0&&t.baseUrl!==null&&typeof t.baseUrl!="string"||t.serviceName!==void 0&&typeof t.serviceName!="string"?!1:I(t.task)}function I(t){return s(t)?!("type"in t)&&t.testType==="contract"&&m(t.file)&&J(t.id)&&m(t.suiteName):!1}function m(t){return t===void 0||typeof t=="string"}function J(t){return t===void 0||typeof t=="string"||typeof t=="number"}function k(t){return s(t)&&Object.values(t).every(e=>typeof e=="string")}
@@ -1 +1 @@
1
- import{stringFromUnknown as _}from"./primitives.js";import{createHttpMethods as b}from"../../../../config/authoring/http-methods.js";import{resolveHttpProfile as F}from"../../../../config/authoring/runtime.js";import{readNodeVitestRuntimeInput as G}from"../runtime-input.js";export function createHttpClient(e={}){const t=(e.baseUrl??readDataContext().baseUrl??"").replace(/\/+$/u,"");if(!t)throw new Error("createHttpClient(...) requires baseUrl or the managed Node/Vitest data context baseUrl");const n=e.recorder||e.trace||null,o=e.defaultHeaders||{"Content-Type":"application/json"},r=e.sessionBundle||null,i=e.defaultActor||r?.primaryActor||null,c=typeof e.getHeaders=="function"?e.getHeaders:null,s=typeof e.getRawHeaders=="function"?e.getRawHeaders:c;async function u(a,f,w,d,E,A={},g={}){O(r,a);const k=w.trim()===""?"GET":w.toUpperCase(),D=`${t}${x(d)}`,H=v(E,{contentTypeJson:g.contentTypeJson!==!1}),$={actor:a&&r?r.actors[a]??null:null,actorName:a,sessionBundle:r},S={...H.body==null?{}:o,...y(f?s:c,$),...A},L=Date.now(),h=await fetch(D,{method:k,headers:S,body:H.body,signal:g.signal}),T=await h.text(),P=Date.now()-L,M=j(h.headers),J={body:T,cookies:C(h.headers),durationMs:P,headers:M,json(){return JSON.parse(T)},method:k,path:x(d),status:h.status,url:D};return n&&n.recordHttpRequest({bodyBytes:ie(H.body),durationMs:P,method:k,path:x(d),requestHeaders:S,responseBytes:Buffer.byteLength(T),status:h.status}),J}const p=m(null,!0),R=b(p,void 0),N=Object.assign(p,{as:B,get:R.get,post:R.post}),U=m(i,!1);return{...b(U,void 0),baseUrl:t,headers(a={}){return{...y(c,{actorName:i,actor:V(r,i),sessionBundle:r}),...a}},rawHeaders(a={}){return{...y(s,{actorName:i,actor:V(r,i),sessionBundle:r}),...a}},raw:N,rawReq:N,request:U,as:I};function m(a,f){return(w,d,E,A,g)=>u(a,f,w,d,E,A,g)}function I(a){O(r,a);const f=m(a,!1),w=B(a);return{...b(f,void 0),headers(d={}){return{...y(c,{actorName:a,actor:r?r.actors[a]??null:null,sessionBundle:r}),...d}},rawHeaders(d={}){return{...y(s,{actorName:a,actor:r?r.actors[a]??null:null,sessionBundle:r}),...d}},raw:w,rawReq:w,request:f}}function B(a){const f=m(a,!0);return Object.assign(f,b(f,void 0))}}export function readDataContext(){const e=G();if(e===null)return ne;if(e.profileId!=="node-vitest-data")throw new Error("Node/Vitest data API requires node-vitest-data runtime input");return te({...e.context,env:e.environment,...Object.hasOwn(e,"setupData")?{setupData:e.setupData}:{}})}export async function createDataHttpClient(e={}){if(!e.profile)return createHttpClient(e);const t=F(e.profile);if(!t)throw new Error(`Data HTTP profile "${e.profile}" is unavailable because no repo config is registered`);const n=Y(t,e),o=X(n),r=await W(n.auth,o,e.profile),i=createHttpClient({...e,baseUrl:o.BASE,...r?.primaryActor?{defaultActor:r.primaryActor}:{},getHeaders(s){return{...n.auth?.headers?.(r,{actor:s.actorName,env:o})??{},...q(n.headers,r,o,s.actorName)}},getRawHeaders(s){return q(n.rawHeaders,r,o,s.actorName)},...r?{sessionBundle:r}:{}}),c=Q(r,i);return{...i,actor:c.actor,actors:c.actors,env:o}}function K(e){return e??null}function Y(e,t){return{...e,...t,auth:t.auth??K(e.auth),headers:t.headers??e.headers,rawHeaders:t.rawHeaders??e.rawHeaders,env:t.env??e.env}}async function W(e,t,n){const o={env:t,http:Z(),json:oe};let r=null;if(typeof e?.setupAsync=="function"?r=await e.setupAsync(o):typeof e?.setup=="function"&&(r=e.setup(o)),r==null)return null;if(!fe(r))throw new Error(`Data HTTP profile "${n??""}" auth setup must return a session bundle with actors and primaryActor`);return r}function q(e,t,n,o){return typeof e!="function"?{}:e(t,{actor:o,env:n})??{}}function X(e){const n={BASE:readDataContext().baseUrl||process.env.BASE_URL},o={...e.env||n,rawEnv:process.env};if(!o.BASE)throw new Error("Data HTTP profile requires BASE_URL or the managed Node/Vitest data context baseUrl");return{...o,BASE:o.BASE,rawEnv:process.env}}function Q(e,t){const n=Object.keys(e?.actors??{}),o=n.map(s=>{const u=e?.actors[s]??null,p=t.as(s);return{email:u?.email||null,headers:p.headers(),index:u?.actorIndex??0,key:s,name:u?.name||null,organizationKey:u?.organizationKey||null,organizationName:u?.organizationName||null,rawHeaders:p.rawHeaders(),rawReq:p.rawReq,req:p,session:u?.session||null}}),r=new Map(o.map(s=>[s.key,s])),i=e?.primaryActor||null,c=i&&r.get(i)||null;return{actor:c,actors:{names:n,primary:c,get(s){const u=r.get(s);if(!u)throw new Error(`Unknown testkit actor "${s}"`);return u},has(s){return r.has(s)},list(){return o.slice()}}}}function Z(){async function e(t,n,o,r={}){const i=se(r),c=await fetch(n,{method:t,headers:i,body:t==="GET"?void 0:ae(o)});return{body:await c.text(),cookies:C(c.headers),headers:j(c.headers),status:c.status}}return{del(t,n,o){return e("DELETE",t,n,o)},get(t,n){return e("GET",t,null,n)},patch(t,n,o){return e("PATCH",t,n,o)},post(t,n,o){return e("POST",t,n,o)},put(t,n,o){return e("PUT",t,n,o)}}}function y(e,t){return typeof e!="function"?{}:e(t)}function O(e,t){if(!(!t||!e)&&!Object.hasOwn(e.actors,t))throw new Error(`Unknown testkit actor "${t}"`)}function x(e){const t=e||"/";return t.startsWith("/")?t:`/${t}`}function v(e,t={}){return e==null?{body:void 0}:typeof e=="string"?{body:e}:e instanceof Uint8Array?{body:Uint8Array.from(e)}:e instanceof URLSearchParams||e instanceof FormData||e instanceof Blob?{body:e}:t.contentTypeJson===!1?{body:z(e)}:{body:JSON.stringify(e)}}function j(e){const t={};for(const[n,o]of e.entries())t[n]=o;return t}function C(e){const t=typeof e.getSetCookie=="function"?e.getSetCookie():ee(e.get("set-cookie")),n={};for(const o of t){const[r]=o.split(";"),i=r.indexOf("=");if(i<=0)continue;const c=r.slice(0,i).trim(),s=r.slice(i+1).trim();n[c]=[{value:s}]}return n}function ee(e){return e?e.split(/,(?=\s*[^;,]+=)/u).map(t=>t.trim()).filter(Boolean):[]}function te(e){if(!l(e))throw new Error("Node/Vitest data context must be an object");if(e.engineId!=="node-vitest")throw new Error('Node/Vitest data context.engineId must be "node-vitest"');if(e.profileId!=="node-vitest-data")throw new Error('Node/Vitest data context.profileId must be "node-vitest-data"');if(!de(e.env))throw new Error("Node/Vitest data context.env must be a string environment record");if("runner"in e)throw new Error("Node/Vitest data context.runner is not supported");const t={...e,env:e.env};if(e.baseUrl!==void 0&&e.baseUrl!==null&&typeof e.baseUrl!="string")throw new Error("Node/Vitest data context.baseUrl must be a string");if(e.serviceName!==void 0&&typeof e.serviceName!="string")throw new Error("Node/Vitest data context.serviceName must be a string");if(!l(e.task))throw new Error("Node/Vitest data context.task must be an object");{const n=e.task.id;if(n!==void 0&&typeof n!="string"&&typeof n!="number")throw new Error("Node/Vitest data context.task.id is invalid");for(const o of["file","suiteName"])if(e.task[o]!==void 0&&typeof e.task[o]!="string")throw new Error(`Node/Vitest data context.task.${o} must be a string`);if(e.task.testType!=="data")throw new Error('Node/Vitest data context.task.testType must be "data"');if("type"in e.task)throw new Error("Node/Vitest data context.task.type is not supported");t.task={...typeof e.task.file=="string"?{file:e.task.file}:{},...n===void 0?{}:{id:n},...typeof e.task.suiteName=="string"?{suiteName:e.task.suiteName}:{},testType:e.task.testType}}return t.engineId=e.engineId,t.profileId=e.profileId,Object.freeze(t)}const re=Object.freeze({}),ne=Object.freeze({env:re});function oe(e){if(!l(e)||typeof e.body!="string")throw new Error("Data HTTP profile response body must be a string");return JSON.parse(e.body)}function se(e){if(e==null)return{};if(!l(e))throw new Error("Data HTTP profile request options must be an object");return e.headers===void 0?{}:ce(e.headers,"Data HTTP profile request headers")}function ae(e){if(e!=null)return z(e)}function ie(e){return e===void 0?0:typeof e=="string"?Buffer.byteLength(e):e instanceof Blob?e.size:e instanceof URLSearchParams?Buffer.byteLength(e.toString()):e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:0}function V(e,t){return t&&e?.actors?e.actors[t]??null:null}function z(e){return typeof e=="string"||e instanceof Blob||e instanceof FormData||e instanceof URLSearchParams||e instanceof ArrayBuffer?e:ArrayBuffer.isView(e)?Uint8Array.from(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)):_(e)}function ce(e,t){if(!l(e))throw new Error(`${t} must be an object`);const n={};for(const[o,r]of Object.entries(e))n[o]=ue(r,`${t}.${o}`);return n}function ue(e,t){if(typeof e!="string"||e.length===0)throw new Error(`${t} must be a non-empty string`);return e}function fe(e){return l(e)&&l(e.actors)&&(e.primaryActor===null||typeof e.primaryActor=="string")}function de(e){return l(e)&&Object.values(e).every(t=>typeof t=="string")}function l(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}
1
+ import{stringFromUnknown as _}from"./primitives.js";import{createHttpMethods as b}from"../../../../config/authoring/http-methods.js";import{resolveHttpProfile as F}from"../../../../config/authoring/runtime.js";import{readNodeVitestRuntimeInput as G}from"../runtime-input.js";import{isUnknownRecord as l}from"../../../../kernel/unknown-values.js";export function createHttpClient(e={}){const t=(e.baseUrl??readDataContext().baseUrl??"").replace(/\/+$/u,"");if(!t)throw new Error("createHttpClient(...) requires baseUrl or the managed Node/Vitest data context baseUrl");const n=e.recorder||e.trace||null,o=e.defaultHeaders||{"Content-Type":"application/json"},r=e.sessionBundle||null,i=e.defaultActor||r?.primaryActor||null,c=typeof e.getHeaders=="function"?e.getHeaders:null,s=typeof e.getRawHeaders=="function"?e.getRawHeaders:c;async function u(a,f,w,d,E,k={},g={}){O(r,a);const A=w.trim()===""?"GET":w.toUpperCase(),D=`${t}${x(d)}`,H=v(E,{contentTypeJson:g.contentTypeJson!==!1}),$={actor:a&&r?r.actors[a]??null:null,actorName:a,sessionBundle:r},S={...H.body==null?{}:o,...m(f?s:c,$),...k},L=Date.now(),h=await fetch(D,{method:A,headers:S,body:H.body,signal:g.signal}),T=await h.text(),P=Date.now()-L,M=C(h.headers),J={body:T,cookies:V(h.headers),durationMs:P,headers:M,json(){return JSON.parse(T)},method:A,path:x(d),status:h.status,url:D};return n&&n.recordHttpRequest({bodyBytes:ie(H.body),durationMs:P,method:A,path:x(d),requestHeaders:S,responseBytes:Buffer.byteLength(T),status:h.status}),J}const p=y(null,!0),R=b(p,void 0),U=Object.assign(p,{as:B,get:R.get,post:R.post}),N=y(i,!1);return{...b(N,void 0),baseUrl:t,headers(a={}){return{...m(c,{actorName:i,actor:j(r,i),sessionBundle:r}),...a}},rawHeaders(a={}){return{...m(s,{actorName:i,actor:j(r,i),sessionBundle:r}),...a}},raw:U,rawReq:U,request:N,as:I};function y(a,f){return(w,d,E,k,g)=>u(a,f,w,d,E,k,g)}function I(a){O(r,a);const f=y(a,!1),w=B(a);return{...b(f,void 0),headers(d={}){return{...m(c,{actorName:a,actor:r?r.actors[a]??null:null,sessionBundle:r}),...d}},rawHeaders(d={}){return{...m(s,{actorName:a,actor:r?r.actors[a]??null:null,sessionBundle:r}),...d}},raw:w,rawReq:w,request:f}}function B(a){const f=y(a,!0);return Object.assign(f,b(f,void 0))}}export function readDataContext(){const e=G();if(e===null)return ne;if(e.profileId!=="node-vitest-data")throw new Error("Node/Vitest data API requires node-vitest-data runtime input");return te({...e.context,env:e.environment,...Object.hasOwn(e,"setupData")?{setupData:e.setupData}:{}})}export async function createDataHttpClient(e={}){if(!e.profile)return createHttpClient(e);const t=F(e.profile);if(!t)throw new Error(`Data HTTP profile "${e.profile}" is unavailable because no repo config is registered`);const n=Y(t,e),o=X(n),r=await W(n.auth,o,e.profile),i=createHttpClient({...e,baseUrl:o.BASE,...r?.primaryActor?{defaultActor:r.primaryActor}:{},getHeaders(s){return{...n.auth?.headers?.(r,{actor:s.actorName,env:o})??{},...q(n.headers,r,o,s.actorName)}},getRawHeaders(s){return q(n.rawHeaders,r,o,s.actorName)},...r?{sessionBundle:r}:{}}),c=Q(r,i);return{...i,actor:c.actor,actors:c.actors,env:o}}function K(e){return e??null}function Y(e,t){return{...e,...t,auth:t.auth??K(e.auth),headers:t.headers??e.headers,rawHeaders:t.rawHeaders??e.rawHeaders,env:t.env??e.env}}async function W(e,t,n){const o={env:t,http:Z(),json:oe};let r=null;if(typeof e?.setupAsync=="function"?r=await e.setupAsync(o):typeof e?.setup=="function"&&(r=e.setup(o)),r==null)return null;if(!fe(r))throw new Error(`Data HTTP profile "${n??""}" auth setup must return a session bundle with actors and primaryActor`);return r}function q(e,t,n,o){return typeof e!="function"?{}:e(t,{actor:o,env:n})??{}}function X(e){const n={BASE:readDataContext().baseUrl||process.env.BASE_URL},o={...e.env||n,rawEnv:process.env};if(!o.BASE)throw new Error("Data HTTP profile requires BASE_URL or the managed Node/Vitest data context baseUrl");return{...o,BASE:o.BASE,rawEnv:process.env}}function Q(e,t){const n=Object.keys(e?.actors??{}),o=n.map(s=>{const u=e?.actors[s]??null,p=t.as(s);return{email:u?.email||null,headers:p.headers(),index:u?.actorIndex??0,key:s,name:u?.name||null,organizationKey:u?.organizationKey||null,organizationName:u?.organizationName||null,rawHeaders:p.rawHeaders(),rawReq:p.rawReq,req:p,session:u?.session||null}}),r=new Map(o.map(s=>[s.key,s])),i=e?.primaryActor||null,c=i&&r.get(i)||null;return{actor:c,actors:{names:n,primary:c,get(s){const u=r.get(s);if(!u)throw new Error(`Unknown testkit actor "${s}"`);return u},has(s){return r.has(s)},list(){return o.slice()}}}}function Z(){async function e(t,n,o,r={}){const i=se(r),c=await fetch(n,{method:t,headers:i,body:t==="GET"?void 0:ae(o)});return{body:await c.text(),cookies:V(c.headers),headers:C(c.headers),status:c.status}}return{del(t,n,o){return e("DELETE",t,n,o)},get(t,n){return e("GET",t,null,n)},patch(t,n,o){return e("PATCH",t,n,o)},post(t,n,o){return e("POST",t,n,o)},put(t,n,o){return e("PUT",t,n,o)}}}function m(e,t){return typeof e!="function"?{}:e(t)}function O(e,t){if(!(!t||!e)&&!Object.hasOwn(e.actors,t))throw new Error(`Unknown testkit actor "${t}"`)}function x(e){const t=e||"/";return t.startsWith("/")?t:`/${t}`}function v(e,t={}){return e==null?{body:void 0}:typeof e=="string"?{body:e}:e instanceof Uint8Array?{body:Uint8Array.from(e)}:e instanceof URLSearchParams||e instanceof FormData||e instanceof Blob?{body:e}:t.contentTypeJson===!1?{body:z(e)}:{body:JSON.stringify(e)}}function C(e){const t={};for(const[n,o]of e.entries())t[n]=o;return t}function V(e){const t=typeof e.getSetCookie=="function"?e.getSetCookie():ee(e.get("set-cookie")),n={};for(const o of t){const[r]=o.split(";"),i=r.indexOf("=");if(i<=0)continue;const c=r.slice(0,i).trim(),s=r.slice(i+1).trim();n[c]=[{value:s}]}return n}function ee(e){return e?e.split(/,(?=\s*[^;,]+=)/u).map(t=>t.trim()).filter(Boolean):[]}function te(e){if(!l(e))throw new Error("Node/Vitest data context must be an object");if(e.engineId!=="node-vitest")throw new Error('Node/Vitest data context.engineId must be "node-vitest"');if(e.profileId!=="node-vitest-data")throw new Error('Node/Vitest data context.profileId must be "node-vitest-data"');if(!de(e.env))throw new Error("Node/Vitest data context.env must be a string environment record");if("runner"in e)throw new Error("Node/Vitest data context.runner is not supported");const t={...e,env:e.env};if(e.baseUrl!==void 0&&e.baseUrl!==null&&typeof e.baseUrl!="string")throw new Error("Node/Vitest data context.baseUrl must be a string");if(e.serviceName!==void 0&&typeof e.serviceName!="string")throw new Error("Node/Vitest data context.serviceName must be a string");if(!l(e.task))throw new Error("Node/Vitest data context.task must be an object");{const n=e.task.id;if(n!==void 0&&typeof n!="string"&&typeof n!="number")throw new Error("Node/Vitest data context.task.id is invalid");for(const o of["file","suiteName"])if(e.task[o]!==void 0&&typeof e.task[o]!="string")throw new Error(`Node/Vitest data context.task.${o} must be a string`);if(e.task.testType!=="data")throw new Error('Node/Vitest data context.task.testType must be "data"');if("type"in e.task)throw new Error("Node/Vitest data context.task.type is not supported");t.task={...typeof e.task.file=="string"?{file:e.task.file}:{},...n===void 0?{}:{id:n},...typeof e.task.suiteName=="string"?{suiteName:e.task.suiteName}:{},testType:e.task.testType}}return t.engineId=e.engineId,t.profileId=e.profileId,Object.freeze(t)}const re=Object.freeze({}),ne=Object.freeze({env:re});function oe(e){if(!l(e)||typeof e.body!="string")throw new Error("Data HTTP profile response body must be a string");return JSON.parse(e.body)}function se(e){if(e==null)return{};if(!l(e))throw new Error("Data HTTP profile request options must be an object");return e.headers===void 0?{}:ce(e.headers,"Data HTTP profile request headers")}function ae(e){if(e!=null)return z(e)}function ie(e){return e===void 0?0:typeof e=="string"?Buffer.byteLength(e):e instanceof Blob?e.size:e instanceof URLSearchParams?Buffer.byteLength(e.toString()):e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:0}function j(e,t){return t&&e?.actors?e.actors[t]??null:null}function z(e){return typeof e=="string"||e instanceof Blob||e instanceof FormData||e instanceof URLSearchParams||e instanceof ArrayBuffer?e:ArrayBuffer.isView(e)?Uint8Array.from(new Uint8Array(e.buffer,e.byteOffset,e.byteLength)):_(e)}function ce(e,t){if(!l(e))throw new Error(`${t} must be an object`);const n={};for(const[o,r]of Object.entries(e))n[o]=ue(r,`${t}.${o}`);return n}function ue(e,t){if(typeof e!="string"||e.length===0)throw new Error(`${t} must be a non-empty string`);return e}function fe(e){return l(e)&&l(e.actors)&&(e.primaryActor===null||typeof e.primaryActor=="string")}function de(e){return l(e)&&Object.values(e).every(t=>typeof t=="string")}
@@ -4,5 +4,5 @@ export declare function __testkitRegisterNodeVitestRepositoryConfiguration(confi
4
4
  export { expect } from "vitest";
5
5
  export { createHttpClient, readDataContext } from "./http.js";
6
6
  export { renderDataFlowMarkdown } from "./report.js";
7
- export { createDataTrace, dataScenario, measureJsonBytes, stableHash } from "./scenario.js";
8
- export type { DataActorHttpClient, DataActorRawRequest, DataActorSession, DataBaselineBudgetOptions, DataBudgetOptions, DataEvidenceDetails, DataExternalCallDetails, DataFixture, DataFlowReport, DataHttpActor, DataHttpActors, DataHttpClient, DataHttpClientOptions, DataHttpHeaderBuilder, DataHttpHeaderContext, DataHttpProfileAuth, DataHttpProfileOptions, DataHttpRecorder, DataHttpRequestOptions, DataHttpRequestRecord, DataHttpResponse, DataMetricBudget, DataMetricOptions, DataRootRawRequest, DataRuntimeContext, DataScenarioContext, DataScenarioOptions, DataScenarioReport, DataSequenceBudget, DataSequenceOptions, DataSessionBundle, } from "./types.js";
7
+ export { dataScenario, measureJsonBytes, stableHash } from "./scenario.js";
8
+ export type { DataActorHttpClient, DataActorRawRequest, DataActorSession, DataBudgetOptions, DataEvidenceDetails, DataExternalCallDetails, DataFixture, DataFlowReport, DataHttpActor, DataHttpActors, DataHttpClient, DataHttpClientOptions, DataHttpHeaderBuilder, DataHttpHeaderContext, DataHttpProfileAuth, DataHttpProfileOptions, DataHttpRecorder, DataHttpRequestOptions, DataHttpRequestRecord, DataHttpResponse, DataMetricBudget, DataMetricOptions, DataRootRawRequest, DataRuntimeContext, DataScenarioContext, DataScenarioOptions, DataScenarioReport, DataSequenceBudget, DataSequenceOptions, DataSessionBundle, } from "./types.js";
@@ -1 +1 @@
1
- import{afterAll as e}from"vitest";import{registerRepoConfig as o}from"../../../../config/authoring/runtime.js";import{emitDataFlowArtifacts as r}from"./report.js";import{dataFlowState as a,finalizeDataFlowState as i}from"./scenario.js";e(()=>{i(),r(a())});export function __testkitRegisterNodeVitestRepositoryConfiguration(t){o(t)}export{expect}from"vitest";export{createHttpClient,readDataContext}from"./http.js";export{renderDataFlowMarkdown}from"./report.js";export{createDataTrace,dataScenario,measureJsonBytes,stableHash}from"./scenario.js";
1
+ import{afterAll as e}from"vitest";import{registerRepoConfig as o}from"../../../../config/authoring/runtime.js";import{emitDataFlowArtifacts as r}from"./report.js";import{dataFlowState as a,finalizeDataFlowState as i}from"./scenario.js";e(()=>{i(),r(a())});export function __testkitRegisterNodeVitestRepositoryConfiguration(t){o(t)}export{expect}from"vitest";export{createHttpClient,readDataContext}from"./http.js";export{renderDataFlowMarkdown}from"./report.js";export{dataScenario,measureJsonBytes,stableHash}from"./scenario.js";
@@ -1,6 +1,6 @@
1
- import{stringFromUnknown as h}from"./primitives.js";import i from"node:fs";import p from"node:path";import{NODE_VITEST_DATA_BUDGET_FAILURE_DETAIL_KIND as m,NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_KIND as g,NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_NAME as l}from"../runtime-input.js";import{DATA_ARTIFACT_KIND as d,DATA_REPORT_KIND as T,DATA_SCHEMA_VERSION as S}from"./types.js";export function emitDataFlowArtifacts(t){const n=process.env.TESTKIT_DATA_ARTIFACT_DIR;if(!n||t.emitted)return;t.emitted=!0,i.mkdirSync(n,{recursive:!0});const e=E(t),r=$(e),u=p.join(n,"data-flow.json"),o=p.join(n,"data-flow.md"),s=p.join(n,"failure-details.json"),c=p.join(n,"manifest.json");i.writeFileSync(u,`${JSON.stringify(e,null,2)}
1
+ import{stringFromUnknown as m}from"./primitives.js";import i from"node:fs";import p from"node:path";import{NODE_VITEST_DATA_BUDGET_FAILURE_DETAIL_KIND as h,NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_KIND as g,NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_NAME as l}from"../runtime-input.js";import{DATA_ARTIFACT_KIND as d,DATA_REPORT_KIND as T,DATA_SCHEMA_VERSION as S}from"./types.js";import{isUnknownArray as $,isUnknownRecord as y}from"../../../../kernel/unknown-values.js";export function emitDataFlowArtifacts(t){const n=process.env.TESTKIT_DATA_ARTIFACT_DIR;if(!n||t.emitted)return;t.emitted=!0,i.mkdirSync(n,{recursive:!0});const e=E(t),s=A(e),u=p.join(n,"data-flow.json"),o=p.join(n,"data-flow.md"),r=p.join(n,"failure-details.json"),c=p.join(n,"manifest.json");i.writeFileSync(u,`${JSON.stringify(e,null,2)}
2
2
  `),i.writeFileSync(o,`${renderDataFlowMarkdown(e)}
3
- `),r!==null&&i.writeFileSync(s,`${JSON.stringify(r,null,2)}
4
- `),i.writeFileSync(c,`${JSON.stringify({schemaVersion:1,artifacts:[{contentType:"application/json",kind:d,name:"data-flow",path:u,summary:e.summaryText},{contentType:"text/markdown",kind:T,name:"data-flow-report",path:o,summary:e.summaryText},...r===null?[]:[{contentType:"application/json",kind:g,name:l,path:s,summary:`${String(r.failures.length)} failed data-flow budget${r.failures.length===1?"":"s"}`}]]},null,2)}
5
- `)}function $(t){const n=t.scenarios.flatMap(e=>e.budgetFailures.map(r=>{const u=`${r.target} budget "${r.name}" (${r.operator})`;return{actual:f(r.actual,`${e.name} ${r.name} actual value`),checkName:r.name,count:1,expected:f(r.expected,`${e.name} ${r.name} expected value`),groupPath:[e.name],key:`${e.name} > ${u}`,kind:m,message:r.message,title:u}}));return n.length===0?null:{failures:n,phase:"exec"}}function f(t,n){let e;try{e=JSON.stringify(t)}catch(u){throw new TypeError(`${n} must be JSON-serializable`,{cause:u})}const r=JSON.parse(e);if(!y(r))throw new TypeError(`${n} must be a finite JSON value`);return r}function y(t){const n=[t];for(;n.length>0;){const e=n.pop();if(!(e===null||typeof e=="boolean"||typeof e=="string")){if(typeof e=="number"){if(!Number.isFinite(e))return!1;continue}if(D(e)){n.push(...e);continue}if(!A(e))return!1;n.push(...Object.values(e))}}return!0}function A(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function D(t){return Array.isArray(t)}function E(t){const n=t.scenarios.map(s=>({budgetFailures:s.budgetFailures,budgets:s.budgetResults,description:s.description,durationMs:Math.max(0,(s.finishedAtMs||Date.now())-s.startedAtMs),error:s.error,evidence:s.evidence,events:s.events,findings:s.findings,metrics:s.metrics,name:s.name,sequences:s.sequences,status:s.status==="running"?"failed":s.status})),e=n.filter(s=>s.status==="failed").length,r=n.reduce((s,c)=>s+c.budgetFailures.length,0),u=k(n.flatMap(s=>s.findings)),o=`${String(n.length-e)}/${String(n.length)} data scenario(s) passed, ${String(r)} budget failure(s)`;return{schemaVersion:S,kind:d,generatedAt:new Date().toISOString(),file:process.env.TESTKIT_TEST_FILE||null,taskId:process.env.TESTKIT_TEST_ID||null,summary:{budgetFailures:r,failed:e,findingCounts:u,passed:n.length-e,scenarios:n.length,status:e>0?"failed":"passed"},summaryText:o,scenarios:n}}export function renderDataFlowMarkdown(t){const n=[];n.push("# Data Flow Report"),n.push(""),n.push(`Status: ${t.summary.status}`),n.push(`Scenarios: ${String(t.summary.passed)}/${String(t.summary.scenarios)} passed`),n.push(`Budget failures: ${String(t.summary.budgetFailures)}`),n.push("");for(const e of t.scenarios)n.push(`## ${e.name}`),n.push(""),n.push(`Status: ${e.status}`),n.push(`Duration: ${String(e.durationMs)}ms`),e.description&&n.push(`Description: ${e.description}`),e.error?.message&&n.push(`Error: ${e.error.message}`),n.push(""),_(n,e.metrics),w(n,e.sequences),b(n,e.evidence),F(n,e.budgets),I(n,e.findings);return n.join(`
6
- `).trimEnd()}function b(t,n){if(t.push("### Evidence"),n.length===0){t.push(""),t.push("No structured data-flow evidence recorded."),t.push("");return}t.push(""),t.push("| Kind | Name | Status | Details |"),t.push("| --- | --- | --- | --- |");for(const e of n)t.push(`| ${a(e.kind)} | ${a(e.name)} | ${a(e.status||"")} | ${a(N(e.details))} |`);t.push("")}function _(t,n){if(t.push("### Metrics"),n.length===0){t.push(""),t.push("No metrics recorded."),t.push("");return}t.push(""),t.push("| Metric | Value | Unit | Kind |"),t.push("| --- | ---: | --- | --- |");for(const e of n)t.push(`| ${a(e.name)} | ${O(e.value)} | ${a(e.unit||"")} | ${a(e.kind||"")} |`);t.push("")}function w(t,n){if(t.push("### Sequences"),n.length===0){t.push(""),t.push("No sequences recorded."),t.push("");return}t.push(""),t.push("| Sequence | Values |"),t.push("| --- | --- |");for(const e of n)t.push(`| ${a(e.name)} | ${a(e.values.join(" -> "))} |`);t.push("")}function F(t,n){if(t.push("### Budgets"),n.length===0){t.push(""),t.push("No budgets declared."),t.push("");return}t.push("");for(const e of n)t.push(`- ${e.status.toUpperCase()} ${e.name}: ${e.message}`);t.push("")}function I(t,n){if(t.push("### Findings"),n.length===0){t.push(""),t.push("No findings recorded."),t.push("");return}t.push("");for(const e of n)t.push(`- ${e.severity.toUpperCase()}: ${e.message}`);t.push("")}function N(t){const n=Object.entries(t||{}).filter(([e])=>e!=="status").slice(0,6);return n.length===0?"":n.map(([e,r])=>`${e}: ${j(r)}`).join(", ")}function j(t){return t==null?"":typeof t=="string"||typeof t=="number"||typeof t=="boolean"?String(t):JSON.stringify(t)}function k(t){const n={info:0,watch:0,waste:0,error:0};for(const e of t)n[e.severity]+=1;return n}function a(t){return h(t??"").replaceAll("|","\\|").replace(/\s+/gu," ").trim()}function O(t){return Number.isInteger(t)?String(t):String(Number(t.toFixed(4)))}
3
+ `),s!==null&&i.writeFileSync(r,`${JSON.stringify(s,null,2)}
4
+ `),i.writeFileSync(c,`${JSON.stringify({schemaVersion:1,artifacts:[{contentType:"application/json",kind:d,name:"data-flow",path:u,summary:e.summaryText},{contentType:"text/markdown",kind:T,name:"data-flow-report",path:o,summary:e.summaryText},...s===null?[]:[{contentType:"application/json",kind:g,name:l,path:r,summary:`${String(s.failures.length)} failed data-flow budget${s.failures.length===1?"":"s"}`}]]},null,2)}
5
+ `)}function A(t){const n=t.scenarios.flatMap(e=>e.budgetFailures.map(s=>{const u=`${s.target} budget "${s.name}" (${s.operator})`;return{actual:f(s.actual,`${e.name} ${s.name} actual value`),checkName:s.name,count:1,expected:f(s.expected,`${e.name} ${s.name} expected value`),groupPath:[e.name],key:`${e.name} > ${u}`,kind:h,message:s.message,title:u}}));return n.length===0?null:{failures:n,phase:"exec"}}function f(t,n){let e;try{e=JSON.stringify(t)}catch(u){throw new TypeError(`${n} must be JSON-serializable`,{cause:u})}const s=JSON.parse(e);if(!D(s))throw new TypeError(`${n} must be a finite JSON value`);return s}function D(t){const n=[t];for(;n.length>0;){const e=n.pop();if(!(e===null||typeof e=="boolean"||typeof e=="string")){if(typeof e=="number"){if(!Number.isFinite(e))return!1;continue}if($(e)){n.push(...e);continue}if(!y(e))return!1;n.push(...Object.values(e))}}return!0}function E(t){const n=t.scenarios.map(r=>({budgetFailures:r.budgetFailures,budgets:r.budgetResults,description:r.description,durationMs:Math.max(0,(r.finishedAtMs||Date.now())-r.startedAtMs),error:r.error,evidence:r.evidence,events:r.events,findings:r.findings,metrics:r.metrics,name:r.name,sequences:r.sequences,status:r.status==="running"?"failed":r.status})),e=n.filter(r=>r.status==="failed").length,s=n.reduce((r,c)=>r+c.budgetFailures.length,0),u=O(n.flatMap(r=>r.findings)),o=`${String(n.length-e)}/${String(n.length)} data scenario(s) passed, ${String(s)} budget failure(s)`;return{schemaVersion:S,kind:d,generatedAt:new Date().toISOString(),file:process.env.TESTKIT_TEST_FILE||null,taskId:process.env.TESTKIT_TEST_ID||null,summary:{budgetFailures:s,failed:e,findingCounts:u,passed:n.length-e,scenarios:n.length,status:e>0?"failed":"passed"},summaryText:o,scenarios:n}}export function renderDataFlowMarkdown(t){const n=[];n.push("# Data Flow Report"),n.push(""),n.push(`Status: ${t.summary.status}`),n.push(`Scenarios: ${String(t.summary.passed)}/${String(t.summary.scenarios)} passed`),n.push(`Budget failures: ${String(t.summary.budgetFailures)}`),n.push("");for(const e of t.scenarios)n.push(`## ${e.name}`),n.push(""),n.push(`Status: ${e.status}`),n.push(`Duration: ${String(e.durationMs)}ms`),e.description&&n.push(`Description: ${e.description}`),e.error?.message&&n.push(`Error: ${e.error.message}`),n.push(""),b(n,e.metrics),w(n,e.sequences),_(n,e.evidence),F(n,e.budgets),I(n,e.findings);return n.join(`
6
+ `).trimEnd()}function _(t,n){if(t.push("### Evidence"),n.length===0){t.push(""),t.push("No structured data-flow evidence recorded."),t.push("");return}t.push(""),t.push("| Kind | Name | Status | Details |"),t.push("| --- | --- | --- | --- |");for(const e of n)t.push(`| ${a(e.kind)} | ${a(e.name)} | ${a(e.status||"")} | ${a(N(e.details))} |`);t.push("")}function b(t,n){if(t.push("### Metrics"),n.length===0){t.push(""),t.push("No metrics recorded."),t.push("");return}t.push(""),t.push("| Metric | Value | Unit | Kind |"),t.push("| --- | ---: | --- | --- |");for(const e of n)t.push(`| ${a(e.name)} | ${j(e.value)} | ${a(e.unit||"")} | ${a(e.kind||"")} |`);t.push("")}function w(t,n){if(t.push("### Sequences"),n.length===0){t.push(""),t.push("No sequences recorded."),t.push("");return}t.push(""),t.push("| Sequence | Values |"),t.push("| --- | --- |");for(const e of n)t.push(`| ${a(e.name)} | ${a(e.values.join(" -> "))} |`);t.push("")}function F(t,n){if(t.push("### Budgets"),n.length===0){t.push(""),t.push("No budgets declared."),t.push("");return}t.push("");for(const e of n)t.push(`- ${e.status.toUpperCase()} ${e.name}: ${e.message}`);t.push("")}function I(t,n){if(t.push("### Findings"),n.length===0){t.push(""),t.push("No findings recorded."),t.push("");return}t.push("");for(const e of n)t.push(`- ${e.severity.toUpperCase()}: ${e.message}`);t.push("")}function N(t){const n=Object.entries(t||{}).filter(([e])=>e!=="status").slice(0,6);return n.length===0?"":n.map(([e,s])=>`${e}: ${k(s)}`).join(", ")}function k(t){return t==null?"":typeof t=="string"||typeof t=="number"||typeof t=="boolean"?String(t):JSON.stringify(t)}function O(t){const n={info:0,watch:0,waste:0,error:0};for(const e of t)n[e.severity]+=1;return n}function a(t){return m(t??"").replaceAll("|","\\|").replace(/\s+/gu," ").trim()}function j(t){return Number.isInteger(t)?String(t):String(Number(t.toFixed(4)))}
@@ -5,7 +5,6 @@ declare global {
5
5
  export declare function isDataScenarioCase(task: object): boolean;
6
6
  export declare function dataScenario(name: string, run: (context: DataScenarioContext) => unknown): void;
7
7
  export declare function dataScenario(name: string, options: DataScenarioOptions, run: (context: DataScenarioContext) => unknown): void;
8
- export declare function createDataTrace(name?: string): DataScenarioContext;
9
8
  export declare function measureJsonBytes(value: unknown): number;
10
9
  export declare function stableHash(value: unknown): string;
11
10
  export declare function dataFlowState(): DataFlowState;
@@ -1,2 +1,2 @@
1
- import{stringFromUnknown as h}from"./primitives.js";import E from"node:crypto";import F from"node:fs";import{parseRuntimeFixtureManifestEntries as M,resolveRuntimeFixtureEntry as v}from"../../../contracts/fixture-manifest.js";import{readNodeVitestRuntimeInput as N}from"../runtime-input.js";import{TestRunner as R,test as O}from"vitest";import{createDataHttpClient as V,readDataContext as C}from"./http.js";const j=/(authorization|cookie|password|secret|token|api[_-]?key|private[_-]?key)/iu,$=String,p=globalThis.__TESTKIT_DATA_FLOW_STATE__??ne();globalThis.__TESTKIT_DATA_FLOW_STATE__=p;const A=new WeakSet;export function isDataScenarioCase(e){return A.has(e)}export function dataScenario(e,t,r){const{options:n,run:s}=Q(t,r);O(e,async()=>{const i=B(e,n);p.scenarios.push(i);const c=k(i);let d=!1,w;try{await s(c)}catch(q){d=!0,w=q,i.error=ee(q)}finally{D(i)}if(d)throw w;if(i.budgetFailures.length>0)throw new Error(Y(i))},n.timeoutMs||n.timeout);const u=R.getCurrentSuite().tasks.at(-1);if(u?.type!=="test")throw new Error("dataScenario did not register a native test case");A.add(u)}export function createDataTrace(e="trace"){return k(B(e,{}))}export function measureJsonBytes(e){return Buffer.byteLength(JSON.stringify(e??null))}export function stableHash(e){const t=S(e);if(t===void 0)throw new TypeError("stableHash(...) requires a serializable value");return E.createHash("sha256").update(t).digest("hex")}function k(e){const t={...C(),addFinding(r,n,s={}){return e.findings.push({severity:X(r),message:a(n,"finding message"),details:f(s)}),t},actor(r,n={}){return m(e,"actor",r,n),t},budget(r){return T(e,r)},bytes(r,n,s={}){return t.metric(r,n,{...s,kind:"bytes",unit:s.unit||"bytes"})},count(r,n=1,s={}){return t.metric(r,n,{...s,kind:"count",unit:s.unit||"count"})},duration(r,n,s={}){return t.metric(r,n,{...s,kind:"duration",unit:s.unit||"ms"})},event(r,n={}){return e.events.push({atMs:Date.now()-e.startedAtMs,name:a(r,"event name"),details:f(n)}),t},externalCall(r,n={}){const s=g(n);return m(e,"external-call",r,s),typeof s.durationMs=="number"&&t.duration(`${r}.external.duration`,s.durationMs),typeof s.requestBytes=="number"&&t.bytes(`${r}.external.request.bytes`,s.requestBytes),typeof s.responseBytes=="number"&&t.bytes(`${r}.external.response.bytes`,s.responseBytes),typeof s.costMinor=="number"&&t.money(`${r}.external.cost`,s.costMinor),t},fixture(r){return I(r,t)},expectMetric(r){return T(e,r)},expectSequence(r){return _(e,r)},finding(r,n,s={}){return t.addFinding(r,n,s)},async http(r={}){return V({...r,recorder:r.recorder||t})},metric(r,n,s={}){return H(e,r,n,s),t},money(r,n,s={}){return t.metric(r,n,{...s,kind:"money",unit:s.unit||"minor"})},ratio(r,n,s={}){return t.metric(r,n,{...s,kind:"ratio",unit:s.unit||"ratio"})},reconcile(r,n={}){return m(e,"reconciliation",r,n),t},record(r,n={}){const s=g(n);return m(e,"record",r,s),typeof s.count=="number"&&t.count(`${r}.record.count`,s.count),t},recordCache(r,{hits:n=0,misses:s=0,reads:u=0,writes:i=0}={}){const c=a(r,"cache metric name");t.count(`${c}.cache.hits`,n),t.count(`${c}.cache.misses`,s),t.count(`${c}.cache.reads`,u),t.count(`${c}.cache.writes`,i);const d=n+s;return d>0&&t.ratio(`${c}.cache.hit_rate`,n/d),t},recordHttpRequest(r){return t.count("http.request.count",1),t.bytes("http.request.bytes",r.bodyBytes||0),t.bytes("http.response.bytes",r.responseBytes||0),t.duration("http.request.duration",r.durationMs||0),t.sequence("http.methods",[r.method]),t.sequence("http.paths",[r.path]),t.event("http.request",{durationMs:r.durationMs||0,method:r.method,path:r.path,requestBytes:r.bodyBytes||0,responseBytes:r.responseBytes||0,status:r.status}),t},recordLlmUsage(r,n={}){const s=a(r,"llm usage name");for(const[u,i]of Object.entries(n))typeof i=="number"&&Number.isFinite(i)&&t.count(`${s}.${re(u)}`,i,{unit:u.toLowerCase().includes("cost")?"minor":"tokens"});return t},recordRpc(r,{method:n,requestBytes:s=0,responseBytes:u=0}={}){const i=a(r,"rpc metric name");return t.count(`${i}.rpc.count`,1),n&&t.sequence(`${i}.rpc.methods`,[n]),t.bytes(`${i}.rpc.request.bytes`,s),t.bytes(`${i}.rpc.response.bytes`,u),t},sequence(r,n,s={}){return P(e,r,n,s),t},sequenceBudget(r){return _(e,r)},system(r,n={}){return m(e,"system",r,n),t},transition(r,n={}){return m(e,"transition",r,n),t}};return Object.freeze(t)}function I(e,t=null){const r=L(e),n=F.readFileSync(r.absolutePath);return t?.count("fixture.count",1,{dimensions:{path:r.path}}),t?.bytes("fixture.bytes",n.byteLength,{dimensions:{path:r.path}}),{buffer(){return Buffer.from(n)},contentType:r.contentType,filename:r.filename,json(){return JSON.parse(n.toString("utf8"))},path:r.path,sha256:r.sha256,sizeBytes:r.sizeBytes,text(s="utf8"){return n.toString(s)}}}function L(e){const t=a(e,"fixture name"),r=J();return v(r.entries,t)}function J(){const e=N();return e===null?{entries:[]}:{entries:M(e.fixtures,"Node/Vitest data fixture manifest")}}function T(e,t){const r=a(t,"metric budget name");return{atLeast(n,s={}){return o(e,{name:r,target:"metric",operator:">=",expected:n,message:s.message}),this},atMost(n,s={}){return o(e,{name:r,target:"metric",operator:"<=",expected:n,message:s.message}),this},equals(n,s={}){return o(e,{name:r,target:"metric",operator:"==",expected:n,message:s.message}),this},greaterThan(n,s={}){return o(e,{name:r,target:"metric",operator:">",expected:n,message:s.message}),this},lessThan(n,s={}){return o(e,{name:r,target:"metric",operator:"<",expected:n,message:s.message}),this},required(n={}){return o(e,{name:r,target:"metric",operator:"exists",message:n.message}),this},relativeToBaseline(n){return o(e,{name:r,target:"metric",operator:"baseline_relative",message:n.message,thresholdVersion:n.thresholdVersion,policy:{kind:"baseline_relative",baselineRunId:n.runId,direction:n.direction||"increase",maximumRelativeDelta:n.maximumRelativeDelta,minimumAbsoluteDelta:n.minimumAbsoluteDelta||0,requiredSamples:n.requiredSamples||1}}),this}}}function _(e,t){const r=a(t,"sequence budget name");return{equals(n,s={}){return o(e,{name:r,target:"sequence",operator:"sequence==",expected:x(n),message:s.message}),this},includesOnly(n,s={}){return o(e,{name:r,target:"sequence",operator:"sequenceOnly",expected:x(n),message:s.message}),this},required(n={}){return o(e,{name:r,target:"sequence",operator:"exists",message:n.message}),this}}}function B(e,t){return{budgets:[],budgetFailures:[],budgetResults:[],description:t.description||null,events:[],evidence:[],error:null,findings:[],finishedAtMs:null,metrics:[],name:a(e,"data scenario name"),sequences:[],startedAtMs:Date.now(),status:"running"}}function D(e){return e.status!=="running"||(e.finishedAtMs=Date.now(),e.budgetResults=e.budgets.map(t=>U(e,t)),e.budgetFailures=e.budgetResults.filter(t=>t.status==="failed"),e.status=e.error||e.budgetFailures.length>0?"failed":"passed"),e}export function dataFlowState(){return p}export function finalizeDataFlowState(){for(const e of p.scenarios)D(e);return p}function H(e,t,r,n={}){const s=r;if(!Number.isFinite(s))throw new Error(`Data metric "${t}" must be a finite number`);e.metrics.push({description:l(n.description),dimensions:z(n.dimensions??{}),kind:l(n.kind)||"metric",name:a(t,"metric name"),unit:l(n.unit),value:s})}function P(e,t,r,n={}){const s=x(r).map(u=>$(u));e.sequences.push({description:l(n.description),dimensions:z(n.dimensions??{}),name:a(t,"sequence name"),values:s})}function o(e,t){e.budgets.push({...t,message:l(t.message)})}function m(e,t,r,n={}){const s=g(n);e.evidence.push({atMs:Date.now()-e.startedAtMs,details:f(s),kind:t,name:a(r,`${t} evidence name`),status:l(s.status)||null})}function g(e){return y(e)?e:{value:e}}function U(e,t){const r=t.target==="sequence"?Z(e,t.name):W(e,t.name),n=K(t,r),s=t.message||G(t,r,n);return t.target==="metric"?{...t,actual:r,expected:t.expected??null,message:s,status:n?"passed":"failed"}:{...t,actual:r,expected:t.expected??null,message:s,status:n?"passed":"failed"}}function K(e,t){if(e.target==="metric")return e.operator==="baseline_relative"?!0:e.operator==="exists"?t!==null:typeof t!="number"?!1:e.operator==="<="?t<=Number(e.expected):e.operator===">="?t>=Number(e.expected):e.operator==="<"?t<Number(e.expected):e.operator===">"?t>Number(e.expected):Object.is(t,Number(e.expected));if(e.operator==="exists")return t!==null;if(!Array.isArray(t))return!1;if(e.operator==="sequence==")return te(t,e.expected);const r=new Set((e.expected??[]).map(n=>h(n)));return t.every(n=>r.has(n))}function W(e,t){for(let r=e.metrics.length-1;r>=0;r-=1)if(e.metrics[r].name===t)return e.metrics[r].value;return null}function Z(e,t){const r=[];for(const n of e.sequences)n.name===t&&r.push(...n.values);return r.length>0?r:null}function G(e,t,r){if(e.operator==="baseline_relative"){const n=e.policy?.kind==="baseline_relative"?e.policy.baselineRunId:null;return`metric "${e.name}" will be compared with immutable run ${n||"<missing>"}`}return e.operator==="exists"?r?`${e.target} "${e.name}" was recorded`:`${e.target} "${e.name}" was not recorded`:`${e.target} "${e.name}" expected ${e.operator} ${JSON.stringify(e.expected)}, got ${JSON.stringify(t)}`}function Y(e){return[`Data-flow budgets failed in "${e.name}":`,...e.budgetFailures.map(t=>`- ${t.message}`)].join(`
2
- `)}function Q(e,t){if(typeof e=="function")return{options:{},run:e};if(typeof t!="function")throw new Error("dataScenario(name, options?, run) requires a run callback");return{options:e,run:t}}function x(e){return ae(e)?[...e]:[e]}function a(e,t){const r=h(e).trim();if(!r)throw new Error(`${t} must be a non-empty string`);return r}function l(e){if(e==null)return null;const t=h(e).trim();return t||null}function X(e){const t=h(e||"info").toLowerCase();return ie(t)?t:"info"}function f(e){if(Array.isArray(e))return e.map(r=>f(r));if(!y(e))return e;const t={};for(const[r,n]of Object.entries(e))t[r]=j.test(r)?"[redacted]":f(n);return t}function ee(e){return e instanceof Error?{message:e.message,name:e.name,stack:e.stack??null}:{message:b(e,"message")??se(e),name:b(e,"name")??"Error",stack:b(e,"stack")}}function S(e){return Array.isArray(e)?`[${e.map(t=>S(t)).join(",")}]`:y(e)?`{${Object.keys(e).sort().map(t=>{const r=S(e[t]);return`${JSON.stringify(t)}:${r??"undefined"}`}).join(",")}}`:JSON.stringify(e)}function te(e,t){return!Array.isArray(e)||!Array.isArray(t)||e.length!==t.length?!1:e.every((r,n)=>String(r)===String(t[n]))}function re(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/[^a-zA-Z0-9]+/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}function ne(){return{emitted:!1,scenarios:[]}}function z(e){const t=f(e);return y(t)?t:{}}function b(e,t){if(!y(e))return null;try{const r=Reflect.get(e,t);return typeof r=="string"?r:null}catch{return null}}function se(e){try{return $(e)}catch{return"Unknown thrown value"}}function ie(e){return e==="error"||e==="info"||e==="waste"||e==="watch"}function ae(e){return Array.isArray(e)}function y(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}
1
+ import{stringFromUnknown as g}from"./primitives.js";import E from"node:crypto";import F from"node:fs";import{parseRuntimeFixtureManifestEntries as M,resolveRuntimeFixtureEntry as _}from"../../../contracts/fixture-manifest.js";import{readNodeVitestRuntimeInput as D}from"../runtime-input.js";import{TestRunner as N,test as O}from"vitest";import{createDataHttpClient as v,readDataContext as C}from"./http.js";import{isUnknownArray as V,isUnknownRecord as p}from"../../../../kernel/unknown-values.js";const R=/(authorization|cookie|password|secret|token|api[_-]?key|private[_-]?key)/iu,b=String,y=globalThis.__TESTKIT_DATA_FLOW_STATE__??se();globalThis.__TESTKIT_DATA_FLOW_STATE__=y;const k=new WeakSet;export function isDataScenarioCase(e){return k.has(e)}export function dataScenario(e,t,r){const{options:n,run:s}=X(t,r);O(e,async()=>{const i=I(e,n);y.scenarios.push(i);const c=j(i);let l=!1,q;try{await s(c)}catch($){l=!0,q=$,i.error=te($)}finally{z(i)}if(l)throw q;if(i.budgetFailures.length>0)throw new Error(Q(i))},n.timeoutMs||n.timeout);const u=N.getCurrentSuite().tasks.at(-1);if(u?.type!=="test")throw new Error("dataScenario did not register a native test case");k.add(u)}export function measureJsonBytes(e){return Buffer.byteLength(JSON.stringify(e??null))}export function stableHash(e){const t=S(e);if(t===void 0)throw new TypeError("stableHash(...) requires a serializable value");return E.createHash("sha256").update(t).digest("hex")}function j(e){const t={...C(),addFinding(r,n,s={}){return e.findings.push({severity:ee(r),message:a(n,"finding message"),details:d(s)}),t},actor(r,n={}){return f(e,"actor",r,n),t},budget(r){return A(e,r)},bytes(r,n,s={}){return t.metric(r,n,{...s,kind:"bytes",unit:s.unit||"bytes"})},count(r,n=1,s={}){return t.metric(r,n,{...s,kind:"count",unit:s.unit||"count"})},duration(r,n,s={}){return t.metric(r,n,{...s,kind:"duration",unit:s.unit||"ms"})},event(r,n={}){return e.events.push({atMs:Date.now()-e.startedAtMs,name:a(r,"event name"),details:d(n)}),t},externalCall(r,n={}){const s=h(n);return f(e,"external-call",r,s),typeof s.durationMs=="number"&&t.duration(`${r}.external.duration`,s.durationMs),typeof s.requestBytes=="number"&&t.bytes(`${r}.external.request.bytes`,s.requestBytes),typeof s.responseBytes=="number"&&t.bytes(`${r}.external.response.bytes`,s.responseBytes),typeof s.costMinor=="number"&&t.money(`${r}.external.cost`,s.costMinor),t},fixture(r){return L(r,t)},expectMetric(r){return A(e,r)},expectSequence(r){return T(e,r)},finding(r,n,s={}){return t.addFinding(r,n,s)},async http(r={}){return v({...r,recorder:r.recorder||t})},metric(r,n,s={}){return U(e,r,n,s),t},money(r,n,s={}){return t.metric(r,n,{...s,kind:"money",unit:s.unit||"minor"})},ratio(r,n,s={}){return t.metric(r,n,{...s,kind:"ratio",unit:s.unit||"ratio"})},reconcile(r,n={}){return f(e,"reconciliation",r,n),t},record(r,n={}){const s=h(n);return f(e,"record",r,s),typeof s.count=="number"&&t.count(`${r}.record.count`,s.count),t},recordCache(r,{hits:n=0,misses:s=0,reads:u=0,writes:i=0}={}){const c=a(r,"cache metric name");t.count(`${c}.cache.hits`,n),t.count(`${c}.cache.misses`,s),t.count(`${c}.cache.reads`,u),t.count(`${c}.cache.writes`,i);const l=n+s;return l>0&&t.ratio(`${c}.cache.hit_rate`,n/l),t},recordHttpRequest(r){return t.count("http.request.count",1),t.bytes("http.request.bytes",r.bodyBytes||0),t.bytes("http.response.bytes",r.responseBytes||0),t.duration("http.request.duration",r.durationMs||0),t.sequence("http.methods",[r.method]),t.sequence("http.paths",[r.path]),t.event("http.request",{durationMs:r.durationMs||0,method:r.method,path:r.path,requestBytes:r.bodyBytes||0,responseBytes:r.responseBytes||0,status:r.status}),t},recordLlmUsage(r,n={}){const s=a(r,"llm usage name");for(const[u,i]of Object.entries(n))typeof i=="number"&&Number.isFinite(i)&&t.count(`${s}.${ne(u)}`,i,{unit:u.toLowerCase().includes("cost")?"minor":"tokens"});return t},recordRpc(r,{method:n,requestBytes:s=0,responseBytes:u=0}={}){const i=a(r,"rpc metric name");return t.count(`${i}.rpc.count`,1),n&&t.sequence(`${i}.rpc.methods`,[n]),t.bytes(`${i}.rpc.request.bytes`,s),t.bytes(`${i}.rpc.response.bytes`,u),t},sequence(r,n,s={}){return P(e,r,n,s),t},sequenceBudget(r){return T(e,r)},system(r,n={}){return f(e,"system",r,n),t},transition(r,n={}){return f(e,"transition",r,n),t}};return Object.freeze(t)}function L(e,t=null){const r=J(e),n=F.readFileSync(r.absolutePath);return t?.count("fixture.count",1,{dimensions:{path:r.path}}),t?.bytes("fixture.bytes",n.byteLength,{dimensions:{path:r.path}}),{buffer(){return Buffer.from(n)},contentType:r.contentType,filename:r.filename,json(){return JSON.parse(n.toString("utf8"))},path:r.path,sha256:r.sha256,sizeBytes:r.sizeBytes,text(s="utf8"){return n.toString(s)}}}function J(e){const t=a(e,"fixture name"),r=H();return _(r.entries,t)}function H(){const e=D();return e===null?{entries:[]}:{entries:M(e.fixtures,"Node/Vitest data fixture manifest")}}function A(e,t){const r=a(t,"metric budget name");return{atLeast(n,s={}){return o(e,{name:r,target:"metric",operator:">=",expected:n,message:s.message}),this},atMost(n,s={}){return o(e,{name:r,target:"metric",operator:"<=",expected:n,message:s.message}),this},equals(n,s={}){return o(e,{name:r,target:"metric",operator:"==",expected:n,message:s.message}),this},greaterThan(n,s={}){return o(e,{name:r,target:"metric",operator:">",expected:n,message:s.message}),this},lessThan(n,s={}){return o(e,{name:r,target:"metric",operator:"<",expected:n,message:s.message}),this},required(n={}){return o(e,{name:r,target:"metric",operator:"exists",message:n.message}),this}}}function T(e,t){const r=a(t,"sequence budget name");return{equals(n,s={}){return o(e,{name:r,target:"sequence",operator:"sequence==",expected:x(n),message:s.message}),this},includesOnly(n,s={}){return o(e,{name:r,target:"sequence",operator:"sequenceOnly",expected:x(n),message:s.message}),this},required(n={}){return o(e,{name:r,target:"sequence",operator:"exists",message:n.message}),this}}}function I(e,t){return{budgets:[],budgetFailures:[],budgetResults:[],description:t.description||null,events:[],evidence:[],error:null,findings:[],finishedAtMs:null,metrics:[],name:a(e,"data scenario name"),sequences:[],startedAtMs:Date.now(),status:"running"}}function z(e){return e.status!=="running"||(e.finishedAtMs=Date.now(),e.budgetResults=e.budgets.map(t=>K(e,t)),e.budgetFailures=e.budgetResults.filter(t=>t.status==="failed"),e.status=e.error||e.budgetFailures.length>0?"failed":"passed"),e}export function dataFlowState(){return y}export function finalizeDataFlowState(){for(const e of y.scenarios)z(e);return y}function U(e,t,r,n={}){const s=r;if(!Number.isFinite(s))throw new Error(`Data metric "${t}" must be a finite number`);e.metrics.push({description:m(n.description),dimensions:B(n.dimensions??{}),kind:m(n.kind)||"metric",name:a(t,"metric name"),unit:m(n.unit),value:s})}function P(e,t,r,n={}){const s=x(r).map(u=>b(u));e.sequences.push({description:m(n.description),dimensions:B(n.dimensions??{}),name:a(t,"sequence name"),values:s})}function o(e,t){e.budgets.push({...t,message:m(t.message)})}function f(e,t,r,n={}){const s=h(n);e.evidence.push({atMs:Date.now()-e.startedAtMs,details:d(s),kind:t,name:a(r,`${t} evidence name`),status:m(s.status)||null})}function h(e){return p(e)?e:{value:e}}function K(e,t){const r=t.target==="sequence"?G(e,t.name):Z(e,t.name),n=W(t,r),s=t.message||Y(t,r,n);return t.target==="metric"?{...t,actual:r,expected:t.expected??null,message:s,status:n?"passed":"failed"}:{...t,actual:r,expected:t.expected??null,message:s,status:n?"passed":"failed"}}function W(e,t){if(e.target==="metric")return e.operator==="exists"?t!==null:typeof t!="number"?!1:e.operator==="<="?t<=Number(e.expected):e.operator===">="?t>=Number(e.expected):e.operator==="<"?t<Number(e.expected):e.operator===">"?t>Number(e.expected):Object.is(t,Number(e.expected));if(e.operator==="exists")return t!==null;if(!Array.isArray(t))return!1;if(e.operator==="sequence==")return re(t,e.expected);const r=new Set((e.expected??[]).map(n=>g(n)));return t.every(n=>r.has(n))}function Z(e,t){for(let r=e.metrics.length-1;r>=0;r-=1)if(e.metrics[r].name===t)return e.metrics[r].value;return null}function G(e,t){const r=[];for(const n of e.sequences)n.name===t&&r.push(...n.values);return r.length>0?r:null}function Y(e,t,r){return e.operator==="exists"?r?`${e.target} "${e.name}" was recorded`:`${e.target} "${e.name}" was not recorded`:`${e.target} "${e.name}" expected ${e.operator} ${JSON.stringify(e.expected)}, got ${JSON.stringify(t)}`}function Q(e){return[`Data-flow budgets failed in "${e.name}":`,...e.budgetFailures.map(t=>`- ${t.message}`)].join(`
2
+ `)}function X(e,t){if(typeof e=="function")return{options:{},run:e};if(typeof t!="function")throw new Error("dataScenario(name, options?, run) requires a run callback");return{options:e,run:t}}function x(e){return V(e)?[...e]:[e]}function a(e,t){const r=g(e).trim();if(!r)throw new Error(`${t} must be a non-empty string`);return r}function m(e){if(e==null)return null;const t=g(e).trim();return t||null}function ee(e){const t=g(e||"info").toLowerCase();return ae(t)?t:"info"}function d(e){if(Array.isArray(e))return e.map(r=>d(r));if(!p(e))return e;const t={};for(const[r,n]of Object.entries(e))t[r]=R.test(r)?"[redacted]":d(n);return t}function te(e){return e instanceof Error?{message:e.message,name:e.name,stack:e.stack??null}:{message:w(e,"message")??ie(e),name:w(e,"name")??"Error",stack:w(e,"stack")}}function S(e){return Array.isArray(e)?`[${e.map(t=>S(t)).join(",")}]`:p(e)?`{${Object.keys(e).sort().map(t=>{const r=S(e[t]);return`${JSON.stringify(t)}:${r??"undefined"}`}).join(",")}}`:JSON.stringify(e)}function re(e,t){return!Array.isArray(e)||!Array.isArray(t)||e.length!==t.length?!1:e.every((r,n)=>String(r)===String(t[n]))}function ne(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/[^a-zA-Z0-9]+/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}function se(){return{emitted:!1,scenarios:[]}}function B(e){const t=d(e);return p(t)?t:{}}function w(e,t){if(!p(e))return null;try{const r=Reflect.get(e,t);return typeof r=="string"?r:null}catch{return null}}function ie(e){try{return b(e)}catch{return"Unknown thrown value"}}function ae(e){return e==="error"||e==="info"||e==="waste"||e==="watch"}
@@ -7,7 +7,7 @@ export declare const DATA_SCHEMA_VERSION = 1;
7
7
  export type UnknownRecord = Record<string, unknown>;
8
8
  export type DataFindingSeverity = "error" | "info" | "waste" | "watch";
9
9
  export type DataScenarioStatus = "failed" | "passed" | "running";
10
- export type DataMetricBudgetOperator = "<" | "<=" | "==" | ">" | ">=" | "baseline_relative" | "exists";
10
+ export type DataMetricBudgetOperator = "<" | "<=" | "==" | ">" | ">=" | "exists";
11
11
  export type DataSequenceBudgetOperator = "exists" | "sequence==" | "sequenceOnly";
12
12
  export interface DataScenarioOptions {
13
13
  description?: string;
@@ -30,21 +30,12 @@ export interface DataEvidenceDetails extends UnknownRecord {
30
30
  export interface DataBudgetOptions {
31
31
  message?: string;
32
32
  }
33
- export interface DataBaselineBudgetOptions extends DataBudgetOptions {
34
- direction?: "decrease" | "increase";
35
- maximumRelativeDelta: number;
36
- minimumAbsoluteDelta?: number;
37
- requiredSamples?: number;
38
- runId: string;
39
- thresholdVersion?: string;
40
- }
41
33
  export interface DataMetricBudget {
42
34
  atLeast(value: number, options?: DataBudgetOptions): this;
43
35
  atMost(value: number, options?: DataBudgetOptions): this;
44
36
  equals(value: number, options?: DataBudgetOptions): this;
45
37
  greaterThan(value: number, options?: DataBudgetOptions): this;
46
38
  lessThan(value: number, options?: DataBudgetOptions): this;
47
- relativeToBaseline(options: DataBaselineBudgetOptions): this;
48
39
  required(options?: DataBudgetOptions): this;
49
40
  }
50
41
  export interface DataSequenceBudget {
@@ -278,32 +269,13 @@ export interface SerializedDataError {
278
269
  name: string;
279
270
  stack: string | null;
280
271
  }
281
- export type DataPerformancePolicyInput = {
282
- kind: "absolute";
283
- operator: "<" | "<=" | ">" | ">=";
284
- requiredSamples?: number;
285
- value: number;
286
- } | {
287
- baselineRunId: string;
288
- direction?: "decrease" | "increase";
289
- kind: "baseline_relative";
290
- maximumRelativeDelta: number;
291
- minimumAbsoluteDelta?: number;
292
- requiredSamples?: number;
293
- } | {
294
- kind: "exact";
295
- requiredSamples?: number;
296
- value: number;
297
- };
298
272
  export interface DataMetricBudgetInput {
299
273
  expected?: number;
300
274
  message: string | null;
301
275
  metricKey?: string | null;
302
276
  name: string;
303
277
  operator: DataMetricBudgetOperator;
304
- policy?: DataPerformancePolicyInput;
305
278
  target: "metric";
306
- thresholdVersion?: string | null;
307
279
  }
308
280
  export interface DataSequenceBudgetInput {
309
281
  expected?: unknown[];
@@ -1 +1 @@
1
- import m from"node:path";import{readVerifiedOwnedFile as a,writeOwnedRuntimeInput as w,RUNTIME_INPUT_BYTE_MEASURE as S}from"../../runtime-input-file.js";import{requireBoundedJsonValue as O,RUNTIME_INPUT_JSON_BOUNDS as h}from"../../contracts/json-bounds.js";import{ENGINE_PROCESS_RESERVED_ENVIRONMENT_KEYS as V}from"../../../process/environment.js";import{installManagedProcessEnvironmentOverlay as R}from"../../../process/environment-overlay.js";export const NODE_VITEST_RUNTIME_INPUT_VERSION=1,NODE_VITEST_RUNTIME_INPUT_FILENAME="runtime-input.json",NODE_VITEST_RUNTIME_INPUT_FILE_ENV="TESTKIT_NODE_VITEST_INPUT_FILE",NODE_VITEST_RUNTIME_INPUT_SHA256_ENV="TESTKIT_NODE_VITEST_INPUT_SHA256",NODE_VITEST_RUNTIME_INPUT_SYMBOL="elench.testkit.node-vitest.runtime-input.v1",NODE_VITEST_DATA_BUDGET_FAILURE_DETAIL_KIND="data-flow-budget",NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_KIND="testkit.failure-details",NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_NAME="data-flow-failure-details";const d={filename:NODE_VITEST_RUNTIME_INPUT_FILENAME,label:"Node/Vitest runtime input",maxSizeBytes:8*1024*1024},f=512,p=4*1024*1024,l=new Set(["BASE_URL","FORCE_COLOR","NODE_OPTIONS","NO_COLOR","UPDATE_SNAPSHOT",...V].map(e=>e.toUpperCase()));export const MAX_NODE_VITEST_SPAWN_ENVIRONMENT_UNITS=24*1024;export async function writeOwnedNodeVitestRuntimeInput(e,t){return w(e,t,d)}export async function verifyOwnedNodeVitestRuntimeInput(e){await a(e,d)}export function selectNodeVitestForwardedEnvironment(e){const t={...e};return _(t),t}export function assertNodeVitestSpawnEnvironmentBudget(e){if(Object.entries(e).reduce((n,[i,r])=>n+i.length+r.length+2,1)>MAX_NODE_VITEST_SPAWN_ENVIRONMENT_UNITS)throw new Error(`Node/Vitest process environment exceeds the ${MAX_NODE_VITEST_SPAWN_ENVIRONMENT_UNITS.toString()} character environment-block budget`)}export async function installNodeVitestRuntimeInput(e){const t=process.env[NODE_VITEST_RUNTIME_INPUT_FILE_ENV],n=process.env[NODE_VITEST_RUNTIME_INPUT_SHA256_ENV];if(t!==e.expectedFile)throw new Error("Node/Vitest runtime input pointer does not match its engine-owned path");if(n!==e.expectedSha256)throw new Error("Node/Vitest runtime input digest does not match its prepared value");const i={directory:m.dirname(e.expectedFile),file:e.expectedFile,sha256:e.expectedSha256,sizeBytes:e.expectedSizeBytes},r=await a(i,d);let s;try{s=JSON.parse(r)}catch(u){throw new Error("Node/Vitest runtime input contains invalid JSON",{cause:u})}const o=E(I(s));if(o.invocationId!==e.expectedInvocationId||o.profileId!==e.expectedProfileId||o.taskId!==e.expectedTaskId)throw new Error("Node/Vitest runtime input identity does not match its task");R({environment:o.environment,label:"Node/Vitest"}),Object.defineProperty(globalThis,Symbol.for(NODE_VITEST_RUNTIME_INPUT_SYMBOL),{configurable:!0,enumerable:!1,value:o,writable:!1}),N(o)}export function applyNodeVitestEngineEnvironment(){const e=readNodeVitestRuntimeInput();if(e===null)throw new Error("Node/Vitest runtime input is not installed");N(e)}function N(e){const t=e.context.baseUrl;typeof t=="string"?process.env.BASE_URL=t:Reflect.deleteProperty(process.env,"BASE_URL")}export function readNodeVitestRuntimeInput(){const e=Reflect.get(globalThis,Symbol.for(NODE_VITEST_RUNTIME_INPUT_SYMBOL));return e===void 0?null:E(I(e,"Installed Node/Vitest runtime input"))}function I(e,t="Node/Vitest runtime input"){if(O(e,t,h,S),!c(e))throw new Error(`${t} must contain an object`);const n=new Set(["context","engineId","environment","fixtures","invocationId","profileId","setupData","taskId","version"]);for(const r of Object.keys(e))if(!n.has(r))throw new Error(`${t} contains unknown field ${r}`);if(e.version!==NODE_VITEST_RUNTIME_INPUT_VERSION)throw new Error(`${t}.version must be 1`);if(e.engineId!=="node-vitest")throw new Error(`${t}.engineId must be "node-vitest"`);if(!D(e.profileId))throw new Error(`${t}.profileId is invalid`);if(!c(e.context)||!c(e.fixtures))throw new Error(`${t} context and fixtures must be objects`);const i=x(e.environment,`${t}.environment`);return _(i),{context:e.context,engineId:"node-vitest",environment:i,fixtures:e.fixtures,invocationId:T(e.invocationId,`${t}.invocationId`),profileId:e.profileId,...Object.hasOwn(e,"setupData")?{setupData:e.setupData}:{},taskId:T(e.taskId,`${t}.taskId`),version:NODE_VITEST_RUNTIME_INPUT_VERSION}}function _(e){const t=Object.entries(e);if(t.length>f)throw new Error(`Node/Vitest forwarded environment exceeds the ${f.toString()} entry limit`);let n=0;const i=new Set;for(const[r,s]of t){y(r,s,"Node/Vitest forwarded environment");const o=r.toUpperCase();if(i.has(o))throw new Error(`Node/Vitest forwarded environment contains case-insensitive duplicate key ${r}`);if(i.add(o),o.startsWith("TESTKIT_")||o.startsWith("VITEST_")||l.has(o))throw new Error(`Node/Vitest forwarded environment contains reserved key ${r}`);n+=Buffer.byteLength(r)+Buffer.byteLength(s)+2}if(n>p)throw new Error(`Node/Vitest forwarded environment exceeds the ${p.toString()} byte limit`)}function x(e,t){if(!c(e))throw new Error(`${t} must be an object`);const n=Object.entries(e);if(!n.every(i=>typeof i[1]=="string"))throw new Error(`${t} values must all be strings`);return Object.fromEntries(n)}function y(e,t,n){if(e.length===0||e.includes("=")||e.includes("\0"))throw new Error(`${n} contains an invalid variable name`);if(t.includes("\0"))throw new Error(`${n}.${e} contains a NUL character`)}function E(e){if(e!==null&&typeof e=="object"&&!Object.isFrozen(e)){Object.freeze(e);for(const t of Object.values(e))E(t)}return e}function T(e,t){if(typeof e!="string"||e.length===0)throw new Error(`${t} must be a non-empty string`);return e}function D(e){return e==="node-vitest-contract"||e==="node-vitest-data"}function c(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}
1
+ import m from"node:path";import{readVerifiedOwnedFile as a,writeOwnedRuntimeInput as w,RUNTIME_INPUT_BYTE_MEASURE as S}from"../../runtime-input-file.js";import{requireBoundedJsonValue as O,RUNTIME_INPUT_JSON_BOUNDS as h}from"../../contracts/json-bounds.js";import{ENGINE_PROCESS_RESERVED_ENVIRONMENT_KEYS as V}from"../../../process/environment.js";import{installManagedProcessEnvironmentOverlay as R}from"../../../process/environment-overlay.js";import{isUnknownRecord as c}from"../../../kernel/unknown-values.js";export const NODE_VITEST_RUNTIME_INPUT_VERSION=1,NODE_VITEST_RUNTIME_INPUT_FILENAME="runtime-input.json",NODE_VITEST_RUNTIME_INPUT_FILE_ENV="TESTKIT_NODE_VITEST_INPUT_FILE",NODE_VITEST_RUNTIME_INPUT_SHA256_ENV="TESTKIT_NODE_VITEST_INPUT_SHA256",NODE_VITEST_RUNTIME_INPUT_SYMBOL="elench.testkit.node-vitest.runtime-input.v1",NODE_VITEST_DATA_BUDGET_FAILURE_DETAIL_KIND="data-flow-budget",NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_KIND="testkit.failure-details",NODE_VITEST_DATA_FAILURE_DETAILS_ARTIFACT_NAME="data-flow-failure-details";const d={filename:NODE_VITEST_RUNTIME_INPUT_FILENAME,label:"Node/Vitest runtime input",maxSizeBytes:8*1024*1024},f=512,p=4*1024*1024,l=new Set(["BASE_URL","FORCE_COLOR","NODE_OPTIONS","NO_COLOR","UPDATE_SNAPSHOT",...V].map(e=>e.toUpperCase()));export const MAX_NODE_VITEST_SPAWN_ENVIRONMENT_UNITS=24*1024;export async function writeOwnedNodeVitestRuntimeInput(e,t){return w(e,t,d)}export async function verifyOwnedNodeVitestRuntimeInput(e){await a(e,d)}export function selectNodeVitestForwardedEnvironment(e){const t={...e};return _(t),t}export function assertNodeVitestSpawnEnvironmentBudget(e){if(Object.entries(e).reduce((n,[i,o])=>n+i.length+o.length+2,1)>MAX_NODE_VITEST_SPAWN_ENVIRONMENT_UNITS)throw new Error(`Node/Vitest process environment exceeds the ${MAX_NODE_VITEST_SPAWN_ENVIRONMENT_UNITS.toString()} character environment-block budget`)}export async function installNodeVitestRuntimeInput(e){const t=process.env[NODE_VITEST_RUNTIME_INPUT_FILE_ENV],n=process.env[NODE_VITEST_RUNTIME_INPUT_SHA256_ENV];if(t!==e.expectedFile)throw new Error("Node/Vitest runtime input pointer does not match its engine-owned path");if(n!==e.expectedSha256)throw new Error("Node/Vitest runtime input digest does not match its prepared value");const i={directory:m.dirname(e.expectedFile),file:e.expectedFile,sha256:e.expectedSha256,sizeBytes:e.expectedSizeBytes},o=await a(i,d);let s;try{s=JSON.parse(o)}catch(u){throw new Error("Node/Vitest runtime input contains invalid JSON",{cause:u})}const r=E(I(s));if(r.invocationId!==e.expectedInvocationId||r.profileId!==e.expectedProfileId||r.taskId!==e.expectedTaskId)throw new Error("Node/Vitest runtime input identity does not match its task");R({environment:r.environment,label:"Node/Vitest"}),Object.defineProperty(globalThis,Symbol.for(NODE_VITEST_RUNTIME_INPUT_SYMBOL),{configurable:!0,enumerable:!1,value:r,writable:!1}),N(r)}export function applyNodeVitestEngineEnvironment(){const e=readNodeVitestRuntimeInput();if(e===null)throw new Error("Node/Vitest runtime input is not installed");N(e)}function N(e){const t=e.context.baseUrl;typeof t=="string"?process.env.BASE_URL=t:Reflect.deleteProperty(process.env,"BASE_URL")}export function readNodeVitestRuntimeInput(){const e=Reflect.get(globalThis,Symbol.for(NODE_VITEST_RUNTIME_INPUT_SYMBOL));return e===void 0?null:E(I(e,"Installed Node/Vitest runtime input"))}function I(e,t="Node/Vitest runtime input"){if(O(e,t,h,S),!c(e))throw new Error(`${t} must contain an object`);const n=new Set(["context","engineId","environment","fixtures","invocationId","profileId","setupData","taskId","version"]);for(const o of Object.keys(e))if(!n.has(o))throw new Error(`${t} contains unknown field ${o}`);if(e.version!==NODE_VITEST_RUNTIME_INPUT_VERSION)throw new Error(`${t}.version must be 1`);if(e.engineId!=="node-vitest")throw new Error(`${t}.engineId must be "node-vitest"`);if(!D(e.profileId))throw new Error(`${t}.profileId is invalid`);if(!c(e.context)||!c(e.fixtures))throw new Error(`${t} context and fixtures must be objects`);const i=x(e.environment,`${t}.environment`);return _(i),{context:e.context,engineId:"node-vitest",environment:i,fixtures:e.fixtures,invocationId:T(e.invocationId,`${t}.invocationId`),profileId:e.profileId,...Object.hasOwn(e,"setupData")?{setupData:e.setupData}:{},taskId:T(e.taskId,`${t}.taskId`),version:NODE_VITEST_RUNTIME_INPUT_VERSION}}function _(e){const t=Object.entries(e);if(t.length>f)throw new Error(`Node/Vitest forwarded environment exceeds the ${f.toString()} entry limit`);let n=0;const i=new Set;for(const[o,s]of t){y(o,s,"Node/Vitest forwarded environment");const r=o.toUpperCase();if(i.has(r))throw new Error(`Node/Vitest forwarded environment contains case-insensitive duplicate key ${o}`);if(i.add(r),r.startsWith("TESTKIT_")||r.startsWith("VITEST_")||l.has(r))throw new Error(`Node/Vitest forwarded environment contains reserved key ${o}`);n+=Buffer.byteLength(o)+Buffer.byteLength(s)+2}if(n>p)throw new Error(`Node/Vitest forwarded environment exceeds the ${p.toString()} byte limit`)}function x(e,t){if(!c(e))throw new Error(`${t} must be an object`);const n=Object.entries(e);if(!n.every(i=>typeof i[1]=="string"))throw new Error(`${t} values must all be strings`);return Object.fromEntries(n)}function y(e,t,n){if(e.length===0||e.includes("=")||e.includes("\0"))throw new Error(`${n} contains an invalid variable name`);if(t.includes("\0"))throw new Error(`${n}.${e} contains a NUL character`)}function E(e){if(e!==null&&typeof e=="object"&&!Object.isFrozen(e)){Object.freeze(e);for(const t of Object.values(e))E(t)}return e}function T(e,t){if(typeof e!="string"||e.length===0)throw new Error(`${t} must be a non-empty string`);return e}function D(e){return e==="node-vitest-contract"||e==="node-vitest-data"}
@@ -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 C,processExitFailure as b,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 j}from"../../api/index.js";import{createNativeInvocationProcessEnvironment as V,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 tt}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(t){const e=g(t);super(e.message,{cause:e}),this.name="PlaywrightConsumerPreparationError"}}export const playwrightAdapterDependencies={createInvocationEnvironment:V,removeOwnedDirectory:it,writeTaskWorkspace:Q};const rt=new Set(["EBUSY","ENOTEMPTY","EPERM"]),et=5;async function it(r){for(let t=0;;t+=1)try{await u.rm(r,{force:!0,recursive:!0});return}catch(e){const i=e instanceof Error&&"code"in e?e.code:void 0;if(t===et||typeof i!="string"||!rt.has(i))throw e;await $((t+1)*100)}}export async function executePlaywrightEngine(r,t,e,i=playwrightAdapterDependencies){const o=await ot(r,t,i,e);return x(r,o.tasks,y,(a,s)=>nt(r,o,a,s),lt(r,o.installation))}async function ot(r,t,e,i){const o=await B(r.workspace.rootDirectory);O(r.workspace.temporaryDirectory,"temporary directory"),O(r.workspace.artifactDirectory,"artifact directory"),await u.mkdir(r.workspace.temporaryDirectory,{recursive:!0}),await u.mkdir(r.workspace.artifactDirectory,{recursive:!0});const a=await u.realpath(r.workspace.temporaryDirectory),s=await u.realpath(r.workspace.artifactDirectory),n=await D(`playwright-${S(r.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 r.tasks.entries()){const I=j(r,c),_=`${h.toString().padStart(3,"0")}-${S(c.id)}`,v=H.join(n,_),f=await D(`${_}-`,{parentDir:s});try{const m=ct(r,c.serviceName),E=await pt(()=>Y(o,c.file,"Playwright task file")),w=await e.writeTaskWorkspace({artifactDirectory:f,baseUrl:m,browserFile:t.browserExecutable,endpoints:r.target.endpoints,inputs:I,invocationId:r.invocationId,managedModuleEntrypoints:{authoring:t.authoringEntrypoints.authoring,cli:t.family.cli,playwright:t.family.playwright.entrypoint,playwrightCore:t.family.playwrightCore.entrypoint,playwrightTest:t.family.playwrightTest.entrypoint,root:t.authoringEntrypoints.root,rootPackageJson:t.authoringEntrypoints.rootPackageJson},moduleFile:t.family.playwrightTest.entrypoint,orchestration:c.orchestration,rootDirectory:o,serviceName:c.serviceName,sourceFile:E,taskDirectory:v,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 ut([v,f],e)).map(w=>w.error);p.push({artifactDirectory:f,inputs:I,task:c,preparationFailure:playwrightPreparationFailure(m,E),prepared:null})}}return Object.freeze({installation:t,invocationEnvironment:l.environment,rootDirectory:o,tasks:Object.freeze(p)})}async function nt(r,t,e,i){const a={...await tt(r.workspace.cacheDirectory,e.inputs.environment),...at(r,t,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:[t.installation.family.cli,"test",X(e.prepared.sourceFile),"--config",e.prepared.workspace.configFile],cwd:t.rootDirectory,displayLabel:"Playwright",env:a,executable:process.execPath,signal:r.signal,timeoutMs:s});let l;try{l=await Z({identity:{engineId:"playwright",invocationId:r.invocationId,taskId:e.task.id,sourceFile:e.prepared.sourceFile},artifactDirectory:e.artifactDirectory,outputDirectory:e.prepared.workspace.outputDirectory,reportFile:e.prepared.workspace.reportFile,rootDirectory:t.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(r.signal.reason));return T(e.task.id,p.status,i,l.evidence,p.failure)}export function classifyPlaywrightProcessResult(r,t,e,i){const o=F(r,e,i,y);if(o!==null)return o;if(t.outputLimit!==null){const n=t.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=t.attachmentFailures.find(n=>n.code==="PLAYWRIGHT_ATTACHMENT_LIMIT");if(a!==void 0)return{failure:a,status:"failed"};if(t.report.failure!==null){const n=t.report.failure;return{...t.report,failure:{...n,details:{...n.details,evidenceErrors:t.reportError===null?0:1,...C(r)}}}}const s=t.attachmentFailures.at(0);return s!==void 0?{failure:s,status:"failed"}:r.exitCode!==0?b(r,y,R(r.stderr)??R(r.stdout)):t.reportError!==null?{failure:{...P(t.reportError,"PLAYWRIGHT_REPORT_INVALID"),classification:"infra"},status:"failed"}:t.report}export function playwrightEvidenceCollectionFailure(r,t){const e=g(t);return M(r,y,e)??{...P(e,"PLAYWRIGHT_EVIDENCE_FAILED"),classification:"infra"}}function at(r,t,e){const i={...t.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:t.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:r.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=st(s,a),A(i),i}function st(r,t){return["--experimental-strip-types",`--require=${JSON.stringify(r)}`,`--import=${JSON.stringify(K(t).href)}`].join(" ")}export function playwrightSpawnEnvironmentBytes(r){return Object.entries(r).reduce((t,[e,i])=>t+(process.platform==="win32"?(e.length+i.length+2)*2:Buffer.byteLength(e,"utf8")+Buffer.byteLength(i,"utf8")+2),0)}function A(r){if(Object.keys(r).length>L)throw new Error(`Playwright physical spawn environment exceeds its ${L.toString()} entry limit`);if(playwrightSpawnEnvironmentBytes(r)>PLAYWRIGHT_SPAWN_ENVIRONMENT_MAX_BYTES)throw new Error(`Playwright physical spawn environment exceeds its ${PLAYWRIGHT_SPAWN_ENVIRONMENT_MAX_BYTES.toString()} byte limit`)}function ct(r,t){if(!Object.hasOwn(r.target.endpoints,t))return null;const e=r.target.endpoints[t];if(typeof e!="string"||e.trim().length===0)throw new Error(`Playwright task service ${t} endpoint must be a non-empty URL`);let i;try{i=new URL(e)}catch(o){throw new Error(`Playwright task service ${t} endpoint is not a valid URL`,{cause:o})}if(i.protocol!=="http:"&&i.protocol!=="https:")throw new Error(`Playwright task service ${t} endpoint must use http or https`);return i.href}function lt(r,t){return{...q({engineId:"playwright",installationKind:"root-playwright-family",profile:r.profile}),browserName:"chromium",packages:{playwright:t.family.playwright.version,playwrightCore:t.family.playwrightCore.version,playwrightTest:t.family.playwrightTest.version},registryMode:t.registry.mode}}export function playwrightPreparationFailure(r,t){if(t.length===0)return{...P(r,"PLAYWRIGHT_PREPARE_FAILED"),classification:r instanceof k||r instanceof z?"product":"infra"};const e=g(r);return{classification:"infra",code:"PLAYWRIGHT_PREPARE_CLEANUP_FAILED",details:{cleanupFailures:t.map(i=>i.message),preparationFailure:e.message},message:`Playwright task preparation failed and its partial workspace could not be removed: ${t.map(i=>i.message).join("; ")}`,...e.stack===void 0?{}:{stack:e.stack}}}async function pt(r){try{return await r()}catch(t){throw new k(t)}}async function ut(r,t){const e=[];for(const i of r)try{await t.removeOwnedDirectory(i)}catch(o){e.push({directory:i,error:g(o)})}return e}
@@ -1,7 +1,7 @@
1
1
  import type { EngineExecutionInputs, EngineTaskOrchestration } from "../../api/index.js";
2
2
  export interface PlaywrightWorkspaceRequest {
3
3
  readonly artifactDirectory: string;
4
- readonly baseUrl: string;
4
+ readonly baseUrl: null | string;
5
5
  readonly browserFile: string;
6
6
  readonly endpoints: Readonly<Record<string, string>>;
7
7
  readonly inputs: EngineExecutionInputs;
@@ -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 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";import{isPathWithin as O}from"../../../process/files/paths.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 m(e)}export async function writePlaywrightTaskWorkspace(e){let r;try{x(e.inputs.supportModules),r=await I(e.rootDirectory,e.inputs)}catch(d){throw new PlaywrightConsumerConfigurationError(d)}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`
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:m(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
+ `}function m(e){return`^${e.split(/[\\/]+/u).map(r=>r.replace(/[.*+?^${}()|[\]\\]/gu,"\\$&")).join("[\\\\/]")}$`}async function I(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(!O(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}async function h(e,r){const t=await n.open(e,"wx",384);try{await t.writeFile(r,"utf8")}finally{await t.close()}}