@gfdelarue/testkit 0.3.4 → 0.3.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 (121) hide show
  1. package/README.md +4 -0
  2. package/dist/app/doctor/index.js +1 -1
  3. package/dist/app/inspect/artifacts.d.ts +1 -0
  4. package/dist/app/inspect/artifacts.js +1 -1
  5. package/dist/app/inspect/index.js +1 -1
  6. package/dist/app/lint/index.js +1 -1
  7. package/dist/app/lint/native.js +1 -1
  8. package/dist/app/lint/policy.js +1 -1
  9. package/dist/app/lint/rules/data.js +1 -1
  10. package/dist/app/lint/rules/engine-imports.js +1 -1
  11. package/dist/app/lint/rules/syntax.js +1 -1
  12. package/dist/app/lint/rules/unit.js +1 -1
  13. package/dist/app/lint/shared.d.ts +1 -1
  14. package/dist/app/lint/shared.js +1 -1
  15. package/dist/app/run/orchestrator.js +1 -1
  16. package/dist/app/run/request.js +1 -1
  17. package/dist/app/setup/playwright.js +1 -1
  18. package/dist/app/status/index.d.ts +2 -0
  19. package/dist/app/status/index.js +1 -1
  20. package/dist/app/status/runs.d.ts +2 -2
  21. package/dist/app/status/runs.js +1 -1
  22. package/dist/app/stop/index.js +1 -1
  23. package/dist/app/typecheck/index.d.ts +2 -0
  24. package/dist/app/typecheck/index.js +4 -4
  25. package/dist/cli/commands/artifacts.js +2 -2
  26. package/dist/cli/commands/db/schema/refresh.js +1 -1
  27. package/dist/cli/commands/db/schema/verify.js +1 -1
  28. package/dist/cli/commands/doctor.js +1 -1
  29. package/dist/cli/operations/db/schema/refresh/operation.d.ts +1 -0
  30. package/dist/cli/operations/db/schema/refresh/operation.js +1 -1
  31. package/dist/cli/operations/db/schema/verify/operation.d.ts +1 -0
  32. package/dist/cli/operations/db/schema/verify/operation.js +1 -1
  33. package/dist/cli/operations/run/operation.js +1 -1
  34. package/dist/config/loader/discover-tests.d.ts +5 -0
  35. package/dist/config/loader/discover-tests.js +1 -1
  36. package/dist/config/loader/discovery.js +2 -2
  37. package/dist/config/loader/file-metadata.js +1 -1
  38. package/dist/config/loader/index.d.ts +2 -1
  39. package/dist/config/loader/index.js +1 -1
  40. package/dist/config/loader/load.d.ts +2 -0
  41. package/dist/config/loader/load.js +1 -1
  42. package/dist/config/loader/managed-configs.d.ts +2 -0
  43. package/dist/config/loader/managed-configs.js +1 -1
  44. package/dist/config/loader/paths.d.ts +1 -1
  45. package/dist/config/loader/paths.js +1 -1
  46. package/dist/config/loader/skip-config.d.ts +1 -1
  47. package/dist/config/loader/test-selection.d.ts +15 -0
  48. package/dist/config/loader/test-selection.js +1 -0
  49. package/dist/database/index.d.ts +1 -3
  50. package/dist/database/index.js +1 -1
  51. package/dist/database/lifecycle-cleanup.d.ts +7 -0
  52. package/dist/database/lifecycle-cleanup.js +1 -0
  53. package/dist/database/local-postgres.js +1 -1
  54. package/dist/database/schema-source.js +3 -3
  55. package/dist/engines/adapters/evidence-files.js +1 -1
  56. package/dist/engines/catalog.d.ts +3 -8
  57. package/dist/engines/catalog.js +1 -1
  58. package/dist/engines/definitions.d.ts +8 -1
  59. package/dist/engines/definitions.js +1 -1
  60. package/dist/engines/generated-performance.d.ts +1 -0
  61. package/dist/engines/generated-performance.js +12 -0
  62. package/dist/engines/installations/node-vitest.d.ts +8 -22
  63. package/dist/engines/installations/node-vitest.js +1 -1
  64. package/dist/engines/installations/package-requirements.d.ts +28 -0
  65. package/dist/engines/installations/package-requirements.js +1 -0
  66. package/dist/engines/installations/playwright.d.ts +1 -11
  67. package/dist/engines/installations/playwright.js +1 -1
  68. package/dist/engines/k6/adapter/repository-configuration.d.ts +1 -1
  69. package/dist/engines/k6/adapter/repository-configuration.js +1 -1
  70. package/dist/engines/managed-module-resolution.js +111 -21
  71. package/dist/engines/manager.d.ts +1 -0
  72. package/dist/engines/manager.js +1 -1
  73. package/dist/engines/node-vitest/adapter/adapter.d.ts +1 -1
  74. package/dist/engines/node-vitest/adapter/adapter.js +1 -1
  75. package/dist/engines/node-vitest/adapter/consumer-typescript-paths.js +1 -1
  76. package/dist/engines/node-vitest/adapter/resolution.d.ts +1 -1
  77. package/dist/engines/node-vitest/adapter/resolution.js +1 -1
  78. package/dist/engines/node-vitest/adapter/workspace.js +33 -9
  79. package/dist/engines/node-vitest/runtime/runtime-input.d.ts +1 -0
  80. package/dist/engines/node-vitest/runtime/runtime-input.js +1 -1
  81. package/dist/engines/runtime-input-file.d.ts +3 -1
  82. package/dist/engines/runtime-input-file.js +1 -1
  83. package/dist/environment/lifecycle-controller.d.ts +1 -2
  84. package/dist/environment/lifecycle-controller.js +1 -1
  85. package/dist/environment/lifecycle.js +1 -1
  86. package/dist/environment/maintenance.d.ts +1 -1
  87. package/dist/environment/maintenance.js +1 -1
  88. package/dist/environment/ready-environment.d.ts +1 -1
  89. package/dist/environment/ready-environment.js +1 -1
  90. package/dist/environment/runtime-contexts.d.ts +1 -1
  91. package/dist/environment/runtime-contexts.js +1 -1
  92. package/dist/environment/runtime-preparation.js +1 -1
  93. package/dist/environment/services.js +1 -1
  94. package/dist/environment/template.d.ts +1 -1
  95. package/dist/environment/template.js +1 -1
  96. package/dist/evidence/bundles.js +1 -1
  97. package/dist/evidence/read-run.js +1 -1
  98. package/dist/evidence/reading.d.ts +1 -1
  99. package/dist/evidence/reading.js +1 -1
  100. package/dist/evidence/storage.js +2 -2
  101. package/dist/kernel/error-serialization.js +1 -1
  102. package/dist/kernel/work-metrics.d.ts +6 -0
  103. package/dist/kernel/work-metrics.js +1 -0
  104. package/dist/process/capture-output.js +1 -1
  105. package/dist/process/execa-bundle.json +1 -1
  106. package/dist/process/files/product-dir.d.ts +1 -0
  107. package/dist/process/files/product-dir.js +1 -0
  108. package/dist/process/locks.js +4 -4
  109. package/dist/process/readiness.js +1 -1
  110. package/dist/process/runs/inspection.d.ts +5 -0
  111. package/dist/process/runs/inspection.js +1 -0
  112. package/dist/process/runs/manifest.d.ts +1 -0
  113. package/dist/process/runs/manifest.js +1 -1
  114. package/dist/process/service-processes.d.ts +1 -1
  115. package/dist/process/service-processes.js +1 -1
  116. package/dist/toolchains/index.js +2 -2
  117. package/docs/engine-architecture.md +4 -1
  118. package/docs/test-types.md +9 -0
  119. package/package.json +2 -1
  120. package/dist/cli/renderers/artifact-preview.d.ts +0 -4
  121. package/dist/cli/renderers/artifact-preview.js +0 -1
@@ -1 +1 @@
1
- import{requireNativeEvidenceJson as O}from"./native-report.js";import S from"node:crypto";import{constants as R}from"node:fs";import d from"node:fs/promises";import F from"node:path";import{readOnlyNoFollowOpenFlags as I,sameFileSnapshot as U,samePathAndHandleFileSnapshot as C}from"../../process/files/file-snapshot.js";const z=64*1024;export const evidenceFileAccess={lstat:async t=>d.lstat(t,{bigint:!0}),openReadOnly:async t=>d.open(t,I(process.platform,R)),platform:process.platform,readChunk:async(t,e)=>(await t.read(e,0,e.byteLength,null)).bytesRead,statHandle:async t=>t.stat({bigint:!0})};export function stableEvidenceFromBuffer(t){return{contents:t,sha256:S.createHash("sha256").update(t).digest("hex"),sizeBytes:t.byteLength}}export async function readStableJsonFile(t,e,n,r){let o;try{o=await readStableEvidenceFile(t,e,n,r)}catch(i){if(L(i))return{file:null,value:null};throw i}let a;try{a=JSON.parse(o.contents.toString("utf8"))}catch(i){throw new Error(`${n} is not valid JSON`,{cause:i})}return O(a,n),{file:o,value:a}}export async function readStableEvidenceFile(t,e,n,r,o){const a=await r.lstat(t);u(a,e,n),o!==void 0&&E(o,a,n);const i=await r.openReadOnly(t);try{const w=await r.statHandle(i);u(w,e,n),m(a,w,n,r.platform);const p=[],l=S.createHash("sha256");let h=0;const s=Buffer.allocUnsafe(z);for(;;){const f=await r.readChunk(i,s);if(N(f,s.byteLength,n),f===0)break;if(h+=f,h>e)throw new Error(`${n} exceeds its ${e.toString()} byte limit`);const g=Buffer.from(s.subarray(0,f));p.push(g),l.update(g)}const c=await r.statHandle(i),y=await r.lstat(t);if(u(c,e,n),u(y,e,n),E(w,c,n),E(a,y,n),m(y,c,n,r.platform),BigInt(h)!==w.size)throw new Error(`${n} changed while it was read`);return{contents:Buffer.concat(p,h),sha256:l.digest("hex"),sizeBytes:h}}finally{await i.close()}}export async function writeOwnedEvidenceFile(t,e,n){const r=F.join(t,e),o=F.join(t,`.${e}.${S.randomUUID()}.tmp`);let a=null;try{return a=await d.open(o,"wx",384),await a.writeFile(n),await a.sync(),await a.close(),a=null,await d.rename(o,r),process.platform!=="win32"&&await d.chmod(r,384),r}catch(i){throw a!==null&&await a.close().catch(()=>{}),await d.rm(o,{force:!0}).catch(()=>{}),i}}export async function snapshotStableEvidenceFile(t,e,n,r,o,a,i){const w=await r.lstat(t);u(w,e,n),E(o,w,n);const p=await r.openReadOnly(t),l=F.join(a,i),h=F.join(a,`.${i}.${S.randomUUID()}.tmp`);let s=null;try{const c=await r.statHandle(p);u(c,e,n),m(w,c,n,r.platform),s=await d.open(h,"wx",384);const y=S.createHash("sha256");let f=0;const g=Buffer.allocUnsafe(z);for(;;){const $=await r.readChunk(p,g);if(N($,g.byteLength,n),$===0)break;if(f+=$,f>e)throw new Error(`${n} exceeds its ${e.toString()} byte limit`);const k=g.subarray(0,$);await s.write(k),y.update(k)}const v=await r.statHandle(p),H=await r.lstat(t);if(u(v,e,n),u(H,e,n),E(c,v,n),E(w,H,n),m(H,v,n,r.platform),BigInt(f)!==c.size)throw new Error(`${n} changed while it was read`);return await s.sync(),await s.close(),s=null,await d.rename(h,l),process.platform!=="win32"&&await d.chmod(l,384),{filePath:l,identity:{sha256:y.digest("hex"),sizeBytes:f}}}catch(c){throw s!==null&&await s.close().catch(()=>{}),await d.rm(h,{force:!0}).catch(()=>{}),c}finally{await p.close()}}export function evidenceArtifact(t,e,n,r,o,a){return{contentType:n,kind:r,metadata:{sha256:e.sha256,sizeBytes:e.sizeBytes},name:o,path:t,summary:a}}function N(t,e,n){if(!Number.isSafeInteger(t)||t<0||t>e)throw new Error(`${n} returned an invalid read length`)}function u(t,e,n){if(!t.isFile()||t.isSymbolicLink())throw new Error(`${n} must be a regular non-symbolic-link file`);if(t.size<0n||t.size>BigInt(e))throw new Error(`${n} exceeds its ${e.toString()} byte limit`)}function E(t,e,n){if(!U(t,e))throw new Error(`${n} changed while it was read`)}function m(t,e,n,r){if(!C(t,e,r))throw new Error(`${n} changed while it was read`)}function L(t){return t instanceof Error&&"code"in t&&t.code==="ENOENT"}
1
+ import{requireNativeEvidenceJson as N}from"./native-report.js";import E from"node:crypto";import{constants as O}from"node:fs";import d from"node:fs/promises";import F from"node:path";import{readOnlyNoFollowOpenFlags as R,sameFileSnapshot as U,samePathAndHandleFileSnapshot as C}from"../../process/files/file-snapshot.js";const z=64*1024;export const evidenceFileAccess={lstat:async t=>d.lstat(t,{bigint:!0}),openReadOnly:async t=>d.open(t,R(process.platform,O)),platform:process.platform,readChunk:async(t,n)=>(await t.read(n,0,n.byteLength,null)).bytesRead,statHandle:async t=>t.stat({bigint:!0})};export function stableEvidenceFromBuffer(t){return{contents:t,sha256:E.createHash("sha256").update(t).digest("hex"),sizeBytes:t.byteLength}}export async function readStableJsonFile(t,n,e,r){let i;try{i=await readStableEvidenceFile(t,n,e,r)}catch(o){if(L(o))return{file:null,value:null};throw o}let a;try{a=JSON.parse(i.contents.toString("utf8"))}catch(o){throw new Error(`${e} is not valid JSON`,{cause:o})}return N(a,e),{file:i,value:a}}export async function readStableEvidenceFile(t,n,e,r,i){const a=i??await r.lstat(t);u(a,n,e);const o=await r.openReadOnly(t);try{const w=await r.statHandle(o);u(w,n,e),m(a,w,e,r.platform);const p=[],l=E.createHash("sha256");let h=0;const s=Buffer.allocUnsafe(z);for(;;){const f=await r.readChunk(o,s);if(I(f,s.byteLength,e),f===0)break;if(h+=f,h>n)throw new Error(`${e} exceeds its ${n.toString()} byte limit`);const g=Buffer.from(s.subarray(0,f));p.push(g),l.update(g)}const c=await r.statHandle(o),y=await r.lstat(t);if(u(c,n,e),u(y,n,e),S(w,c,e),S(a,y,e),m(y,c,e,r.platform),BigInt(h)!==w.size)throw new Error(`${e} changed while it was read`);return{contents:Buffer.concat(p,h),sha256:l.digest("hex"),sizeBytes:h}}finally{await o.close()}}export async function writeOwnedEvidenceFile(t,n,e){const r=F.join(t,n),i=F.join(t,`.${n}.${E.randomUUID()}.tmp`);let a=null;try{return a=await d.open(i,"wx",384),await a.writeFile(e),await a.sync(),await a.close(),a=null,await d.rename(i,r),process.platform!=="win32"&&await d.chmod(r,384),r}catch(o){throw a!==null&&await a.close().catch(()=>{}),await d.rm(i,{force:!0}).catch(()=>{}),o}}export async function snapshotStableEvidenceFile(t,n,e,r,i,a,o){const w=await r.lstat(t);u(w,n,e),S(i,w,e);const p=await r.openReadOnly(t),l=F.join(a,o),h=F.join(a,`.${o}.${E.randomUUID()}.tmp`);let s=null;try{const c=await r.statHandle(p);u(c,n,e),m(w,c,e,r.platform),s=await d.open(h,"wx",384);const y=E.createHash("sha256");let f=0;const g=Buffer.allocUnsafe(z);for(;;){const $=await r.readChunk(p,g);if(I($,g.byteLength,e),$===0)break;if(f+=$,f>n)throw new Error(`${e} exceeds its ${n.toString()} byte limit`);const k=g.subarray(0,$);await s.write(k),y.update(k)}const v=await r.statHandle(p),H=await r.lstat(t);if(u(v,n,e),u(H,n,e),S(c,v,e),S(w,H,e),m(H,v,e,r.platform),BigInt(f)!==c.size)throw new Error(`${e} changed while it was read`);return await s.sync(),await s.close(),s=null,await d.rename(h,l),process.platform!=="win32"&&await d.chmod(l,384),{filePath:l,identity:{sha256:y.digest("hex"),sizeBytes:f}}}catch(c){throw s!==null&&await s.close().catch(()=>{}),await d.rm(h,{force:!0}).catch(()=>{}),c}finally{await p.close()}}export function evidenceArtifact(t,n,e,r,i,a){return{contentType:e,kind:r,metadata:{sha256:n.sha256,sizeBytes:n.sizeBytes},name:i,path:t,summary:a}}function I(t,n,e){if(!Number.isSafeInteger(t)||t<0||t>n)throw new Error(`${e} returned an invalid read length`)}function u(t,n,e){if(!t.isFile()||t.isSymbolicLink())throw new Error(`${e} must be a regular non-symbolic-link file`);if(t.size<0n||t.size>BigInt(n))throw new Error(`${e} exceeds its ${n.toString()} byte limit`)}function S(t,n,e){if(!U(t,n))throw new Error(`${e} changed while it was read`)}function m(t,n,e,r){if(!C(t,n,r))throw new Error(`${e} changed while it was read`)}function L(t){return t instanceof Error&&"code"in t&&t.code==="ENOENT"}
@@ -1,11 +1,7 @@
1
1
  import type { EngineJsonObject, RunnerProfileDescriptor } from "./api/index.js";
2
2
  import { BUILT_IN_RUNNER_PROFILES } from "./definitions.js";
3
- import { type EngineId, type PublicTestType, type RunnerProfileId } from "../domain/identifiers.js";
4
- export interface EngineProfileIdentity {
5
- readonly engineId: EngineId;
6
- readonly profileId: RunnerProfileId;
7
- readonly testType: PublicTestType;
8
- }
3
+ import type { EngineId, PublicTestType, RunnerProfileId } from "../domain/identifiers.js";
4
+ export { isEngineProfileIdentity, type EngineProfileIdentity } from "./definitions.js";
9
5
  export interface EngineCatalog {
10
6
  readonly profiles: readonly RunnerProfileDescriptor[];
11
7
  profilesForTestType(testType: PublicTestType): readonly RunnerProfileDescriptor[];
@@ -14,7 +10,6 @@ export interface EngineCatalog {
14
10
  export declare const BUILT_IN_ENGINE_CATALOG: EngineCatalog;
15
11
  export { BUILT_IN_RUNNER_PROFILES };
16
12
  export declare function resolveEngineProfile<Id extends EngineId>(testType: PublicTestType, engineId: Id): RunnerProfileDescriptor<Id>;
17
- export declare function isEngineProfileIdentity(value: unknown): value is EngineProfileIdentity;
18
13
  type EngineAuthoringModule = "@gfdelarue/testkit/k6" | "@gfdelarue/testkit/node-vitest/data" | "@gfdelarue/testkit/node-vitest/contract" | "@gfdelarue/testkit/playwright";
19
14
  export interface EngineAuthoringProfile {
20
15
  readonly engineId: EngineId;
@@ -25,7 +20,7 @@ export interface ManagedPublicPackageOwner {
25
20
  name: string;
26
21
  }
27
22
  export type EngineConfigurations = Readonly<Partial<Record<EngineId, EngineJsonObject>>>;
28
- export declare function buildEngineConfigurations(config: object, engineIds: ReadonlySet<EngineId>): EngineConfigurations | undefined;
23
+ export declare function buildEngineConfigurations(config: object, engineIds: ReadonlySet<EngineId>): Promise<EngineConfigurations | undefined>;
29
24
  export declare function expectedEngineAuthoringModule(profileId: RunnerProfileId): EngineAuthoringModule;
30
25
  export declare function invalidEngineAuthoringImport(filePath: string, metadata: Readonly<EngineAuthoringProfile>, specifier: string, expectedModule?: EngineAuthoringModule): Error;
31
26
  export declare function requireMatchingHostImport(filePath: string, metadata: Readonly<EngineAuthoringProfile>, specifier: string): void;
@@ -1 +1 @@
1
- import{builtinModules as s}from"node:module";import{NODE_VITEST_PACKAGE_REQUIREMENTS as u,NODE_VITEST_PRIVATE_PACKAGE_PREFIXES as d}from"./installations/node-vitest.js";import{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS as p}from"./installations/playwright.js";import{buildK6RepositoryConfiguration as f}from"./k6/adapter/repository-configuration.js";import{BUILT_IN_RUNNER_PROFILES as i}from"./definitions.js";import{isEngineId as I,isPublicTestType as l,isRunnerProfileId as c}from"../domain/identifiers.js";export const BUILT_IN_ENGINE_CATALOG=Object.freeze({profiles:i,profilesForTestType(e){return Object.freeze(i.filter(n=>n.supportedTestTypes.includes(e)))},resolve(e,n){const t=i.find(r=>r.engineId===n&&r.supportedTestTypes.includes(e));if(!t)throw new Error(`Unsupported engine/test-type pair: ${n}/${e}`);return t}});export{i as BUILT_IN_RUNNER_PROFILES};export function resolveEngineProfile(e,n){return BUILT_IN_ENGINE_CATALOG.resolve(e,n)}export function isEngineProfileIdentity(e){if(!g(e)||!l(e.testType)||!I(e.engineId)||!c(e.profileId))return!1;try{return resolveEngineProfile(e.testType,e.engineId).id===e.profileId}catch{return!1}}function g(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}const a=new Set(s.map(e=>e.replace(/^node:/u,""))),E=Object.freeze([...u.map(({packageName:e})=>Object.freeze({engineId:"node-vitest",name:e})),...p.map(({packageName:e})=>Object.freeze({engineId:"playwright",name:e}))]);export function buildEngineConfigurations(e,n){const t=n.has("k6")?f(e):void 0;return t===void 0?void 0:{k6:t}}export function expectedEngineAuthoringModule(e){switch(e){case"k6-http":case"k6-dal":return"@gfdelarue/testkit/k6";case"node-vitest-data":return"@gfdelarue/testkit/node-vitest/data";case"node-vitest-contract":return"@gfdelarue/testkit/node-vitest/contract";case"playwright-ui":return"@gfdelarue/testkit/playwright"}}export function invalidEngineAuthoringImport(e,n,t,r=expectedEngineAuthoringModule(n.profileId)){return new Error(`Invalid Testkit authoring in "${e}": ${n.engineId}/${n.profileId} may not import "${t}"; use "${r}" for this suite`)}export function requireMatchingHostImport(e,n,t){if(n.engineId==="k6"&&m(t))throw new Error(`Invalid Testkit authoring in "${e}": k6 suites may not import Node built-in module "${t}"`);if(n.engineId!=="k6"&&T(t))throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import k6 module "${t}"`);if(d.some(o=>t.startsWith(o)))throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import private Vitest implementation package "${t}"`);const r=managedPublicPackageOwner(t);if(r!==null&&r.engineId!==n.engineId)throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import ${r.engineId} package "${t}"`)}export function managedPublicPackageOwner(e){for(const n of E)if(e===n.name||e.startsWith(`${n.name}/`))return n;return null}function m(e){const n=e.replace(/^node:/u,"");return a.has(n)}function T(e){return e==="k6"||e.startsWith("k6/")}
1
+ import{builtinModules as u}from"node:module";import{NODE_VITEST_PACKAGE_REQUIREMENTS as s,NODE_VITEST_PRIVATE_PACKAGE_PREFIXES as d}from"./installations/package-requirements.js";import{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS as a}from"./installations/package-requirements.js";import{BUILT_IN_RUNNER_PROFILES as i}from"./definitions.js";export{isEngineProfileIdentity}from"./definitions.js";export const BUILT_IN_ENGINE_CATALOG=Object.freeze({profiles:i,profilesForTestType(e){return Object.freeze(i.filter(n=>n.supportedTestTypes.includes(e)))},resolve(e,n){const t=i.find(r=>r.engineId===n&&r.supportedTestTypes.includes(e));if(!t)throw new Error(`Unsupported engine/test-type pair: ${n}/${e}`);return t}});export{i as BUILT_IN_RUNNER_PROFILES};export function resolveEngineProfile(e,n){return BUILT_IN_ENGINE_CATALOG.resolve(e,n)}const p=new Set(u.map(e=>e.replace(/^node:/u,""))),l=Object.freeze([...s.map(({packageName:e})=>Object.freeze({engineId:"node-vitest",name:e})),...a.map(({packageName:e})=>Object.freeze({engineId:"playwright",name:e}))]);export async function buildEngineConfigurations(e,n){if(!n.has("k6"))return;const{buildK6RepositoryConfiguration:t}=await import("./k6/adapter/repository-configuration.js"),r=t(e);return r===void 0?void 0:{k6:r}}export function expectedEngineAuthoringModule(e){switch(e){case"k6-http":case"k6-dal":return"@gfdelarue/testkit/k6";case"node-vitest-data":return"@gfdelarue/testkit/node-vitest/data";case"node-vitest-contract":return"@gfdelarue/testkit/node-vitest/contract";case"playwright-ui":return"@gfdelarue/testkit/playwright"}}export function invalidEngineAuthoringImport(e,n,t,r=expectedEngineAuthoringModule(n.profileId)){return new Error(`Invalid Testkit authoring in "${e}": ${n.engineId}/${n.profileId} may not import "${t}"; use "${r}" for this suite`)}export function requireMatchingHostImport(e,n,t){if(n.engineId==="k6"&&g(t))throw new Error(`Invalid Testkit authoring in "${e}": k6 suites may not import Node built-in module "${t}"`);if(n.engineId!=="k6"&&I(t))throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import k6 module "${t}"`);if(d.some(o=>t.startsWith(o)))throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import private Vitest implementation package "${t}"`);const r=managedPublicPackageOwner(t);if(r!==null&&r.engineId!==n.engineId)throw new Error(`Invalid Testkit authoring in "${e}": ${n.engineId} suites may not import ${r.engineId} package "${t}"`)}export function managedPublicPackageOwner(e){for(const n of l)if(e===n.name||e.startsWith(`${n.name}/`))return n;return null}function g(e){const n=e.replace(/^node:/u,"");return p.has(n)}function I(e){return e==="k6"||e.startsWith("k6/")}
@@ -1,5 +1,5 @@
1
1
  import type { RunnerProfileDescriptor } from "./api/index.js";
2
- import type { EngineId } from "../domain/identifiers.js";
2
+ import type { EngineId, PublicTestType, RunnerProfileId } from "../domain/identifiers.js";
3
3
  import type { InternalEngineRegistrationById } from "./installation-catalog.js";
4
4
  export type EndpointReadinessOwner = "adapter" | "orchestrator-http";
5
5
  export interface BuiltInRunnerProfile<Id extends EngineId = EngineId> extends RunnerProfileDescriptor<Id> {
@@ -12,4 +12,11 @@ type BuiltInDefinitions = {
12
12
  };
13
13
  export declare const BUILT_IN_ENGINE_DEFINITIONS: BuiltInDefinitions;
14
14
  export declare const BUILT_IN_RUNNER_PROFILES: readonly BuiltInRunnerProfile[];
15
+ export interface EngineProfileIdentity {
16
+ readonly engineId: EngineId;
17
+ readonly profileId: RunnerProfileId;
18
+ readonly testType: PublicTestType;
19
+ }
20
+ /** Validate persisted identities without loading engine configuration builders. */
21
+ export declare function isEngineProfileIdentity(value: unknown): value is EngineProfileIdentity;
15
22
  export {};
@@ -1 +1 @@
1
- import{resolveK6Installation as i}from"./installations/k6.js";import{resolveNodeVitestInstallation as a}from"./installations/node-vitest.js";import{resolvePlaywrightInstallation as n}from"./installations/playwright.js";export const BUILT_IN_ENGINE_DEFINITIONS=Object.freeze({k6:Object.freeze({id:"k6",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"k6",id:"k6-http",supportedTestTypes:["int","e2e","load"],endpointReadinessOwner:"orchestrator-http"}),t({capabilities:{applicationRuntime:"none",databaseRuntime:"required",endpointAccess:"none",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"k6",id:"k6-dal",supportedTestTypes:["dal"],endpointReadinessOwner:"adapter"})]),resolveInstallation:i,async loadExecutor(){return(await import("./k6/adapter/index.js")).executeK6Engine}}),"node-vitest":Object.freeze({id:"node-vitest",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"node-vitest",id:"node-vitest-data",supportedTestTypes:["data"],endpointReadinessOwner:"adapter"}),t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"node-vitest",id:"node-vitest-contract",supportedTestTypes:["contract"],endpointReadinessOwner:"adapter"})]),resolveInstallation:a,async loadExecutor(){return(await import("./node-vitest/adapter/index.js")).executeNodeVitestEngine}}),playwright:Object.freeze({id:"playwright",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"compatible"},engineId:"playwright",id:"playwright-ui",supportedTestTypes:["ui"],endpointReadinessOwner:"orchestrator-http"})]),resolveInstallation:n,async loadExecutor(){return(await import("./playwright/adapter/index.js")).executePlaywrightEngine}})}),BUILT_IN_RUNNER_PROFILES=Object.freeze(Object.values(BUILT_IN_ENGINE_DEFINITIONS).flatMap(e=>e.profiles));function t(e){return Object.freeze(e.capabilities),Object.freeze(e.supportedTestTypes),Object.freeze(e)}
1
+ export const BUILT_IN_ENGINE_DEFINITIONS=Object.freeze({k6:Object.freeze({id:"k6",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"k6",id:"k6-http",supportedTestTypes:["int","e2e","load"],endpointReadinessOwner:"orchestrator-http"}),t({capabilities:{applicationRuntime:"none",databaseRuntime:"required",endpointAccess:"none",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"k6",id:"k6-dal",supportedTestTypes:["dal"],endpointReadinessOwner:"adapter"})]),async resolveInstallation(e){return(await import("./installations/k6.js")).resolveK6Installation(e)},async loadExecutor(){return(await import("./k6/adapter/index.js")).executeK6Engine}}),"node-vitest":Object.freeze({id:"node-vitest",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"node-vitest",id:"node-vitest-data",supportedTestTypes:["data"],endpointReadinessOwner:"adapter"}),t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"isolated"},engineId:"node-vitest",id:"node-vitest-contract",supportedTestTypes:["contract"],endpointReadinessOwner:"adapter"})]),async resolveInstallation(e){return(await import("./installations/node-vitest.js")).resolveNodeVitestInstallation(e)},async loadExecutor(){return(await import("./node-vitest/adapter/index.js")).executeNodeVitestEngine}}),playwright:Object.freeze({id:"playwright",profiles:Object.freeze([t({capabilities:{applicationRuntime:"required",databaseRuntime:"optional",endpointAccess:"published-http",executionHost:"orchestrator",runtimeIsolation:"orchestrated",taskBatching:"compatible"},engineId:"playwright",id:"playwright-ui",supportedTestTypes:["ui"],endpointReadinessOwner:"orchestrator-http"})]),async resolveInstallation(e){return(await import("./installations/playwright.js")).resolvePlaywrightInstallation(e)},async loadExecutor(){return(await import("./playwright/adapter/index.js")).executePlaywrightEngine}})}),BUILT_IN_RUNNER_PROFILES=Object.freeze(Object.values(BUILT_IN_ENGINE_DEFINITIONS).flatMap(e=>e.profiles));export function isEngineProfileIdentity(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;const i=e,n=BUILT_IN_RUNNER_PROFILES.find(a=>a.engineId===i.engineId&&a.supportedTestTypes.some(o=>o===i.testType));return n!==void 0&&n.id===i.profileId}function t(e){return Object.freeze(e.capabilities),Object.freeze(e.supportedTestTypes),Object.freeze(e)}
@@ -0,0 +1 @@
1
+ export declare function ownedGeneratedScript(source: string, label: string): string;
@@ -0,0 +1,12 @@
1
+ const t=`
2
+ function __testkitWithOwner(owner, label, callback) {
3
+ const observer = globalThis[Symbol.for("testkit.performance.observer")];
4
+ const finish = observer?.beginPerformanceOwner?.(owner, label);
5
+ try { return callback(); }
6
+ finally { finish?.(); }
7
+ }
8
+ `;export function ownedGeneratedScript(e,n){return`${t}
9
+ __testkitWithOwner("testkit", ${JSON.stringify(n)}, () => {
10
+ ${e}
11
+ });
12
+ `}
@@ -1,23 +1,6 @@
1
+ export { NODE_VITEST_PACKAGE_REQUIREMENTS, NODE_VITEST_PRIVATE_PACKAGE_PREFIXES } from "./package-requirements.js";
1
2
  import { RootPackageResolver, type ResolvedPackageEntrypoint } from "./package-resolution.js";
2
3
  import type { DirectPackageInstallation, EngineResolutionContext } from "./types.js";
3
- export declare const NODE_VITEST_PACKAGE_REQUIREMENTS: readonly [Readonly<{
4
- authoringResolution: "package-exports";
5
- packageName: "vitest";
6
- publicEntrypoints: readonly ["vitest"];
7
- }>, Readonly<{
8
- authoringResolution: "package-exports";
9
- packageName: "vite";
10
- publicEntrypoints: readonly ["vite"];
11
- }>, Readonly<{
12
- authoringResolution: "exact-entrypoint";
13
- packageName: "typescript";
14
- publicEntrypoints: readonly ["typescript"];
15
- }>, Readonly<{
16
- authoringResolution: "exact-entrypoint";
17
- packageName: "esbuild";
18
- publicEntrypoints: readonly ["esbuild"];
19
- }>];
20
- export declare const NODE_VITEST_PRIVATE_PACKAGE_PREFIXES: readonly ["@vitest/"];
21
4
  interface VitestPackageInstallation extends DirectPackageInstallation<"vitest"> {
22
5
  readonly cli: string;
23
6
  }
@@ -39,9 +22,12 @@ export interface NodeVitestInstallation {
39
22
  };
40
23
  }
41
24
  interface NodeVitestResolutionDependencies {
42
- readonly importEntrypoint: (selectedPackage: Readonly<ResolvedPackageEntrypoint>) => Promise<unknown>;
43
25
  readonly packageResolver: RootPackageResolver;
44
26
  }
45
- export declare function resolveNodeVitestInstallation(context: Readonly<EngineResolutionContext>, dependencies?: Readonly<NodeVitestResolutionDependencies>): Promise<NodeVitestInstallation>;
46
- export declare function preflightNodeVitestInstallation(installation: Readonly<NodeVitestInstallation>, context: Readonly<EngineResolutionContext>, importEntrypoint?: (selectedPackage: Readonly<ResolvedPackageEntrypoint>) => Promise<unknown>): Promise<void>;
47
- export {};
27
+ export declare function resolveNodeVitestInstallation(context: Readonly<EngineResolutionContext>, dependencies?: Readonly<NodeVitestResolutionDependencies>): NodeVitestInstallation;
28
+ export declare function preflightNodeVitestInstallation(installation: Readonly<NodeVitestInstallation>, context: Readonly<{
29
+ signal: {
30
+ readonly aborted: boolean;
31
+ readonly reason?: unknown;
32
+ };
33
+ }>, importEntrypoint?: (selectedPackage: Readonly<ResolvedPackageEntrypoint>) => Promise<unknown>): Promise<void>;
@@ -1 +1 @@
1
- import p from"node:fs";import u from"node:path";import{isPathWithin as y}from"../../process/files/paths.js";import{BrokenPackageInstallationError as l,RootPackageResolver as g,importResolvedPackageEntrypoint as f}from"./package-resolution.js";export const NODE_VITEST_PACKAGE_REQUIREMENTS=Object.freeze([Object.freeze({authoringResolution:"package-exports",packageName:"vitest",publicEntrypoints:Object.freeze(["vitest"])}),Object.freeze({authoringResolution:"package-exports",packageName:"vite",publicEntrypoints:Object.freeze(["vite"])}),Object.freeze({authoringResolution:"exact-entrypoint",packageName:"typescript",publicEntrypoints:Object.freeze(["typescript"])}),Object.freeze({authoringResolution:"exact-entrypoint",packageName:"esbuild",publicEntrypoints:Object.freeze(["esbuild"])})]),NODE_VITEST_PRIVATE_PACKAGE_PREFIXES=Object.freeze(["@vitest/"]);const E=Object.freeze({importEntrypoint:f,packageResolver:new g});export async function resolveNodeVitestInstallation(t,e=E){t.signal.throwIfAborted();const o=new Map;for(const r of NODE_VITEST_PACKAGE_REQUIREMENTS)o.set(r.packageName,e.packageResolver.resolveImportFromRoot({dependencyGroup:"dependencies",packageName:r.packageName,publicEntrypoint:r.publicEntrypoints[0]}));const i=s(o,"vitest"),n=Object.freeze({authoringEntrypoints:d(e.packageResolver),engineId:"node-vitest",packages:Object.freeze({esbuild:c(s(o,"esbuild")),typescript:c(s(o,"typescript")),vite:c(s(o,"vite")),vitest:Object.freeze({...c(i),cli:v(i,e.packageResolver)})})});return await preflightNodeVitestInstallation(n,t,e.importEntrypoint),n}function d(t){return Object.freeze({config:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/config"),contract:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/node-vitest/contract"),data:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/node-vitest/data"),root:t.resolveRootPublicEntrypoint("@gfdelarue/testkit"),rootPackageJson:t.packageJsonPath})}export async function preflightNodeVitestInstallation(t,e,o=f){for(const i of NODE_VITEST_PACKAGE_REQUIREMENTS){e.signal.throwIfAborted();const n=t.packages[i.packageName];try{const r=await o(n);await h(i.packageName,r)}catch(r){throw e.signal.throwIfAborted(),new l(n.name,n.version,`its public ${i.packageName} capability failed; reinstall without omitting optional dependencies`,{cause:k(r)})}}}function s(t,e){const o=t.get(e);if(o===void 0||o.name!==e)throw new TypeError(`Node/Vitest package resolution did not select ${e}`);return o}function c(t){return Object.freeze({entrypoint:t.entrypoint,name:t.name,root:t.root,version:t.version})}function v(t,e){try{const i=m(t.manifestPath).bin,n=typeof i=="object"&&i!==null&&!Array.isArray(i)?i.vitest:i;if(typeof n!="string"||u.isAbsolute(n))throw new TypeError("package bin.vitest must be a relative path");const r=p.realpathSync(u.resolve(t.root,n));if(!y(t.root,r)||!p.statSync(r).isFile())throw new TypeError("package bin.vitest must resolve to a contained regular file");return r}catch(o){throw e.brokenInstallation(t,"its public Vitest CLI is invalid",o)}}function m(t){const e=JSON.parse(p.readFileSync(t,"utf8"));if(typeof e!="object"||e===null||Array.isArray(e))throw new TypeError("package manifest must contain a JSON object");return e}async function h(t,e){const o=b(e,`${t} public module`);switch(t){case"vitest":a(o,"expect",t),a(o,"test",t);return;case"vite":return;case"typescript":{const i=b(o.ScriptTarget,"typescript ScriptTarget");a(o,"createSourceFile",t)("preflight.ts","export {};",i.Latest);return}case"esbuild":a(o,"stop",t),await a(o,"build",t)({stdin:{contents:"export {};",loader:"js"},write:!1})}}function b(t,e){if(typeof t!="object"||t===null)throw new TypeError(`${e} must be an object`);return t}function a(t,e,o){const i=t[e];if(typeof i!="function")throw new TypeError(`${o} public module must export function ${e}`);return i}function k(t){return t instanceof l&&t.cause!==void 0?t.cause:t}
1
+ import{NODE_VITEST_PACKAGE_REQUIREMENTS as u}from"./package-requirements.js";export{NODE_VITEST_PACKAGE_REQUIREMENTS,NODE_VITEST_PRIVATE_PACKAGE_PREFIXES}from"./package-requirements.js";import l from"node:fs";import p from"node:path";import{isPathWithin as d}from"../../process/files/paths.js";import{BrokenPackageInstallationError as f,RootPackageResolver as y,importResolvedPackageEntrypoint as g}from"./package-resolution.js";const v=Object.freeze({packageResolver:new y});export function resolveNodeVitestInstallation(t,e=v){t.signal.throwIfAborted();const o=new Map;for(const n of u)o.set(n.packageName,e.packageResolver.resolveImportFromRoot({dependencyGroup:"dependencies",packageName:n.packageName,publicEntrypoint:n.publicEntrypoints[0]}));const r=s(o,"vitest");return Object.freeze({authoringEntrypoints:m(e.packageResolver),engineId:"node-vitest",packages:Object.freeze({esbuild:c(s(o,"esbuild")),typescript:c(s(o,"typescript")),vite:c(s(o,"vite")),vitest:Object.freeze({...c(r),cli:h(r,e.packageResolver)})})})}function m(t){return Object.freeze({config:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/config"),contract:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/node-vitest/contract"),data:t.resolveRootPublicEntrypoint("@gfdelarue/testkit/node-vitest/data"),root:t.resolveRootPublicEntrypoint("@gfdelarue/testkit"),rootPackageJson:t.packageJsonPath})}export async function preflightNodeVitestInstallation(t,e,o=g){for(const r of u){b(e.signal);const i=t.packages[r.packageName];try{const n=await o(i);await k(r.packageName,n)}catch(n){throw b(e.signal),new f(i.name,i.version,`its public ${r.packageName} capability failed; reinstall without omitting optional dependencies`,{cause:T(n)})}}}function s(t,e){const o=t.get(e);if(o===void 0||o.name!==e)throw new TypeError(`Node/Vitest package resolution did not select ${e}`);return o}function c(t){return Object.freeze({entrypoint:t.entrypoint,name:t.name,root:t.root,version:t.version})}function h(t,e){try{const r=w(t.manifestPath).bin,i=typeof r=="object"&&r!==null&&!Array.isArray(r)?r.vitest:r;if(typeof i!="string"||p.isAbsolute(i))throw new TypeError("package bin.vitest must be a relative path");const n=l.realpathSync(p.resolve(t.root,i));if(!d(t.root,n)||!l.statSync(n).isFile())throw new TypeError("package bin.vitest must resolve to a contained regular file");return n}catch(o){throw e.brokenInstallation(t,"its public Vitest CLI is invalid",o)}}function w(t){const e=JSON.parse(l.readFileSync(t,"utf8"));if(typeof e!="object"||e===null||Array.isArray(e))throw new TypeError("package manifest must contain a JSON object");return e}async function k(t,e){const o=E(e,`${t} public module`);switch(t){case"vitest":a(o,"expect",t),a(o,"test",t);return;case"vite":return;case"typescript":{const r=E(o.ScriptTarget,"typescript ScriptTarget");a(o,"createSourceFile",t)("preflight.ts","export {};",r.Latest);return}case"esbuild":a(o,"stop",t),await a(o,"build",t)({stdin:{contents:"export {};",loader:"js"},write:!1})}}function E(t,e){if(typeof t!="object"||t===null)throw new TypeError(`${e} must be an object`);return t}function a(t,e,o){const r=t[e];if(typeof r!="function")throw new TypeError(`${o} public module must export function ${e}`);return r}function T(t){return t instanceof f&&t.cause!==void 0?t.cause:t}function b(t){if(t.aborted)throw t.reason instanceof Error?t.reason:new Error("Node/Vitest installation check cancelled",{cause:t.reason})}
@@ -0,0 +1,28 @@
1
+ export declare const NODE_VITEST_PACKAGE_REQUIREMENTS: readonly [Readonly<{
2
+ authoringResolution: "package-exports";
3
+ packageName: "vitest";
4
+ publicEntrypoints: readonly ["vitest"];
5
+ }>, Readonly<{
6
+ authoringResolution: "package-exports";
7
+ packageName: "vite";
8
+ publicEntrypoints: readonly ["vite"];
9
+ }>, Readonly<{
10
+ authoringResolution: "exact-entrypoint";
11
+ packageName: "typescript";
12
+ publicEntrypoints: readonly ["typescript"];
13
+ }>, Readonly<{
14
+ authoringResolution: "exact-entrypoint";
15
+ packageName: "esbuild";
16
+ publicEntrypoints: readonly ["esbuild"];
17
+ }>];
18
+ export declare const NODE_VITEST_PRIVATE_PACKAGE_PREFIXES: readonly ["@vitest/"];
19
+ export declare const PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS: readonly [Readonly<{
20
+ packageName: "@playwright/test";
21
+ publicEntrypoints: readonly ["@playwright/test", "@playwright/test/cli"];
22
+ }>, Readonly<{
23
+ packageName: "playwright";
24
+ publicEntrypoints: readonly ["playwright"];
25
+ }>, Readonly<{
26
+ packageName: "playwright-core";
27
+ publicEntrypoints: readonly ["playwright-core"];
28
+ }>];
@@ -0,0 +1 @@
1
+ export const NODE_VITEST_PACKAGE_REQUIREMENTS=Object.freeze([Object.freeze({authoringResolution:"package-exports",packageName:"vitest",publicEntrypoints:Object.freeze(["vitest"])}),Object.freeze({authoringResolution:"package-exports",packageName:"vite",publicEntrypoints:Object.freeze(["vite"])}),Object.freeze({authoringResolution:"exact-entrypoint",packageName:"typescript",publicEntrypoints:Object.freeze(["typescript"])}),Object.freeze({authoringResolution:"exact-entrypoint",packageName:"esbuild",publicEntrypoints:Object.freeze(["esbuild"])})]),NODE_VITEST_PRIVATE_PACKAGE_PREFIXES=Object.freeze(["@vitest/"]),PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS=Object.freeze([Object.freeze({packageName:"@playwright/test",publicEntrypoints:Object.freeze(["@playwright/test","@playwright/test/cli"])}),Object.freeze({packageName:"playwright",publicEntrypoints:Object.freeze(["playwright"])}),Object.freeze({packageName:"playwright-core",publicEntrypoints:Object.freeze(["playwright-core"])})]);
@@ -1,17 +1,8 @@
1
+ export { PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS } from "./package-requirements.js";
1
2
  import { type ManagedProcessResult } from "../../process/index.js";
2
3
  import { type LinuxLibc, type PlatformTarget } from "../../process/host/platform.js";
3
4
  import { RootPackageResolver } from "./package-resolution.js";
4
5
  import type { DirectPackageInstallation, EngineResolutionContext } from "./types.js";
5
- export declare const PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS: readonly [Readonly<{
6
- packageName: "@playwright/test";
7
- publicEntrypoints: readonly ["@playwright/test", "@playwright/test/cli"];
8
- }>, Readonly<{
9
- packageName: "playwright";
10
- publicEntrypoints: readonly ["playwright"];
11
- }>, Readonly<{
12
- packageName: "playwright-core";
13
- publicEntrypoints: readonly ["playwright-core"];
14
- }>];
15
6
  export interface PlaywrightPackageFamily {
16
7
  readonly cli: string;
17
8
  readonly playwright: DirectPackageInstallation<"playwright">;
@@ -82,4 +73,3 @@ export declare function parsePlaywrightChildOutput(stdout: string): ParsedChildO
82
73
  export declare function requireMatchingPlaywrightChildRequest(output: Readonly<PlaywrightChildSuccess>, request: Readonly<PlaywrightChildRequest>): void;
83
74
  export declare function requireBrowserExecutable(value: string, target: Readonly<PlatformTarget>): string;
84
75
  export declare function requireSupportedPlaywrightHost(host: Readonly<PlaywrightHost>): void;
85
- export {};
@@ -1 +1 @@
1
- import c from"node:fs";import w from"node:os";import f from"node:path";import{fileURLToPath as h}from"node:url";import{runManagedProcess as R}from"../../process/index.js";import{currentLinuxLibc as x,currentPlatformTarget as O,platformTargetKey as g,SUPPORTED_PLATFORM_TARGETS as T}from"../../process/host/platform.js";import{RootPackageResolver as m}from"./package-resolution.js";export const PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS=Object.freeze([Object.freeze({packageName:"@playwright/test",publicEntrypoints:Object.freeze(["@playwright/test","@playwright/test/cli"])}),Object.freeze({packageName:"playwright",publicEntrypoints:Object.freeze(["playwright"])}),Object.freeze({packageName:"playwright-core",publicEntrypoints:Object.freeze(["playwright-core"])})]);const _=64*1024,S=6e4,b="PLAYWRIGHT_BROWSERS_PATH",I=new Set(["npm_config_playwright_browsers_path","npm_package_config_playwright_browsers_path"]);export class PlaywrightInstallationError extends Error{code="TESTKIT_PLAYWRIGHT_INSTALLATION_INVALID";constructor(r,t){super(`Playwright installation is invalid: ${r}. Run testkit setup playwright --force.`,t),this.name="PlaywrightInstallationError"}}export class UnsupportedPlaywrightPlatformError extends Error{code="TESTKIT_PLAYWRIGHT_PLATFORM_UNSUPPORTED";constructor(r,t){super(`Playwright does not support ${g(r)}${r.platform==="linux"?` with ${t??"unknown"} libc`:""}`),this.name="UnsupportedPlaywrightPlatformError"}}export function resolvePlaywrightPackageFamily(e=new m){const[r,t,o]=PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS,i=e.resolveRequireFromRoot(u(r)),n=e.resolveImportFromRoot(u(r));A(e,i,n);const a=e.resolveRequireFromPackage(i,u(t)),s=e.resolveRequireFromPackage(a,u(o)),P=e.resolveRequirePublicEntrypoint(i,r.publicEntrypoints[1]);return Object.freeze({cli:P,playwright:p(a,"playwright"),playwrightCore:p(s,"playwright-core"),playwrightTest:p(n,"@playwright/test")})}function A(e,r,t){if(!(r.name===t.name&&r.version===t.version&&r.root===t.root))throw e.brokenInstallation(r,"the import and require public entrypoints select different physical package roots",void 0)}export function resolvePlaywrightRegistry(e){const r=e.platform==="win32"?f.win32:f.posix;if(!r.isAbsolute(e.productRoot))throw new TypeError("Playwright product root must be absolute");const t=e.configuredValue;if(t==="0")return Object.freeze({canonicalValue:"0",mode:"hermetic"});if(t!==void 0&&t.length>0){const o=r.isAbsolute(t);return Object.freeze({canonicalValue:o?r.normalize(t):r.resolve(e.productRoot,t),mode:o?"configured-absolute":"configured-relative"})}return Object.freeze({canonicalValue:r.resolve(e.productRoot,r.join(v(e.platform,e.ambientEnvironment,e.homeDirectory??w.homedir(),r),"ms-playwright")),mode:"default"})}export function playwrightRegistryEnvironment(e,r){const t={};for(const[o,i]of Object.entries(e))typeof i=="string"&&!I.has(o.toLowerCase())&&o.toUpperCase()!==b&&(t[o]=i);return t[b]=r.canonicalValue,Object.freeze(t)}export async function resolvePlaywrightInstallation(e,r={}){e.signal.throwIfAborted();const t={linuxLibc:x(),target:O()};requireSupportedPlaywrightHost(t);const o=new m,i=r.ambientEnvironment??process.env,n=resolvePlaywrightPackageFamily(o),a=resolvePlaywrightRegistry({ambientEnvironment:i,configuredValue:r.configuredRegistry??i.PLAYWRIGHT_BROWSERS_PATH,homeDirectory:w.homedir(),platform:t.target.platform,productRoot:e.productRoot}),s=await L(e,{family:n,registry:a},i);return Object.freeze({authoringEntrypoints:Object.freeze({authoring:o.resolveRootPublicEntrypoint("@gfdelarue/testkit/playwright"),root:o.resolveRootPublicEntrypoint("@gfdelarue/testkit"),rootPackageJson:o.resolveRootPublicEntrypoint("@gfdelarue/testkit/package.json")}),browserExecutable:requireBrowserExecutable(s.browserExecutable,t.target),engineId:"playwright",family:n,registry:a})}async function L(e,r,t){const o=Buffer.from(JSON.stringify(r),"utf8").toString("base64url"),i=await R({args:[j(),o],cwd:e.productRoot,displayLabel:"Playwright installation resolver",env:playwrightRegistryEnvironment(t,r.registry),executable:process.execPath,signal:e.signal,timeoutMs:S}),n=C(i);throwIfPlaywrightProcessAborted(e.signal,i,n),requireBoundedPlaywrightChildOutput(i.stdout);let a;try{a=parsePlaywrightChildOutput(i.stdout)}catch(s){throw n!==null?new PlaywrightInstallationError(`isolated resolver failed: ${n.message}`,{cause:n}):s}if(n!==null)throw new PlaywrightInstallationError(`isolated resolver failed: ${n.message}`,{cause:n});if(!a.ok){if(i.exitCode!==1||i.exitSignal!==null){const s=E(i);throw new PlaywrightInstallationError(`isolated resolver failed: ${s.message}`,{cause:s})}throw new PlaywrightInstallationError(`isolated resolver failed: ${a.error.message}`,{cause:N(a.error)})}if(i.exitCode!==0||i.exitSignal!==null){const s=E(i);throw new PlaywrightInstallationError(`isolated resolver failed: ${s.message}`,{cause:s})}return requireMatchingPlaywrightChildRequest(a,r),a}export function throwIfPlaywrightProcessAborted(e,r,t){if(e.aborted){if(!k(r)||t===null){e.throwIfAborted();return}throw t===e.reason?t:new AggregateError([e.reason,t],"Playwright process was cancelled and process cleanup also failed",{cause:e.reason})}}function k(e){return e.terminationError!==null||e.error!==null||e.timedOut||e.outputLimitExceeded}export function requireBoundedPlaywrightChildOutput(e){if(Buffer.byteLength(e,"utf8")>_)throw new PlaywrightInstallationError("isolated resolver returned oversized output")}export function parsePlaywrightChildOutput(e){let r;try{r=JSON.parse(e)}catch(t){throw new PlaywrightInstallationError("isolated resolver did not return bounded JSON",{cause:t})}if(!l(r)||typeof r.ok!="boolean")throw new PlaywrightInstallationError("isolated resolver returned an invalid response");if(!r.ok){if(!l(r.error)||typeof r.error.name!="string"||typeof r.error.message!="string"||r.error.code!==void 0&&typeof r.error.code!="string")throw new PlaywrightInstallationError("isolated resolver returned an invalid error");return{error:{...r.error.code===void 0?{}:{code:r.error.code},message:r.error.message,name:r.error.name},ok:!1}}if(typeof r.browserExecutable!="string"||!z(r.family)||!$(r.registry))throw new PlaywrightInstallationError("isolated resolver returned an invalid installation");return{browserExecutable:r.browserExecutable,family:r.family,ok:!0,registry:r.registry}}export function requireMatchingPlaywrightChildRequest(e,r){if(JSON.stringify(e.family)!==JSON.stringify(r.family))throw new PlaywrightInstallationError("isolated resolver selected a different physical package family");if(e.registry.canonicalValue!==r.registry.canonicalValue||e.registry.mode!==r.registry.mode)throw new PlaywrightInstallationError("isolated resolver selected a different browser registry")}export function requireBrowserExecutable(e,r){if(!f.isAbsolute(e))throw new PlaywrightInstallationError(`public chromium.executablePath() returned a non-absolute path ${JSON.stringify(e)}`);let t;try{t=c.statSync(e)}catch(o){throw new PlaywrightInstallationError(`public chromium.executablePath() returned missing path ${JSON.stringify(e)}`,{cause:o})}if(!t.isFile())throw new PlaywrightInstallationError(`public chromium.executablePath() must identify a regular file; received ${JSON.stringify(e)}`);if(r.platform!=="win32")try{c.accessSync(e,c.constants.X_OK)}catch(o){throw new PlaywrightInstallationError(`public chromium.executablePath() is not executable: ${JSON.stringify(e)}`,{cause:o})}return e}export function requireSupportedPlaywrightHost(e){const r=g(e.target);if(!T.some(t=>g(t)===r)||e.target.platform==="linux"&&e.linuxLibc!=="glibc")throw new UnsupportedPlaywrightPlatformError(e.target,e.linuxLibc)}function v(e,r,t,o){return e==="linux"?r.XDG_CACHE_HOME||o.join(d(t),".cache"):e==="darwin"?o.join(d(t),"Library","Caches"):r.LOCALAPPDATA||o.join(d(t),"AppData","Local")}function d(e){if(e.length===0)throw new TypeError("Playwright default registry requires a home directory");return e}function u(e){return{dependencyGroup:"dependencies",packageName:e.packageName,publicEntrypoint:e.publicEntrypoints[0]}}function p(e,r){if(e.name!==r)throw new TypeError(`Playwright package family expected ${r}, received ${e.name}`);return Object.freeze({entrypoint:e.entrypoint,name:r,root:e.root,version:e.version})}function j(){const e=h(new URL("./playwright-resolution-child.js",import.meta.url));return c.existsSync(e)?e:h(new URL("../../../dist/engines/installations/playwright-resolution-child.js",import.meta.url))}function C(e){return e.terminationError!==null?e.terminationError:e.error!==null?e.error:e.timedOut?new Error("isolated resolver timed out"):e.cancelled?new Error("isolated resolver was cancelled"):e.outputLimitExceeded?new Error("isolated resolver output exceeded the bound"):null}function E(e){return new Error(`isolated resolver exited with ${e.exitCode===null?String(e.exitSignal):e.exitCode.toString()}`)}function N(e){const r=new Error(e.message);return r.name=e.name,e.code!==void 0&&Object.defineProperty(r,"code",{enumerable:!0,value:e.code}),r}function z(e){return l(e)&&typeof e.cli=="string"&&y(e.playwrightTest,"@playwright/test")&&y(e.playwright,"playwright")&&y(e.playwrightCore,"playwright-core")}function y(e,r){return l(e)&&e.name===r&&typeof e.version=="string"&&typeof e.root=="string"&&typeof e.entrypoint=="string"}function $(e){return l(e)&&typeof e.canonicalValue=="string"&&(e.mode==="configured-absolute"||e.mode==="configured-relative"||e.mode==="default"||e.mode==="hermetic")}function l(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}
1
+ import{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS as R}from"./package-requirements.js";export{PLAYWRIGHT_PACKAGE_FAMILY_REQUIREMENTS}from"./package-requirements.js";import c from"node:fs";import w from"node:os";import f from"node:path";import{fileURLToPath as h}from"node:url";import{runManagedProcess as x}from"../../process/index.js";import{currentLinuxLibc as T,currentPlatformTarget as _,platformTargetKey as d,SUPPORTED_PLATFORM_TARGETS as I}from"../../process/host/platform.js";import{RootPackageResolver as m}from"./package-resolution.js";const A=64*1024,O=6e4,b="PLAYWRIGHT_BROWSERS_PATH",S=new Set(["npm_config_playwright_browsers_path","npm_package_config_playwright_browsers_path"]);export class PlaywrightInstallationError extends Error{code="TESTKIT_PLAYWRIGHT_INSTALLATION_INVALID";constructor(r,t){super(`Playwright installation is invalid: ${r}. Run testkit setup playwright --force.`,t),this.name="PlaywrightInstallationError"}}export class UnsupportedPlaywrightPlatformError extends Error{code="TESTKIT_PLAYWRIGHT_PLATFORM_UNSUPPORTED";constructor(r,t){super(`Playwright does not support ${d(r)}${r.platform==="linux"?` with ${t??"unknown"} libc`:""}`),this.name="UnsupportedPlaywrightPlatformError"}}export function resolvePlaywrightPackageFamily(e=new m){const[r,t,o]=R,i=e.resolveRequireFromRoot(u(r)),n=e.resolveImportFromRoot(u(r));L(e,i,n);const a=e.resolveRequireFromPackage(i,u(t)),s=e.resolveRequireFromPackage(a,u(o)),P=e.resolveRequirePublicEntrypoint(i,r.publicEntrypoints[1]);return Object.freeze({cli:P,playwright:p(a,"playwright"),playwrightCore:p(s,"playwright-core"),playwrightTest:p(n,"@playwright/test")})}function L(e,r,t){if(!(r.name===t.name&&r.version===t.version&&r.root===t.root))throw e.brokenInstallation(r,"the import and require public entrypoints select different physical package roots",void 0)}export function resolvePlaywrightRegistry(e){const r=e.platform==="win32"?f.win32:f.posix;if(!r.isAbsolute(e.productRoot))throw new TypeError("Playwright product root must be absolute");const t=e.configuredValue;if(t==="0")return Object.freeze({canonicalValue:"0",mode:"hermetic"});if(t!==void 0&&t.length>0){const o=r.isAbsolute(t);return Object.freeze({canonicalValue:o?r.normalize(t):r.resolve(e.productRoot,t),mode:o?"configured-absolute":"configured-relative"})}return Object.freeze({canonicalValue:r.resolve(e.productRoot,r.join(C(e.platform,e.ambientEnvironment,e.homeDirectory??w.homedir(),r),"ms-playwright")),mode:"default"})}export function playwrightRegistryEnvironment(e,r){const t={};for(const[o,i]of Object.entries(e))typeof i=="string"&&!S.has(o.toLowerCase())&&o.toUpperCase()!==b&&(t[o]=i);return t[b]=r.canonicalValue,Object.freeze(t)}export async function resolvePlaywrightInstallation(e,r={}){e.signal.throwIfAborted();const t={linuxLibc:T(),target:_()};requireSupportedPlaywrightHost(t);const o=new m,i=r.ambientEnvironment??process.env,n=resolvePlaywrightPackageFamily(o),a=resolvePlaywrightRegistry({ambientEnvironment:i,configuredValue:r.configuredRegistry??i.PLAYWRIGHT_BROWSERS_PATH,homeDirectory:w.homedir(),platform:t.target.platform,productRoot:e.productRoot}),s=await k(e,{family:n,registry:a},i);return Object.freeze({authoringEntrypoints:Object.freeze({authoring:o.resolveRootPublicEntrypoint("@gfdelarue/testkit/playwright"),root:o.resolveRootPublicEntrypoint("@gfdelarue/testkit"),rootPackageJson:o.resolveRootPublicEntrypoint("@gfdelarue/testkit/package.json")}),browserExecutable:requireBrowserExecutable(s.browserExecutable,t.target),engineId:"playwright",family:n,registry:a})}async function k(e,r,t){const o=Buffer.from(JSON.stringify(r),"utf8").toString("base64url"),i=await x({args:[N(),o],cwd:e.productRoot,displayLabel:"Playwright installation resolver",env:playwrightRegistryEnvironment(t,r.registry),executable:process.execPath,signal:e.signal,timeoutMs:O}),n=j(i);throwIfPlaywrightProcessAborted(e.signal,i,n),requireBoundedPlaywrightChildOutput(i.stdout);let a;try{a=parsePlaywrightChildOutput(i.stdout)}catch(s){throw n!==null?new PlaywrightInstallationError(`isolated resolver failed: ${n.message}`,{cause:n}):s}if(n!==null)throw new PlaywrightInstallationError(`isolated resolver failed: ${n.message}`,{cause:n});if(!a.ok){if(i.exitCode!==1||i.exitSignal!==null){const s=E(i);throw new PlaywrightInstallationError(`isolated resolver failed: ${s.message}`,{cause:s})}throw new PlaywrightInstallationError(`isolated resolver failed: ${a.error.message}`,{cause:M(a.error)})}if(i.exitCode!==0||i.exitSignal!==null){const s=E(i);throw new PlaywrightInstallationError(`isolated resolver failed: ${s.message}`,{cause:s})}return requireMatchingPlaywrightChildRequest(a,r),a}export function throwIfPlaywrightProcessAborted(e,r,t){if(e.aborted){if(!v(r)||t===null){e.throwIfAborted();return}throw t===e.reason?t:new AggregateError([e.reason,t],"Playwright process was cancelled and process cleanup also failed",{cause:e.reason})}}function v(e){return e.terminationError!==null||e.error!==null||e.timedOut||e.outputLimitExceeded}export function requireBoundedPlaywrightChildOutput(e){if(Buffer.byteLength(e,"utf8")>A)throw new PlaywrightInstallationError("isolated resolver returned oversized output")}export function parsePlaywrightChildOutput(e){let r;try{r=JSON.parse(e)}catch(t){throw new PlaywrightInstallationError("isolated resolver did not return bounded JSON",{cause:t})}if(!l(r)||typeof r.ok!="boolean")throw new PlaywrightInstallationError("isolated resolver returned an invalid response");if(!r.ok){if(!l(r.error)||typeof r.error.name!="string"||typeof r.error.message!="string"||r.error.code!==void 0&&typeof r.error.code!="string")throw new PlaywrightInstallationError("isolated resolver returned an invalid error");return{error:{...r.error.code===void 0?{}:{code:r.error.code},message:r.error.message,name:r.error.name},ok:!1}}if(typeof r.browserExecutable!="string"||!$(r.family)||!H(r.registry))throw new PlaywrightInstallationError("isolated resolver returned an invalid installation");return{browserExecutable:r.browserExecutable,family:r.family,ok:!0,registry:r.registry}}export function requireMatchingPlaywrightChildRequest(e,r){if(JSON.stringify(e.family)!==JSON.stringify(r.family))throw new PlaywrightInstallationError("isolated resolver selected a different physical package family");if(e.registry.canonicalValue!==r.registry.canonicalValue||e.registry.mode!==r.registry.mode)throw new PlaywrightInstallationError("isolated resolver selected a different browser registry")}export function requireBrowserExecutable(e,r){if(!f.isAbsolute(e))throw new PlaywrightInstallationError(`public chromium.executablePath() returned a non-absolute path ${JSON.stringify(e)}`);let t;try{t=c.statSync(e)}catch(o){throw new PlaywrightInstallationError(`public chromium.executablePath() returned missing path ${JSON.stringify(e)}`,{cause:o})}if(!t.isFile())throw new PlaywrightInstallationError(`public chromium.executablePath() must identify a regular file; received ${JSON.stringify(e)}`);if(r.platform!=="win32")try{c.accessSync(e,c.constants.X_OK)}catch(o){throw new PlaywrightInstallationError(`public chromium.executablePath() is not executable: ${JSON.stringify(e)}`,{cause:o})}return e}export function requireSupportedPlaywrightHost(e){const r=d(e.target);if(!I.some(t=>d(t)===r)||e.target.platform==="linux"&&e.linuxLibc!=="glibc")throw new UnsupportedPlaywrightPlatformError(e.target,e.linuxLibc)}function C(e,r,t,o){return e==="linux"?r.XDG_CACHE_HOME||o.join(g(t),".cache"):e==="darwin"?o.join(g(t),"Library","Caches"):r.LOCALAPPDATA||o.join(g(t),"AppData","Local")}function g(e){if(e.length===0)throw new TypeError("Playwright default registry requires a home directory");return e}function u(e){return{dependencyGroup:"dependencies",packageName:e.packageName,publicEntrypoint:e.publicEntrypoints[0]}}function p(e,r){if(e.name!==r)throw new TypeError(`Playwright package family expected ${r}, received ${e.name}`);return Object.freeze({entrypoint:e.entrypoint,name:r,root:e.root,version:e.version})}function N(){const e=h(new URL("./playwright-resolution-child.js",import.meta.url));return c.existsSync(e)?e:h(new URL("../../../dist/engines/installations/playwright-resolution-child.js",import.meta.url))}function j(e){return e.terminationError!==null?e.terminationError:e.error!==null?e.error:e.timedOut?new Error("isolated resolver timed out"):e.cancelled?new Error("isolated resolver was cancelled"):e.outputLimitExceeded?new Error("isolated resolver output exceeded the bound"):null}function E(e){return new Error(`isolated resolver exited with ${e.exitCode===null?String(e.exitSignal):e.exitCode.toString()}`)}function M(e){const r=new Error(e.message);return r.name=e.name,e.code!==void 0&&Object.defineProperty(r,"code",{enumerable:!0,value:e.code}),r}function $(e){return l(e)&&typeof e.cli=="string"&&y(e.playwrightTest,"@playwright/test")&&y(e.playwright,"playwright")&&y(e.playwrightCore,"playwright-core")}function y(e,r){return l(e)&&e.name===r&&typeof e.version=="string"&&typeof e.root=="string"&&typeof e.entrypoint=="string"}function H(e){return l(e)&&typeof e.canonicalValue=="string"&&(e.mode==="configured-absolute"||e.mode==="configured-relative"||e.mode==="default"||e.mode==="hermetic")}function l(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}
@@ -1,2 +1,2 @@
1
- import { type EngineJsonObject } from "../../api/index.js";
1
+ import type { EngineJsonObject } from "../../api/evidence.js";
2
2
  export declare function buildK6RepositoryConfiguration(config: object): EngineJsonObject | undefined;
@@ -1 +1 @@
1
- import{normalizeEngineJsonValue as c}from"../../api/index.js";import{K6_REPOSITORY_CONFIGURATION_VERSION as u}from"../../contracts/k6-repository-configuration.js";export function buildK6RepositoryConfiguration(e){const t=i(e,"profiles","testkit config profiles");if(t===void 0)return;const o=i(t,"http","testkit config profiles.http");if(o===void 0)return;const r=[];for(const[n,s]of Object.entries(o)){if(n.trim().length===0)throw new TypeError("testkit config profiles.http keys must be non-empty");r.push([n,p(s,`testkit config profiles.http.${n}`)])}const f=Object.fromEntries(r);return Object.freeze({httpProfiles:Object.freeze(f),kind:"testkit-k6-repository-configuration",version:u})}function p(e,t){try{return Object.freeze({kind:"json",value:l(c(e,t),t)})}catch(o){throw new TypeError(`${t} cannot cross the Node/k6 runtime boundary. Repository profiles must be JSON-only. Define setup and header functions in the k6 suite module instead.`,{cause:o})}}function l(e,t){if(e===null||Array.isArray(e)||typeof e!="object")throw new TypeError(`${t} must be a JSON object`);return e}function i(e,t,o){const r=Reflect.get(e,t);if(r!=null){if(!d(r))throw new TypeError(`${o} must be an object`);return r}}function d(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}
1
+ import{normalizeEngineJsonValue as c}from"../../api/runtime-artifact.js";import{K6_REPOSITORY_CONFIGURATION_VERSION as u}from"../../contracts/k6-repository-configuration.js";export function buildK6RepositoryConfiguration(e){const t=i(e,"profiles","testkit config profiles");if(t===void 0)return;const o=i(t,"http","testkit config profiles.http");if(o===void 0)return;const r=[];for(const[n,s]of Object.entries(o)){if(n.trim().length===0)throw new TypeError("testkit config profiles.http keys must be non-empty");r.push([n,p(s,`testkit config profiles.http.${n}`)])}const f=Object.fromEntries(r);return Object.freeze({httpProfiles:Object.freeze(f),kind:"testkit-k6-repository-configuration",version:u})}function p(e,t){try{return Object.freeze({kind:"json",value:l(c(e,t),t)})}catch(o){throw new TypeError(`${t} cannot cross the Node/k6 runtime boundary. Repository profiles must be JSON-only. Define setup and header functions in the k6 suite module instead.`,{cause:o})}}function l(e,t){if(e===null||Array.isArray(e)||typeof e!="object")throw new TypeError(`${t} must be a JSON object`);return e}function i(e,t,o){const r=Reflect.get(e,t);if(r!=null){if(!d(r))throw new TypeError(`${o} must be an object`);return r}}function d(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}
@@ -1,9 +1,10 @@
1
- import{inspectManagedNodeModuleResolutionPolicy as o}from"./managed-module-resolution-policy.js";export function createManagedNodeModuleResolution(e){const t=o(e),n={...t.direct};for(const[a,i]of Object.entries(t.packageExports)){const r=i.import??i.default??i.require;r!==null&&(n[a]=r)}return Object.freeze({aliases:Object.freeze(n),bootstrapSource:s(t),dependencyRoots:t.managedImporterRoots})}export function managedNodeModuleResolutionBootstrapSource(e){return createManagedNodeModuleResolution(e).bootstrapSource}function s(e){return`
1
+ import{ownedGeneratedScript as o}from"./generated-performance.js";import{inspectManagedNodeModuleResolutionPolicy as s}from"./managed-module-resolution-policy.js";export function createManagedNodeModuleResolution(e){const t=s(e),n={...t.direct};for(const[a,i]of Object.entries(t.packageExports)){const r=i.import??i.default??i.require;r!==null&&(n[a]=r)}return Object.freeze({aliases:Object.freeze(n),bootstrapSource:c(t),dependencyRoots:t.managedImporterRoots})}export function managedNodeModuleResolutionBootstrapSource(e){return createManagedNodeModuleResolution(e).bootstrapSource}function c(e){return o(`
2
2
  const fs = require("node:fs");
3
3
  const path = require("node:path");
4
- const { registerHooks } = require("node:module");
4
+ const { isBuiltin, registerHooks } = require("node:module");
5
5
  const { fileURLToPath, pathToFileURL } = require("node:url");
6
6
 
7
+ let canonicalPaths = null;
7
8
  const POLICY = Object.freeze(${JSON.stringify(e)});
8
9
  const CONSUMER_ROOTS = Object.freeze(
9
10
  POLICY.consumerRoots.map((root) => verifiedDirectory(root, "consumer root")),
@@ -15,6 +16,9 @@ const DIRECT = new Map(
15
16
  ]),
16
17
  );
17
18
  const PACKAGE_ROOTS = verifyPackageRoots(POLICY.packageRoots, "native");
19
+ const PRIVATE_NATIVE_SCOPES = Object.freeze(
20
+ POLICY.managedImporterRoots.filter((root) => !Object.values(PACKAGE_ROOTS).includes(root)),
21
+ );
18
22
  const DIRECT_BRIDGE_ROOTS = Object.freeze(
19
23
  POLICY.directBridgeRoots.map((root) =>
20
24
  verifiedDirectory(root, "direct bridge root"),
@@ -68,7 +72,30 @@ if (existing !== undefined) {
68
72
  // tools that register asynchronous loaders. Resolution is the complete
69
73
  // policy here, so do not install a load hook that has no policy to enforce.
70
74
  const hooks = registerHooks({
71
- resolve(specifier, context, nextResolve) {
75
+ resolve(specifier, context, nativeResolve) {
76
+ const nextResolve = (specifier, context) => {
77
+ canonicalPaths = new Map();
78
+ try { return __testkitWithOwner("external", "Native module resolution", () => nativeResolve(specifier, context)); }
79
+ finally { canonicalPaths = new Map(); }
80
+ };
81
+ return __testkitWithOwner("testkit", "Testkit managed resolution policy", () => {
82
+ const previousPaths = canonicalPaths;
83
+ canonicalPaths = new Map();
84
+ try {
85
+ // Builtins and physically native-internal file edges need no package graph scan.
86
+ // A downstream resolver may redirect either one, so inspect its result.
87
+ let nativeResult;
88
+ if (isBuiltin(specifier) && !DIRECT.has(specifier)) {
89
+ nativeResult = nextResolve(specifier, context);
90
+ if (isBuiltin(nativeResult.url)) return nativeResult;
91
+ }
92
+ const nativeOrigin = specifier.startsWith("./") || specifier.startsWith("../") || specifier.startsWith("file:") || path.isAbsolute(specifier)
93
+ ? nativeFileOrigin(specifier, context.parentURL) : null;
94
+ if (nativeOrigin !== null) {
95
+ nativeResult = nextResolve(specifier, context);
96
+ if (sameNativePackageEdge(nativeOrigin, context.parentURL, nativeResult.url))
97
+ return nativeResult;
98
+ }
72
99
  const conditions = normalizedConditions(context.conditions);
73
100
  const classified = classifyResolvedSpecifier(specifier, context.parentURL);
74
101
  requireAllowedResolvedSpecifier(classified);
@@ -106,7 +133,7 @@ if (existing !== undefined) {
106
133
  forbiddenPackage,
107
134
  );
108
135
  }
109
- const resolved = nextResolve(specifier, context);
136
+ const resolved = nativeResult ?? nextResolve(specifier, context);
110
137
  const resolvedClassification = classifyResolvedSpecifier(
111
138
  resolved.url,
112
139
  context.parentURL,
@@ -121,6 +148,8 @@ if (existing !== undefined) {
121
148
  if (redirected !== null) return redirected;
122
149
  }
123
150
  return resolved;
151
+ } finally { canonicalPaths = previousPaths; }
152
+ });
124
153
  },
125
154
  });
126
155
  Object.defineProperty(globalThis, STATE, {
@@ -131,6 +160,66 @@ if (existing !== undefined) {
131
160
  });
132
161
  }
133
162
 
163
+ function recordResolutionWork(metric) {
164
+ globalThis[Symbol.for("testkit.work.observer")]?.observer?.(metric, 1);
165
+ }
166
+
167
+ function observedRealpath(file) {
168
+ recordResolutionWork("resolver.realpath");
169
+ // Match policy inspection on Windows: native realpath expands 8.3 names and
170
+ // changes their spelling, mixing physical paths with the inspected roots.
171
+ return process.platform === "win32" ? fs.realpathSync(file) : fs.realpathSync.native(file);
172
+ }
173
+
174
+ function observedRead(file, encoding) {
175
+ recordResolutionWork("resolver.read");
176
+ return fs.readFileSync(file, encoding);
177
+ }
178
+
179
+ function observedExists(file) {
180
+ recordResolutionWork("resolver.exists");
181
+ return fs.existsSync(file);
182
+ }
183
+
184
+ function nativeFileOrigin(specifier, parentURL) {
185
+ const requestedPath = specifier.startsWith("file:") ? fileURLToPath(specifier) : path.isAbsolute(specifier) ? specifier : null;
186
+ // A lexical miss only skips this optimization; all trust uses fresh physical paths.
187
+ if (requestedPath !== null && ![...Object.values(PACKAGE_ROOTS), ...PRIVATE_NATIVE_SCOPES].some(root => isPathWithin(root, requestedPath))) return null;
188
+ if (typeof parentURL !== "string" || !parentURL.startsWith("file:")) return null;
189
+ try {
190
+ const file = observedRealpath(fileURLToPath(parentURL));
191
+ const root = nativePackageRoot(file);
192
+ if (root === undefined) return null;
193
+ if (requestedPath !== null) {
194
+ const requested = observedRealpath(requestedPath);
195
+ if (!isPathWithin(root, requested)) return null;
196
+ }
197
+ return { file, root };
198
+ } catch { return null; }
199
+ }
200
+
201
+ function nativePackageRoot(file) {
202
+ const selected = Object.values(PACKAGE_ROOTS).find((root) => isPathWithin(root, file));
203
+ if (selected !== undefined) return selected;
204
+ for (const scope of PRIVATE_NATIVE_SCOPES) {
205
+ if (!isPathWithin(scope, file)) continue;
206
+ const relative = path.relative(scope, file);
207
+ const separator = relative.indexOf(path.sep);
208
+ if (separator > 0) return path.join(scope, relative.slice(0, separator));
209
+ }
210
+ return undefined;
211
+ }
212
+
213
+ function sameNativePackageEdge(origin, parentURL, targetURL) {
214
+ // Trust never survives another resolver changing the importer or its root.
215
+ if (observedRealpath(fileURLToPath(parentURL)) !== origin.file ||
216
+ observedRealpath(origin.root) !== origin.root)
217
+ throw new Error("Managed " + POLICY.engineLabel + " native importer changed during resolution");
218
+ if (typeof targetURL !== "string" || !targetURL.startsWith("file:")) return false;
219
+ try { return isPathWithin(origin.root, observedRealpath(fileURLToPath(targetURL))); }
220
+ catch { return false; }
221
+ }
222
+
134
223
  function resolveManagedSpecifier(specifier, conditions, parentURL) {
135
224
  const direct = DIRECT.get(specifier);
136
225
  if (direct !== undefined)
@@ -185,9 +274,9 @@ function nearestPackageManifest(importerFile) {
185
274
  let directory = path.dirname(importerFile);
186
275
  while (true) {
187
276
  const manifestFile = path.join(directory, "package.json");
188
- if (fs.existsSync(manifestFile)) {
277
+ if (observedExists(manifestFile)) {
189
278
  try {
190
- const manifest = JSON.parse(fs.readFileSync(manifestFile, "utf8"));
279
+ const manifest = JSON.parse(observedRead(manifestFile, "utf8"));
191
280
  if (isObject(manifest)) return manifest;
192
281
  } catch {}
193
282
  return null;
@@ -376,10 +465,7 @@ function unclassified() {
376
465
  function resolvedFileCandidates(file) {
377
466
  const resolved = path.resolve(file);
378
467
  const candidates = [];
379
- try {
380
- const canonical = fs.realpathSync(file);
381
- candidates.push(canonical);
382
- } catch {}
468
+ candidates.push(canonicalPath(file));
383
469
  if (!candidates.includes(resolved)) candidates.push(resolved);
384
470
  return candidates;
385
471
  }
@@ -391,8 +477,8 @@ function classifyPackageBoundaries(file, parentURL) {
391
477
  if (scanBoundary !== null && canonicalPath(directory) === scanBoundary)
392
478
  return null;
393
479
  const manifestFile = path.join(directory, "package.json");
394
- if (fs.existsSync(manifestFile)) {
395
- const manifest = JSON.parse(fs.readFileSync(manifestFile, "utf8"));
480
+ if (observedExists(manifestFile)) {
481
+ const manifest = JSON.parse(observedRead(manifestFile, "utf8"));
396
482
  const packageName =
397
483
  typeof manifest.name === "string" ? manifest.name : null;
398
484
  if (packageName !== null && Object.hasOwn(PACKAGE_ROOTS, packageName))
@@ -637,7 +723,7 @@ function verifyPackageRoots(roots, kind) {
637
723
  Object.entries(roots).map(([packageName, root]) => {
638
724
  const canonical = canonicalPath(root);
639
725
  const manifest = JSON.parse(
640
- fs.readFileSync(path.join(canonical, "package.json"), "utf8"),
726
+ observedRead(path.join(canonical, "package.json"), "utf8"),
641
727
  );
642
728
  if (manifest.name !== packageName)
643
729
  throw new Error(
@@ -658,7 +744,7 @@ function verifiedOptionalFile(file, label) {
658
744
  }
659
745
 
660
746
  function verifiedDirectory(directory, label) {
661
- const resolved = fs.realpathSync(directory);
747
+ const resolved = observedRealpath(directory);
662
748
  if (!fs.statSync(resolved).isDirectory())
663
749
  throw new Error(
664
750
  "Managed " + POLICY.engineLabel + " " + label + " is not a directory",
@@ -667,7 +753,7 @@ function verifiedDirectory(directory, label) {
667
753
  }
668
754
 
669
755
  function verifiedFile(file, label) {
670
- const resolved = fs.realpathSync(file);
756
+ const resolved = observedRealpath(file);
671
757
  if (!fs.statSync(resolved).isFile())
672
758
  throw new Error(
673
759
  "Managed " + POLICY.engineLabel + " " + label + " is not a regular file",
@@ -676,11 +762,15 @@ function verifiedFile(file, label) {
676
762
  }
677
763
 
678
764
  function canonicalPath(file) {
679
- try {
680
- return fs.realpathSync(file);
681
- } catch {
682
- return path.resolve(file);
683
- }
765
+ // Share physical checks only within this policy decision. A later import or
766
+ // another resolver can change the filesystem and must see fresh identities.
767
+ const cached = canonicalPaths?.get(file);
768
+ if (cached !== undefined) return cached;
769
+ let canonical;
770
+ try { canonical = observedRealpath(file); }
771
+ catch { canonical = path.resolve(file); }
772
+ canonicalPaths?.set(file, canonical);
773
+ return canonical;
684
774
  }
685
775
 
686
776
  function sameFile(left, right) {
@@ -696,4 +786,4 @@ function isPathWithin(root, candidate) {
696
786
  !path.isAbsolute(relative))
697
787
  );
698
788
  }
699
- `}
789
+ `,"Testkit managed resolution bootstrap")}
@@ -18,6 +18,7 @@ export declare class EngineExecutorLoadError extends Error {
18
18
  export declare class EngineManager {
19
19
  private readonly catalog;
20
20
  private readonly productRoot;
21
+ private readonly installations;
21
22
  constructor(options: Readonly<EngineManagerOptions>);
22
23
  resolve<Id extends EngineId>(engineId: Id): InternalEngineRegistration<Id>;
23
24
  withEngine<Id extends EngineId, Result>(engineId: Id, signal: AbortSignal, operation: (session: ResolvedEngineExecutionSession<Id>) => Result | PromiseLike<Result>): Promise<Result>;
@@ -1 +1 @@
1
- import{ENGINE_PROTOCOL_LIMITS as d,beginEngineExecution as E,createEngineInvocationScope as g}from"./api/index.js";import"../domain/identifiers.js";export class EngineExecutorLoadError extends Error{code="TESTKIT_ENGINE_EXECUTOR_LOAD_FAILED";engineId;constructor(e,o){super(`Resolved ${e} executor could not be loaded`,o),this.name="EngineExecutorLoadError",this.engineId=e}}export class EngineManager{catalog;productRoot;constructor(e){this.catalog=e.catalog,this.productRoot=e.productRoot}resolve(e){return this.catalog.resolve(e)}async withEngine(e,o,r){const a=this.resolve(e);o.throwIfAborted();const c=await a.resolveInstallation({productRoot:this.productRoot,signal:o});return o.throwIfAborted(),r(h(a,c))}}function h(t,e){return Object.freeze({engineId:t.id,async execute(o){u(o.signal);const r=E(o),a=g({timeoutMs:d.cleanupTimeoutMs});let c=null,i,s=!1;try{const l=await w(t);u(o.signal),c=r.acceptResult(await l(r.request,e,a.scope))}catch(l){s=!0,i=l}finally{r.close()}const n=await a.drain();if(s)throw n.length===0?i:new AggregateError([i,...n],`Engine invocation failed and ${n.length.toString()} cleanup handler(s) also failed`,{cause:i});if(n.length>0)throw new AggregateError(n,`${n.length.toString()} engine invocation cleanup handler(s) failed`);if(c===null)throw new Error("Engine invocation completed without a result");return r.commit(),c}})}function u(t){if(t.aborted)throw t.reason instanceof Error?t.reason:new Error("Resolved engine invocation was cancelled",{cause:t.reason})}async function w(t){try{return await t.loadExecutor()}catch(e){throw new EngineExecutorLoadError(t.id,{cause:e})}}
1
+ import{ENGINE_PROTOCOL_LIMITS as d,beginEngineExecution as E,createEngineInvocationScope as h}from"./api/index.js";import"../domain/identifiers.js";export class EngineExecutorLoadError extends Error{code="TESTKIT_ENGINE_EXECUTOR_LOAD_FAILED";engineId;constructor(t,o){super(`Resolved ${t} executor could not be loaded`,o),this.name="EngineExecutorLoadError",this.engineId=t}}export class EngineManager{catalog;productRoot;installations=new WeakMap;constructor(t){this.catalog=t.catalog,this.productRoot=t.productRoot}resolve(t){return this.catalog.resolve(t)}async withEngine(t,o,i){const c=this.resolve(t);o.throwIfAborted();let n=this.installations.get(o);n||(n=new Map,this.installations.set(o,n));let r=n.get(t);if(!r){const a=n;r=c.resolveInstallation({productRoot:this.productRoot,signal:o}).catch(l=>{throw a.delete(t),l}),a.set(t,r)}const s=await r;return o.throwIfAborted(),i(w(c,s))}}function w(e,t){return Object.freeze({engineId:e.id,async execute(o){u(o.signal);const i=E(o),c=h({timeoutMs:d.cleanupTimeoutMs});let n=null,r,s=!1;try{const l=await g(e);u(o.signal),n=i.acceptResult(await l(i.request,t,c.scope))}catch(l){s=!0,r=l}finally{i.close()}const a=await c.drain();if(s)throw a.length===0?r:new AggregateError([r,...a],`Engine invocation failed and ${a.length.toString()} cleanup handler(s) also failed`,{cause:r});if(a.length>0)throw new AggregateError(a,`${a.length.toString()} engine invocation cleanup handler(s) failed`);if(n===null)throw new Error("Engine invocation completed without a result");return i.commit(),n}})}function u(e){if(e.aborted)throw e.reason instanceof Error?e.reason:new Error("Resolved engine invocation was cancelled",{cause:e.reason})}async function g(e){try{return await e.loadExecutor()}catch(t){throw new EngineExecutorLoadError(e.id,{cause:t})}}
@@ -1,7 +1,7 @@
1
1
  import { type ProcessClassification } from "../../adapters/execution.js";
2
2
  import { type EngineExecutionRequest, type EngineExecutionResult, type EngineFailureEvidence, type EngineInvocationScope } from "../../api/index.js";
3
3
  import { type ManagedProcessResult } from "../../../process/index.js";
4
- import type { NodeVitestInstallation } from "../../installations/node-vitest.js";
4
+ import { type NodeVitestInstallation } from "../../installations/node-vitest.js";
5
5
  import { type CollectedNodeVitestEvidence } from "./evidence.js";
6
6
  import { writeOwnedNodeVitestRuntimeInput, type NodeVitestRuntimeInputDocument } from "../runtime/runtime-input.js";
7
7
  import { writeNodeVitestWorkspace } from "./workspace.js";