lighthouse 13.4.1-dev.20260916 → 13.5.0-dev.20260917

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.
@@ -35,6 +35,7 @@ declare class Baseline extends Audit {
35
35
  "array-flat": string;
36
36
  "array-from": string;
37
37
  "array-fromasync": string;
38
+ "array-group": string;
38
39
  "array-includes": string;
39
40
  "array-isarray": string;
40
41
  "array-iteration-methods": string;
@@ -101,6 +102,7 @@ declare class Baseline extends Audit {
101
102
  "change-event": string;
102
103
  "channel-messaging": string;
103
104
  charset: string;
105
+ "check-visibility": string;
104
106
  cite: string;
105
107
  "class-syntax": string;
106
108
  "clip-path": string;
@@ -450,6 +452,7 @@ declare class Baseline extends Audit {
450
452
  "promise-allsettled": string;
451
453
  "promise-any": string;
452
454
  "promise-finally": string;
455
+ "promise-withresolvers": string;
453
456
  "proxy-reflect": string;
454
457
  push: string;
455
458
  q: string;
@@ -574,6 +577,7 @@ declare class Baseline extends Audit {
574
577
  title: string;
575
578
  "title-attr": string;
576
579
  "touch-action": string;
580
+ "transferable-arraybuffer": string;
577
581
  transforms2d: string;
578
582
  transforms3d: string;
579
583
  transitions: string;
@@ -605,6 +609,7 @@ declare class Baseline extends Audit {
605
609
  "wasm-bigint": string;
606
610
  "wasm-bulk-memory": string;
607
611
  "wasm-exception-handling": string;
612
+ "wasm-extended-constant-expressions": string;
608
613
  "wasm-multi-value": string;
609
614
  "wasm-mutable-globals": string;
610
615
  "wasm-non-trapping-float-to-int": string;
@@ -659,15 +664,16 @@ declare class Baseline extends Audit {
659
664
  "abs-sign": string;
660
665
  "active-view-transition": string;
661
666
  "align-content-block": string;
667
+ alpha: string;
662
668
  "alt-text-generated-content": string;
663
- "array-group": string;
664
669
  "async-clipboard": string;
670
+ "async-iterable-streams": string;
665
671
  "atomics-pause": string;
666
672
  "atomics-wait-async": string;
673
+ autocorrect: string;
667
674
  "backdrop-filter": string;
668
675
  "baseline-shift": string;
669
676
  "canvas-2d-willreadfrequently": string;
670
- "check-visibility": string;
671
677
  "clipboard-supports": string;
672
678
  "composed-ranges": string;
673
679
  "container-style-queries": string;
@@ -704,17 +710,19 @@ declare class Baseline extends Audit {
704
710
  "json-raw": string;
705
711
  "largest-contentful-paint": string;
706
712
  "light-dark": string;
713
+ "light-dark-image": string;
707
714
  "link-rel-dns-prefetch": string;
708
715
  "math-sum-precise": string;
709
716
  navigation: string;
710
717
  "open-pseudo": string;
718
+ "overflow-anchor": string;
711
719
  "page-setup": string;
712
720
  "paint-order": string;
713
721
  "parse-html-unsafe": string;
714
722
  popover: string;
715
723
  "print-color-adjust": string;
724
+ "progress-function": string;
716
725
  "promise-try": string;
717
- "promise-withresolvers": string;
718
726
  rcap: string;
719
727
  rch: string;
720
728
  "readable-byte-streams": string;
@@ -752,7 +760,7 @@ declare class Baseline extends Audit {
752
760
  "text-wrap": string;
753
761
  "text-wrap-balance": string;
754
762
  "toggleevent-source": string;
755
- "transferable-arraybuffer": string;
763
+ "top-level-await": string;
756
764
  "transform-box": string;
757
765
  "transition-behavior": string;
758
766
  "trusted-types": string;
@@ -763,8 +771,8 @@ declare class Baseline extends Audit {
763
771
  "view-transitions": string;
764
772
  "wasm-branch-hinting": string;
765
773
  "wasm-exnref-exceptions": string;
766
- "wasm-extended-constant-expressions": string;
767
774
  "wasm-garbage-collection": string;
775
+ "wasm-jspi": string;
768
776
  "wasm-tail-call-optimization": string;
769
777
  "wasm-typed-fun-refs": string;
770
778
  "webgl-color-management": string;
@@ -1,5 +1,6 @@
1
1
  export type NavigationOptions = {
2
2
  waitUntil: Array<"fcp" | "load" | "navigated">;
3
+ signal?: AbortSignal;
3
4
  } & Partial<LH.Config.Settings>;
4
5
  /**
5
6
  * Navigates to the given URL, assuming that the page is not already on this URL.
@@ -39,7 +39,7 @@ const DEFAULT_NETWORK_QUIET_THRESHOLD = 5000;
39
39
  // Controls how long to wait between longtasks before determining the CPU is idle, off by default
40
40
  const DEFAULT_CPU_QUIET_THRESHOLD = 0;
41
41
 
42
- /** @typedef {{waitUntil: Array<'fcp'|'load'|'navigated'>} & Partial<LH.Config.Settings>} NavigationOptions */
42
+ /** @typedef {{waitUntil: Array<'fcp'|'load'|'navigated'>, signal?: AbortSignal} & Partial<LH.Config.Settings>} NavigationOptions */
43
43
 
44
44
  /** @param {NavigationOptions} options */
45
45
  function resolveWaitForFullyLoadedOptions(options) {
@@ -107,23 +107,49 @@ async function gotoURL(driver, requestor, options) {
107
107
 
108
108
  /** @type {Array<Promise<{timedOut: boolean}>>} */
109
109
  const waitConditionPromises = [];
110
+ /** @type {Array<() => void>} */
111
+ const cleanups = [];
112
+
113
+ /** @type {(event: Event) => void} */
114
+ let onAbort = () => {};
115
+ /** @type {Promise<never>} */
116
+ const abortPromise = new Promise((_, reject) => {
117
+ if (!options.signal) return;
118
+ options.signal.throwIfAborted();
119
+ onAbort = () => reject(new Error('Navigation aborted by signal'));
120
+ options.signal.addEventListener('abort', onAbort, {once: true});
121
+ });
122
+ if (options.signal) cleanups.push(() => options.signal?.removeEventListener('abort', onAbort));
110
123
 
111
124
  if (waitForNavigated) {
112
- const navigatedPromise = waitForFrameNavigated(session).promise;
113
- waitConditionPromises.push(navigatedPromise.then(() => ({timedOut: false})));
125
+ const {promise, cancel} = waitForFrameNavigated(session);
126
+ cleanups.push(() => cancel());
127
+ waitConditionPromises.push(promise
128
+ .then(() => ({timedOut: false}))
129
+ .catch(() => ({timedOut: false})));
114
130
  }
115
131
 
116
132
  if (waitForLoad) {
117
133
  const waitOptions = resolveWaitForFullyLoadedOptions(options);
118
- waitConditionPromises.push(waitForFullyLoaded(session, networkMonitor, waitOptions));
134
+ waitConditionPromises.push(
135
+ waitForFullyLoaded(session, networkMonitor, waitOptions, options.signal)
136
+ );
119
137
  } else if (waitForFcp) {
120
138
  throw new Error('Cannot wait for FCP without waiting for page load');
121
139
  }
122
140
 
123
- const waitConditions = await Promise.race([
141
+ const waitConditionsRace = [
124
142
  session.onCrashPromise(),
125
143
  Promise.all(waitConditionPromises),
126
- ]);
144
+ ];
145
+ if (options.signal) waitConditionsRace.push(abortPromise);
146
+
147
+ let waitConditions;
148
+ try {
149
+ waitConditions = await Promise.race(waitConditionsRace);
150
+ } finally {
151
+ for (const cleanup of cleanups) cleanup();
152
+ }
127
153
  const timedOut = waitConditions.some(condition => condition.timedOut);
128
154
  const navigationUrls = await networkMonitor.getNavigationUrls();
129
155
 
@@ -142,7 +168,9 @@ async function gotoURL(driver, requestor, options) {
142
168
  const mainDocumentUrl = navigationUrls.mainDocumentUrl || requestedUrl;
143
169
 
144
170
  // Bring `Page.navigate` errors back into the promise chain. See https://github.com/GoogleChrome/lighthouse/pull/6739.
145
- await waitForNavigationTriggered;
171
+ await Promise.race(options.signal ?
172
+ [waitForNavigationTriggered, abortPromise] :
173
+ [waitForNavigationTriggered]);
146
174
 
147
175
  if (options.debugNavigation) {
148
176
  await waitForUserToContinue(driver);
@@ -101,9 +101,10 @@ export function waitForCPUIdle(session: LH.Gatherer.ProtocolSession, waitForCPUQ
101
101
  * @param {LH.Gatherer.ProtocolSession} session
102
102
  * @param {NetworkMonitor} networkMonitor
103
103
  * @param {WaitOptions} options
104
+ * @param {AbortSignal} [signal]
104
105
  * @return {Promise<{timedOut: boolean}>}
105
106
  */
106
- export function waitForFullyLoaded(session: LH.Gatherer.ProtocolSession, networkMonitor: NetworkMonitor, options: WaitOptions): Promise<{
107
+ export function waitForFullyLoaded(session: LH.Gatherer.ProtocolSession, networkMonitor: NetworkMonitor, options: WaitOptions, signal?: AbortSignal): Promise<{
107
108
  timedOut: boolean;
108
109
  }>;
109
110
  /**
@@ -418,9 +418,10 @@ const DEFAULT_WAIT_FUNCTIONS = {waitForFcp, waitForLoadEvent, waitForCPUIdle, wa
418
418
  * @param {LH.Gatherer.ProtocolSession} session
419
419
  * @param {NetworkMonitor} networkMonitor
420
420
  * @param {WaitOptions} options
421
+ * @param {AbortSignal} [signal]
421
422
  * @return {Promise<{timedOut: boolean}>}
422
423
  */
423
- async function waitForFullyLoaded(session, networkMonitor, options) {
424
+ async function waitForFullyLoaded(session, networkMonitor, options, signal) {
424
425
  const {pauseAfterFcpMs, pauseAfterLoadMs, networkQuietThresholdMs,
425
426
  cpuQuietThresholdMs, maxWaitForLoadedMs, maxWaitForFcpMs} = options;
426
427
  const {waitForFcp, waitForLoadEvent, waitForNetworkIdle, waitForCPUIdle} =
@@ -524,12 +525,23 @@ async function waitForFullyLoaded(session, networkMonitor, options) {
524
525
  };
525
526
  });
526
527
 
528
+ /** @type {(event: Event) => void} */
529
+ let onAbort = () => {};
530
+ /** @type {Promise<() => Promise<{timedOut: boolean}>>} */
531
+ const abortPromise = new Promise((resolve) => {
532
+ signal?.throwIfAborted();
533
+ onAbort = () => resolve(async () => ({timedOut: false}));
534
+ signal?.addEventListener('abort', onAbort, {once: true});
535
+ });
536
+
527
537
  // Wait for load or timeout and run the cleanup function the winner returns.
528
538
  const cleanupFn = await Promise.race([
529
539
  loadPromise,
530
540
  maxTimeoutPromise,
541
+ abortPromise,
531
542
  ]);
532
543
 
544
+ signal?.removeEventListener('abort', onAbort);
533
545
  maxTimeoutHandle && clearTimeout(maxTimeoutHandle);
534
546
  resolveOnFcp.cancel();
535
547
  resolveOnLoadEvent.cancel();
@@ -5,17 +5,19 @@ export type NavigationContext = {
5
5
  requestor: LH.NavigationRequestor;
6
6
  baseArtifacts: LH.BaseArtifacts;
7
7
  computedCache: Map<string, LH.ArbitraryEqualityMap>;
8
+ signal?: AbortSignal | undefined;
8
9
  };
9
10
  export type PhaseState = Omit<Parameters<typeof collectPhaseArtifacts>[0], "phase">;
10
11
  /**
11
12
  * @param {LH.Puppeteer.Page|undefined} page
12
13
  * @param {LH.NavigationRequestor|undefined} requestor
13
- * @param {{config?: LH.Config, flags?: LH.Flags}} [options]
14
+ * @param {{config?: LH.Config, flags?: LH.Flags, signal?: AbortSignal }} [options]
14
15
  * @return {Promise<LH.Gatherer.GatherResult>}
15
16
  */
16
17
  export function navigationGather(page: LH.Puppeteer.Page | undefined, requestor: LH.NavigationRequestor | undefined, options?: {
17
18
  config?: LH.Config;
18
19
  flags?: LH.Flags;
20
+ signal?: AbortSignal;
19
21
  }): Promise<LH.Gatherer.GatherResult>;
20
22
  /**
21
23
  * @param {{driver: Driver, resolvedConfig: LH.Config.ResolvedConfig, requestor: LH.NavigationRequestor}} args
@@ -32,6 +32,7 @@ import {NetworkRecords} from '../computed/network-records.js';
32
32
  * @property {LH.NavigationRequestor} requestor
33
33
  * @property {LH.BaseArtifacts} baseArtifacts
34
34
  * @property {Map<string, LH.ArbitraryEqualityMap>} computedCache
35
+ * @property {AbortSignal} [signal]
35
36
  */
36
37
 
37
38
  /** @typedef {Omit<Parameters<typeof collectPhaseArtifacts>[0], 'phase'>} PhaseState */
@@ -79,12 +80,13 @@ async function _cleanupNavigation({driver}) {
79
80
  * @return {Promise<{requestedUrl: string, mainDocumentUrl: string, navigationError: LH.LighthouseError | undefined}>}
80
81
  */
81
82
  async function _navigate(navigationContext) {
82
- const {driver, resolvedConfig, requestor} = navigationContext;
83
+ const {driver, resolvedConfig, requestor, signal} = navigationContext;
83
84
 
84
85
  try {
85
86
  const {requestedUrl, mainDocumentUrl, warnings} = await gotoURL(driver, requestor, {
86
87
  ...resolvedConfig.settings,
87
88
  waitUntil: resolvedConfig.settings.pauseAfterFcpMs ? ['fcp', 'load'] : ['load'],
89
+ signal,
88
90
  });
89
91
 
90
92
  navigationContext.baseArtifacts.LighthouseRunWarnings.push(...warnings);
@@ -251,11 +253,11 @@ async function _cleanup({requestedUrl, driver, resolvedConfig, lhBrowser, lhPage
251
253
  /**
252
254
  * @param {LH.Puppeteer.Page|undefined} page
253
255
  * @param {LH.NavigationRequestor|undefined} requestor
254
- * @param {{config?: LH.Config, flags?: LH.Flags}} [options]
256
+ * @param {{config?: LH.Config, flags?: LH.Flags, signal?: AbortSignal }} [options]
255
257
  * @return {Promise<LH.Gatherer.GatherResult>}
256
258
  */
257
259
  async function navigationGather(page, requestor, options = {}) {
258
- const {flags = {}, config} = options;
260
+ const {flags = {}, config, signal} = options;
259
261
  log.setLevel(flags.logLevel || 'error');
260
262
 
261
263
  const {resolvedConfig} = await initializeConfig('navigation', config, flags);
@@ -291,6 +293,7 @@ async function navigationGather(page, requestor, options = {}) {
291
293
  resolvedConfig,
292
294
  requestor: normalizedRequestor,
293
295
  computedCache,
296
+ signal,
294
297
  };
295
298
  const {baseArtifacts} = await _setup(context);
296
299
 
@@ -24,6 +24,7 @@
24
24
  "array-flat": "2020-01-15",
25
25
  "array-from": "2016-09-20",
26
26
  "array-fromasync": "2024-01-25",
27
+ "array-group": "2024-03-05",
27
28
  "array-includes": "2016-09-20",
28
29
  "array-isarray": "2015-07-29",
29
30
  "array-iteration-methods": "2015-07-29",
@@ -90,6 +91,7 @@
90
91
  "change-event": "2015-07-29",
91
92
  "channel-messaging": "2015-09-22",
92
93
  "charset": "2015-07-29",
94
+ "check-visibility": "2024-03-05",
93
95
  "cite": "2015-07-29",
94
96
  "class-syntax": "2016-03-08",
95
97
  "clip-path": "2021-01-21",
@@ -278,7 +280,7 @@
278
280
  "input": "2015-07-29",
279
281
  "input-button": "2015-07-29",
280
282
  "input-checkbox": "2015-07-29",
281
- "input-date-time": "2021-04-26",
283
+ "input-date-time": "2021-10-05",
282
284
  "input-email-tel-url": "2015-07-29",
283
285
  "input-event": "2020-01-15",
284
286
  "input-file": "2015-07-29",
@@ -439,6 +441,7 @@
439
441
  "promise-allsettled": "2020-07-28",
440
442
  "promise-any": "2020-09-16",
441
443
  "promise-finally": "2018-10-02",
444
+ "promise-withresolvers": "2024-03-05",
442
445
  "proxy-reflect": "2016-09-20",
443
446
  "push": "2023-03-27",
444
447
  "q": "2015-07-29",
@@ -563,6 +566,7 @@
563
566
  "title": "2015-07-29",
564
567
  "title-attr": "2015-07-29",
565
568
  "touch-action": "2019-09-19",
569
+ "transferable-arraybuffer": "2024-03-05",
566
570
  "transforms2d": "2015-09-30",
567
571
  "transforms3d": "2022-03-14",
568
572
  "transitions": "2015-09-30",
@@ -594,6 +598,7 @@
594
598
  "wasm-bigint": "2021-04-26",
595
599
  "wasm-bulk-memory": "2021-10-25",
596
600
  "wasm-exception-handling": "2022-05-03",
601
+ "wasm-extended-constant-expressions": "2024-03-05",
597
602
  "wasm-multi-value": "2020-10-20",
598
603
  "wasm-mutable-globals": "2020-03-24",
599
604
  "wasm-non-trapping-float-to-int": "2021-10-25",
@@ -607,7 +612,7 @@
607
612
  "weakset": "2015-09-30",
608
613
  "web-animations": "2020-09-16",
609
614
  "web-audio": "2021-04-26",
610
- "web-cryptography": "2015-07-29",
615
+ "web-cryptography": "2017-09-19",
611
616
  "web-locks": "2022-03-14",
612
617
  "webauthn": "2021-09-07",
613
618
  "webauthn-public-key-easy": "2023-10-24",
@@ -648,15 +653,16 @@
648
653
  "abs-sign": "2025-06-26",
649
654
  "active-view-transition": "2026-01-13",
650
655
  "align-content-block": "2024-04-16",
656
+ "alpha": "2026-09-14",
651
657
  "alt-text-generated-content": "2024-07-09",
652
- "array-group": "2024-03-05",
653
658
  "async-clipboard": "2024-06-11",
659
+ "async-iterable-streams": "2026-09-14",
654
660
  "atomics-pause": "2025-04-01",
655
661
  "atomics-wait-async": "2025-11-11",
662
+ "autocorrect": "2026-09-11",
656
663
  "backdrop-filter": "2024-09-16",
657
664
  "baseline-shift": "2026-03-24",
658
665
  "canvas-2d-willreadfrequently": "2024-09-16",
659
- "check-visibility": "2024-03-05",
660
666
  "clipboard-supports": "2025-03-31",
661
667
  "composed-ranges": "2025-08-19",
662
668
  "container-style-queries": "2026-05-19",
@@ -693,17 +699,19 @@
693
699
  "json-raw": "2025-03-31",
694
700
  "largest-contentful-paint": "2025-12-12",
695
701
  "light-dark": "2024-05-13",
702
+ "light-dark-image": "2026-09-14",
696
703
  "link-rel-dns-prefetch": "2025-09-15",
697
704
  "math-sum-precise": "2026-04-10",
698
705
  "navigation": "2026-01-13",
699
706
  "open-pseudo": "2026-05-11",
707
+ "overflow-anchor": "2026-09-14",
700
708
  "page-setup": "2024-12-11",
701
709
  "paint-order": "2024-03-22",
702
710
  "parse-html-unsafe": "2025-09-15",
703
711
  "popover": "2025-01-27",
704
712
  "print-color-adjust": "2025-05-01",
713
+ "progress-function": "2026-09-01",
705
714
  "promise-try": "2025-01-07",
706
- "promise-withresolvers": "2024-03-05",
707
715
  "rcap": "2026-01-13",
708
716
  "rch": "2026-01-13",
709
717
  "readable-byte-streams": "2026-03-24",
@@ -741,7 +749,7 @@
741
749
  "text-wrap": "2024-10-17",
742
750
  "text-wrap-balance": "2024-05-13",
743
751
  "toggleevent-source": "2026-05-11",
744
- "transferable-arraybuffer": "2024-03-05",
752
+ "top-level-await": "2026-09-14",
745
753
  "transform-box": "2024-04-16",
746
754
  "transition-behavior": "2024-08-06",
747
755
  "trusted-types": "2026-02-24",
@@ -752,8 +760,8 @@
752
760
  "view-transitions": "2025-10-14",
753
761
  "wasm-branch-hinting": "2026-02-24",
754
762
  "wasm-exnref-exceptions": "2025-05-29",
755
- "wasm-extended-constant-expressions": "2024-03-05",
756
763
  "wasm-garbage-collection": "2024-12-11",
764
+ "wasm-jspi": "2026-09-14",
757
765
  "wasm-tail-call-optimization": "2024-12-11",
758
766
  "wasm-typed-fun-refs": "2024-09-16",
759
767
  "webgl-color-management": "2024-10-29",
@@ -770,7 +778,6 @@
770
778
  "accessor-methods",
771
779
  "ad-selection",
772
780
  "alignment-baseline",
773
- "alpha",
774
781
  "alternative-style-sheets",
775
782
  "ambient-light",
776
783
  "anchor-positioning",
@@ -785,7 +792,6 @@
785
792
  "app-shortcuts",
786
793
  "arguments-callee",
787
794
  "arianotify",
788
- "async-iterable-streams",
789
795
  "attr",
790
796
  "attribution-reporting",
791
797
  "audio-session",
@@ -793,7 +799,6 @@
793
799
  "audiolistener",
794
800
  "audiolistener-setposition-setorientation",
795
801
  "autocapitalize",
796
- "autocorrect",
797
802
  "autofill",
798
803
  "background-attachment",
799
804
  "background-clip-border-area",
@@ -839,10 +844,12 @@
839
844
  "contact-picker",
840
845
  "container-anchor-position-queries",
841
846
  "container-scroll-state-queries",
847
+ "container-timing",
842
848
  "content-index",
843
849
  "context-fill-stroke",
844
850
  "controls-list",
845
851
  "cookie-store",
852
+ "cookie-store-get-metadata",
846
853
  "corner-shape",
847
854
  "counter-reset-reversed",
848
855
  "cross-document-view-transitions",
@@ -922,10 +929,12 @@
922
929
  "gamepad-vr",
923
930
  "gap-decorations",
924
931
  "geolocation-element",
932
+ "geolocation-element-initialpermissionstatus",
925
933
  "getallrecords",
926
934
  "getboxquads",
927
935
  "glyph-orientation-vertical",
928
936
  "gpc",
937
+ "grid-lanes",
929
938
  "gyroscope",
930
939
  "hanging-punctuation",
931
940
  "has-slotted",
@@ -936,6 +945,8 @@
936
945
  "host-context",
937
946
  "html-media-capture",
938
947
  "html-processing-instructions",
948
+ "html-setters",
949
+ "html-streaming-setters",
939
950
  "html-wrapper-methods",
940
951
  "hyphenate-limit-chars",
941
952
  "idle-detection",
@@ -944,10 +955,14 @@
944
955
  "image-function",
945
956
  "ime-mode",
946
957
  "import-assertions",
958
+ "import-defer",
959
+ "import-maps-multiple",
947
960
  "initial-letter",
948
961
  "ink",
949
962
  "input-color",
950
963
  "input-color-alpha",
964
+ "input-date-time-month",
965
+ "input-date-time-week",
951
966
  "insertable-streams",
952
967
  "install",
953
968
  "interaction-contentful-paint",
@@ -966,8 +981,8 @@
966
981
  "languagedetector",
967
982
  "languagemodel",
968
983
  "layout-instability",
969
- "light-dark-image",
970
984
  "line-clamp",
985
+ "link-parameters",
971
986
  "link-rel-expect",
972
987
  "link-rel-prefetch",
973
988
  "loading-lazy-media",
@@ -982,7 +997,6 @@
982
997
  "margin-trim",
983
998
  "marker",
984
999
  "mask-border",
985
- "masonry",
986
1000
  "mathml-full",
987
1001
  "measure-memory",
988
1002
  "media-pseudos",
@@ -1007,7 +1021,6 @@
1007
1021
  "opaquerange",
1008
1022
  "orientation-sensor",
1009
1023
  "origin",
1010
- "overflow-anchor",
1011
1024
  "overflow-clip-margin",
1012
1025
  "overflow-overlay",
1013
1026
  "overlay",
@@ -1038,7 +1051,6 @@
1038
1051
  "private-click-measurement",
1039
1052
  "private-network-access",
1040
1053
  "profiler",
1041
- "progress-function",
1042
1054
  "protected-audience",
1043
1055
  "proto",
1044
1056
  "random-function",
@@ -1086,6 +1098,7 @@
1086
1098
  "share",
1087
1099
  "shared-storage",
1088
1100
  "shared-storage-locks",
1101
+ "shared-workers-extended-lifetime",
1089
1102
  "show-picker-input",
1090
1103
  "show-picker-select",
1091
1104
  "signature-based-resource-integrity",
@@ -1120,7 +1133,6 @@
1120
1133
  "text-spacing-trim",
1121
1134
  "text-wrap-pretty",
1122
1135
  "time-relative-selectors",
1123
- "top-level-await",
1124
1136
  "topics",
1125
1137
  "touch-events",
1126
1138
  "transferable-streams",
@@ -1139,7 +1151,6 @@
1139
1151
  "virtual-keyboard",
1140
1152
  "virtual-pressure-sources",
1141
1153
  "virtual-sensors",
1142
- "wasm-jspi",
1143
1154
  "wasm-memory64",
1144
1155
  "wasm-multi-memory",
1145
1156
  "wasm-simd-relaxed",
@@ -1,3 +1,3 @@
1
1
  {
2
- "date": "2026-08-27"
2
+ "date": "2026-09-17"
3
3
  }
@@ -13,6 +13,9 @@ export class UserFlow {
13
13
  _gatherSteps: LH.UserFlow.GatherStep[];
14
14
  /** @type {GatherStepRunnerOptions} */
15
15
  _gatherStepRunnerOptions: GatherStepRunnerOptions;
16
+ /** @type {AbortController} */
17
+ _controller: AbortController;
18
+ dispose(): void;
16
19
  /**
17
20
  * @param {LH.UserFlow.StepFlags|undefined} flags
18
21
  * @return {LH.UserFlow.StepFlags|undefined}
package/core/user-flow.js CHANGED
@@ -66,6 +66,16 @@ class UserFlow {
66
66
  this._gatherSteps = [];
67
67
  /** @type {GatherStepRunnerOptions} */
68
68
  this._gatherStepRunnerOptions = new WeakMap();
69
+ /** @type {AbortController} */
70
+ this._controller = new AbortController();
71
+
72
+ page.on('close', () => {
73
+ this.dispose();
74
+ });
75
+ }
76
+
77
+ dispose() {
78
+ this._controller.abort();
69
79
  }
70
80
 
71
81
  /**
@@ -131,6 +141,7 @@ class UserFlow {
131
141
  const gatherResult = await navigationGather(this._page, requestor, {
132
142
  config: this._options?.config,
133
143
  flags: nextFlags,
144
+ signal: this._controller.signal,
134
145
  });
135
146
 
136
147
  this._addGatherStep(gatherResult, nextFlags);
@@ -162,6 +173,7 @@ class UserFlow {
162
173
  () => new Promise(continueNavigation => completeSetup(continueNavigation)),
163
174
  stepOptions
164
175
  ).catch(err => {
176
+ if (this._controller.signal.aborted) return;
165
177
  if (this.currentNavigation) {
166
178
  // If the navigation already started, re-throw the error so it is emitted when `navigationResultPromise` is awaited.
167
179
  throw err;