Found while reviewing #15. All four items are pre-existing — git diff main...HEAD -- lib/lab.js on that branch touches none of these typedefs — so they were deliberately kept out of a no-behaviour-change refactor rather than folded in.
Each was confirmed by type-checking a consumer project against the shipped types/ output under node16 resolution. Exact errors below.
1. LabPlanOptions rejects the options the CLI actually passes
lib/lab.js documents it as "shared lab options plus plan-level controls", and runLabPlan spreads everything except continueOnError / reuseBrowser / repeats / _runLab / _launch into labOptions. The type declares only the plan-level controls.
error TS2353: Object literal may only specify known properties,
and 'skipAudits' does not exist in type 'LabPlanOptions'.
The same applies to categories, blockedUrlPatterns, stripJsonProps, clean and silent — every option bin/web-perf.js passes today. runLabPlan is documented as public API in the README.
Fix: @typedef {LabAuditOptions & { ... }} LabPlanOptions. LabAuditOptions now exists (added in #15), so this is a one-line intersection.
2. LabReport omits three fields that survive stripJsonProps
lib/strip-props.js strips only i18n and timing, so a default report keeps environment, runtimeError and configSettings. This repo reads two of them itself — lib/variance.js reads report.environment.benchmarkIndex, lib/lab.js reads report.runtimeError — and the README tells consumers LabReport contains "categories, audits, environment, configSettings".
error TS2339: Property 'environment' does not exist on type 'LabReport'.
error TS2339: Property 'runtimeError' does not exist on type 'LabReport'.
error TS2339: Property 'configSettings' does not exist on type 'LabReport'.
A TypeScript consumer cannot reproduce the variance flow the README describes without casting.
3. LabPlanHooks.onSummary types its summary as bare object
error TS2339: Property 'stability' does not exist on type 'object'.
bin/web-perf.js dereferences summary.stability.warnings in that exact callback. lib/lab.js already uses import('./variance').RunSummary in writeRunSummary's JSDoc, so the concrete type is one line away. Any TS consumer of the public hook has to cast.
4. CRUX_FORM_FACTORS / DEFAULT_CRUX_FORM_FACTORS are mutable and shared
Both are exported from crux and crux-history as the same array instance, and both are the default parameter value inside the client:
crux.DEFAULT_CRUX_FORM_FACTORS === cruxHistory.DEFAULT_CRUX_FORM_FACTORS // true
Object.isFrozen(...) // false
A consumer doing DEFAULT_CRUX_FORM_FACTORS.push('tablet') changes the default for both commands for the rest of the process, silently tripling requests per URL against the 25,000/day quota. lib/prompts.js already defends itself with [...DEFAULT_CRUX_FORM_FACTORS], which shows the hazard was understood.
Worth stating plainly: this predates #15. On main, crux-history.js already imported and re-exported crux's arrays, so the aliasing is not new — the refactor only moved where they are declared.
Fix: Object.freeze both, or export copies.
Verification
npm run lint, npm test, npm run generate-types, plus a re-run of the consumer type-check showing the five errors above are gone.
Found while reviewing #15. All four items are pre-existing —
git diff main...HEAD -- lib/lab.json that branch touches none of these typedefs — so they were deliberately kept out of a no-behaviour-change refactor rather than folded in.Each was confirmed by type-checking a consumer project against the shipped
types/output undernode16resolution. Exact errors below.1.
LabPlanOptionsrejects the options the CLI actually passeslib/lab.jsdocuments it as "shared lab options plus plan-level controls", andrunLabPlanspreads everything exceptcontinueOnError/reuseBrowser/repeats/_runLab/_launchintolabOptions. The type declares only the plan-level controls.The same applies to
categories,blockedUrlPatterns,stripJsonProps,cleanandsilent— every optionbin/web-perf.jspasses today.runLabPlanis documented as public API in the README.Fix:
@typedef {LabAuditOptions & { ... }} LabPlanOptions.LabAuditOptionsnow exists (added in #15), so this is a one-line intersection.2.
LabReportomits three fields that survivestripJsonPropslib/strip-props.jsstrips onlyi18nandtiming, so a default report keepsenvironment,runtimeErrorandconfigSettings. This repo reads two of them itself —lib/variance.jsreadsreport.environment.benchmarkIndex,lib/lab.jsreadsreport.runtimeError— and the README tells consumersLabReportcontains "categories, audits, environment, configSettings".A TypeScript consumer cannot reproduce the variance flow the README describes without casting.
3.
LabPlanHooks.onSummarytypes its summary as bareobjectbin/web-perf.jsdereferencessummary.stability.warningsin that exact callback.lib/lab.jsalready usesimport('./variance').RunSummaryinwriteRunSummary's JSDoc, so the concrete type is one line away. Any TS consumer of the public hook has to cast.4.
CRUX_FORM_FACTORS/DEFAULT_CRUX_FORM_FACTORSare mutable and sharedBoth are exported from
cruxandcrux-historyas the same array instance, and both are the default parameter value inside the client:A consumer doing
DEFAULT_CRUX_FORM_FACTORS.push('tablet')changes the default for both commands for the rest of the process, silently tripling requests per URL against the 25,000/day quota.lib/prompts.jsalready defends itself with[...DEFAULT_CRUX_FORM_FACTORS], which shows the hazard was understood.Worth stating plainly: this predates #15. On
main,crux-history.jsalready imported and re-exported crux's arrays, so the aliasing is not new — the refactor only moved where they are declared.Fix:
Object.freezeboth, or export copies.Verification
npm run lint,npm test,npm run generate-types, plus a re-run of the consumer type-check showing the five errors above are gone.