diff --git a/.eslintrc.cjs b/.eslintrc.cjs index af71feccf169..ae8e16ac4841 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -76,7 +76,7 @@ module.exports = { vars: 'all', args: 'after-used', argsIgnorePattern: '(^reject$|^_+$)', - varsIgnorePattern: '(^_$|^LH$)', + varsIgnorePattern: '(^_$|^LH$|^Lantern$)', }], 'no-cond-assign': 2, 'space-infix-ops': 2, diff --git a/core/computed/load-simulator.js b/core/computed/load-simulator.js index b5f2545b32ee..eef16370b489 100644 --- a/core/computed/load-simulator.js +++ b/core/computed/load-simulator.js @@ -4,13 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../lib/lantern/types/lantern.js'; import {makeComputedArtifact} from './computed-artifact.js'; import * as constants from '../config/constants.js'; import {Simulator} from '../lib/lantern/simulator/simulator.js'; import {NetworkAnalysis} from './network-analysis.js'; -/** @typedef {import('../../types/internal/lantern.js').Lantern.Simulation.Options} SimulationOptions */ - class LoadSimulator { /** * @param {{devtoolsLog: LH.DevtoolsLog, settings: LH.Audit.Context['settings']}} data @@ -21,7 +20,7 @@ class LoadSimulator { const {throttlingMethod, throttling, precomputedLanternData} = data.settings; const networkAnalysis = await NetworkAnalysis.request(data.devtoolsLog, context); - /** @type {SimulationOptions} */ + /** @type {Lantern.Simulation.Options} */ const options = { additionalRttByOrigin: networkAnalysis.additionalRttByOrigin, serverResponseTimeByOrigin: networkAnalysis.serverResponseTimeByOrigin, diff --git a/core/lib/lantern/metric.js b/core/lib/lantern/metric.js index 47c317ed667f..536d0b74b802 100644 --- a/core/lib/lantern/metric.js +++ b/core/lib/lantern/metric.js @@ -4,13 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from './types/lantern.js'; import {BaseNode} from '../../lib/lantern/base-node.js'; import {NetworkRequest} from '../../lib/network-request.js'; /** @typedef {import('./base-node.js').Node} Node */ /** @typedef {import('./network-node.js').NetworkNode} NetworkNode */ /** @typedef {import('./simulator/simulator.js').Simulator} Simulator */ -/** @typedef {import('../../../types/internal/lantern.js').Lantern.Simulation.MetricComputationDataInput} MetricComputationDataInput */ /** * @typedef Extras @@ -43,7 +43,7 @@ class Metric { } /** - * @return {LH.Gatherer.Simulation.MetricCoefficients} + * @return {Lantern.Simulation.MetricCoefficients} */ static get COEFFICIENTS() { throw new Error('COEFFICIENTS unimplemented!'); @@ -56,7 +56,7 @@ class Metric { * settings change. * * @param {number} rttMs - * @return {LH.Gatherer.Simulation.MetricCoefficients} + * @return {Lantern.Simulation.MetricCoefficients} */ static getScaledCoefficients(rttMs) { // eslint-disable-line no-unused-vars return this.COEFFICIENTS; @@ -81,16 +81,16 @@ class Metric { } /** - * @param {LH.Gatherer.Simulation.Result} simulationResult + * @param {Lantern.Simulation.Result} simulationResult * @param {Extras} extras - * @return {LH.Gatherer.Simulation.Result} + * @return {Lantern.Simulation.Result} */ static getEstimateFromSimulation(simulationResult, extras) { // eslint-disable-line no-unused-vars return simulationResult; } /** - * @param {MetricComputationDataInput} data + * @param {Lantern.Simulation.MetricComputationDataInput} data * @param {Omit=} extras * @return {Promise} */ diff --git a/core/lib/lantern/network-node.js b/core/lib/lantern/network-node.js index 63040ba43aa2..e6adb97c0ce1 100644 --- a/core/lib/lantern/network-node.js +++ b/core/lib/lantern/network-node.js @@ -4,8 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** @template T @typedef {import('../../../types/internal/lantern.js').Lantern.NetworkRequest} NetworkRequest */ - +import * as Lantern from './types/lantern.js'; import {NetworkRequestTypes} from './lantern.js'; import {BaseNode} from './base-node.js'; // TODO(15841): bring impl of isNonNetworkRequest inside lantern and remove this. @@ -17,7 +16,7 @@ import UrlUtils from '../url-utils.js'; */ class NetworkNode extends BaseNode { /** - * @param {NetworkRequest} networkRequest + * @param {Lantern.NetworkRequest} networkRequest */ constructor(networkRequest) { super(networkRequest.requestId); @@ -51,7 +50,7 @@ class NetworkNode extends BaseNode { } /** - * @return {NetworkRequest} + * @return {Lantern.NetworkRequest} */ get request() { return this._request; diff --git a/core/lib/lantern/page-dependency-graph.js b/core/lib/lantern/page-dependency-graph.js index 3a1de4d8a94e..3c02e1fd30a6 100644 --- a/core/lib/lantern/page-dependency-graph.js +++ b/core/lib/lantern/page-dependency-graph.js @@ -4,13 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from './types/lantern.js'; import {NetworkRequestTypes} from './lantern.js'; import {NetworkNode} from './network-node.js'; import {CPUNode} from './cpu-node.js'; import {TraceProcessor} from '../tracehouse/trace-processor.js'; import {NetworkAnalyzer} from './simulator/network-analyzer.js'; -/** @typedef {import('../../../types/internal/lantern.js').Lantern.NetworkRequest} NetworkRequest */ /** @typedef {import('./base-node.js').Node} Node */ /** @typedef {Omit} URLArtifact */ @@ -31,7 +31,7 @@ const IGNORED_MIME_TYPES_REGEX = /^video/; class PageDependencyGraph { /** - * @param {NetworkRequest} record + * @param {Lantern.NetworkRequest} record * @return {Array} */ static getNetworkInitiators(record) { @@ -60,7 +60,7 @@ class PageDependencyGraph { } /** - * @param {Array} networkRecords + * @param {Array} networkRecords * @return {NetworkNodeOutput} */ static getNetworkNodeOutput(networkRecords) { @@ -394,7 +394,7 @@ class PageDependencyGraph { /** * @param {LH.Artifacts.ProcessedTrace} processedTrace - * @param {Array} networkRecords + * @param {Array} networkRecords * @param {URLArtifact} URL * @return {Node} */ diff --git a/core/lib/lantern/simulator/connection-pool.js b/core/lib/lantern/simulator/connection-pool.js index de32dff95bd8..5d09423bbf18 100644 --- a/core/lib/lantern/simulator/connection-pool.js +++ b/core/lib/lantern/simulator/connection-pool.js @@ -4,9 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** @typedef {import('../../../../types/internal/lantern.js').Lantern.NetworkRequest} NetworkRequest */ -/** @typedef {import('../../../../types/internal/lantern.js').Lantern.Simulation.Options} SimulationOptions */ - +import * as Lantern from '../types/lantern.js'; import {NetworkAnalyzer} from './network-analyzer.js'; import {TcpConnection} from './tcp-connection.js'; @@ -19,8 +17,8 @@ const CONNECTIONS_PER_ORIGIN = 6; export class ConnectionPool { /** - * @param {NetworkRequest[]} records - * @param {Required} options + * @param {Lantern.NetworkRequest[]} records + * @param {Required} options */ constructor(records, options) { this._options = options; @@ -28,7 +26,7 @@ export class ConnectionPool { this._records = records; /** @type {Map} */ this._connectionsByOrigin = new Map(); - /** @type {Map} */ + /** @type {Map} */ this._connectionsByRecord = new Map(); this._connectionsInUse = new Set(); this._connectionReusedByRequestId = NetworkAnalyzer.estimateIfConnectionWasReused(records, { @@ -126,7 +124,7 @@ export class ConnectionPool { * If ignoreConnectionReused is true, acquire will consider all connections not in use as available. * Otherwise, only connections that have matching "warmth" are considered available. * - * @param {NetworkRequest} record + * @param {Lantern.NetworkRequest} record * @param {{ignoreConnectionReused?: boolean}} options * @return {?TcpConnection} */ @@ -152,7 +150,7 @@ export class ConnectionPool { * Return the connection currently being used to fetch a record. If no connection * currently being used for this record, an error will be thrown. * - * @param {NetworkRequest} record + * @param {Lantern.NetworkRequest} record * @return {TcpConnection} */ acquireActiveConnectionFromRecord(record) { @@ -163,7 +161,7 @@ export class ConnectionPool { } /** - * @param {NetworkRequest} record + * @param {Lantern.NetworkRequest} record */ release(record) { const connection = this._connectionsByRecord.get(record); diff --git a/core/lib/lantern/simulator/dns-cache.js b/core/lib/lantern/simulator/dns-cache.js index c4ceb8a33823..97b451c34536 100644 --- a/core/lib/lantern/simulator/dns-cache.js +++ b/core/lib/lantern/simulator/dns-cache.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** @typedef {import('../../../../types/internal/lantern.js').Lantern.NetworkRequest} NetworkRequest */ +import * as Lantern from '../types/lantern.js'; // A DNS lookup will usually take ~1-2 roundtrips of connection latency plus the extra DNS routing time. // Example: https://www.webpagetest.org/result/180703_3A_e33ec79747c002ed4d7bcbfc81462203/1/details/#waterfall_view_step1 @@ -25,7 +25,7 @@ class DNSCache { } /** - * @param {NetworkRequest} request + * @param {Lantern.NetworkRequest} request * @param {{requestedAt: number, shouldUpdateCache: boolean}=} options * @return {number} */ @@ -47,7 +47,7 @@ class DNSCache { } /** - * @param {NetworkRequest} request + * @param {Lantern.NetworkRequest} request * @param {number} resolvedAt */ _updateCacheResolvedAtIfNeeded(request, resolvedAt) { diff --git a/core/lib/lantern/simulator/network-analyzer.js b/core/lib/lantern/simulator/network-analyzer.js index f598b7554da9..59e5ba51a699 100644 --- a/core/lib/lantern/simulator/network-analyzer.js +++ b/core/lib/lantern/simulator/network-analyzer.js @@ -4,8 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** @typedef {import('../../../../types/internal/lantern.js').Lantern.NetworkRequest} NetworkRequest */ - +import * as Lantern from '../types/lantern.js'; import UrlUtils from '../../url-utils.js'; const INITIAL_CWD = 14 * 1024; @@ -33,8 +32,8 @@ class NetworkAnalyzer { } /** - * @param {NetworkRequest[]} records - * @return {Map} + * @param {Lantern.NetworkRequest[]} records + * @return {Map} */ static groupByOrigin(records) { const grouped = new Map(); @@ -89,10 +88,10 @@ class NetworkAnalyzer { return summaryByKey; } - /** @typedef {{record: NetworkRequest, timing: LH.Crdp.Network.ResourceTiming, connectionReused?: boolean}} RequestInfo */ + /** @typedef {{record: Lantern.NetworkRequest, timing: LH.Crdp.Network.ResourceTiming, connectionReused?: boolean}} RequestInfo */ /** - * @param {NetworkRequest[]} records + * @param {Lantern.NetworkRequest[]} records * @param {(e: RequestInfo) => number | number[] | undefined} iteratee * @return {Map} */ @@ -251,7 +250,7 @@ class NetworkAnalyzer { /** * Given the RTT to each origin, estimates the observed server response times. * - * @param {NetworkRequest[]} records + * @param {Lantern.NetworkRequest[]} records * @param {Map} rttByOrigin * @return {Map} */ @@ -272,7 +271,7 @@ class NetworkAnalyzer { } /** - * @param {NetworkRequest[]} records + * @param {Lantern.NetworkRequest[]} records * @return {boolean} */ static canTrustConnectionInformation(records) { @@ -292,7 +291,7 @@ class NetworkAnalyzer { * Returns a map of requestId -> connectionReused, estimating the information if the information * available in the records themselves appears untrustworthy. * - * @param {NetworkRequest[]} records + * @param {Lantern.NetworkRequest[]} records * @param {{forceCoarseEstimates: boolean}} [options] * @return {Map} */ @@ -336,7 +335,7 @@ class NetworkAnalyzer { * Attempts to use the most accurate information first and falls back to coarser estimates when it * is unavailable. * - * @param {NetworkRequest[]} records + * @param {Lantern.NetworkRequest[]} records * @param {RTTEstimateOptions} [options] * @return {Map} */ @@ -417,7 +416,7 @@ class NetworkAnalyzer { * Estimates the server response time of each origin. RTT times can be passed in or will be * estimated automatically if not provided. * - * @param {NetworkRequest[]} records + * @param {Lantern.NetworkRequest[]} records * @param {RTTEstimateOptions & {rttByOrigin?: Map}} [options] * @return {Map} */ @@ -443,7 +442,7 @@ class NetworkAnalyzer { * Excludes data URI, failed or otherwise incomplete, and cached requests. * Returns Infinity if there were no analyzable network records. * - * @param {Array} networkRecords + * @param {Array} networkRecords * @return {number} */ static estimateThroughput(networkRecords) { @@ -496,7 +495,7 @@ class NetworkAnalyzer { } /** - * @template {NetworkRequest} T + * @template {Lantern.NetworkRequest} T * @param {Array} records * @param {string} resourceUrl * @return {T|undefined} @@ -510,7 +509,7 @@ class NetworkAnalyzer { } /** - * @template {NetworkRequest} T + * @template {Lantern.NetworkRequest} T * @param {Array} records * @param {string} resourceUrl * @return {T|undefined} @@ -530,7 +529,7 @@ class NetworkAnalyzer { * Resolves redirect chain given a main document. * See: {@link NetworkAnalyzer.findLastDocumentForUrl}) for how to retrieve main document. * - * @template {NetworkRequest} T + * @template {Lantern.NetworkRequest} T * @param {T} request * @return {T} */ diff --git a/core/lib/lantern/simulator/simulator.js b/core/lib/lantern/simulator/simulator.js index fa4a785b1d2a..9f342aab9045 100644 --- a/core/lib/lantern/simulator/simulator.js +++ b/core/lib/lantern/simulator/simulator.js @@ -4,13 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -// This could be replaced by jsdoc namespace import, when ready. -// https://github.com/microsoft/TypeScript/issues/41825 -/** @typedef {import('../../../../types/internal/lantern.js').Lantern.NetworkRequest} NetworkRequest */ -/** @typedef {import('../../../../types/internal/lantern.js').Lantern.Simulation.Options} SimulationOptions */ -/** @typedef {import('../../../../types/internal/lantern.js').Lantern.Simulation.NodeTiming} SimulationNodeTiming */ -/** @template T @typedef {import('../../../../types/internal/lantern.js').Lantern.Simulation.Result} SimulationResult */ - +import * as Lantern from '../types/lantern.js'; import {BaseNode} from '../base-node.js'; import {TcpConnection} from './tcp-connection.js'; import {ConnectionPool} from './connection-pool.js'; @@ -57,10 +51,10 @@ const ALL_SIMULATION_NODE_TIMINGS = new Map(); */ class Simulator { /** - * @param {SimulationOptions} [options] + * @param {Lantern.Simulation.Options} [options] */ constructor(options) { - /** @type {Required} */ + /** @type {Required} */ this._options = Object.assign( { rtt: mobileSlow4G.rttMs, @@ -110,7 +104,7 @@ class Simulator { * @param {Node} graph */ _initializeConnectionPool(graph) { - /** @type {NetworkRequest[]} */ + /** @type {Lantern.NetworkRequest[]} */ const records = []; graph.getRootNode().traverse(node => { if (node.type === BaseNode.TYPES.NETWORK) { @@ -199,7 +193,7 @@ class Simulator { } /** - * @param {NetworkRequest} record + * @param {Lantern.NetworkRequest} record * @return {?TcpConnection} */ _acquireConnection(record) { @@ -393,7 +387,7 @@ class Simulator { } /** - * @return {{nodeTimings: Map, completeNodeTimings: Map}} + * @return {{nodeTimings: Map, completeNodeTimings: Map}} */ _computeFinalNodeTimings() { /** @type {Array<[Node, CompleteNodeTiming]>} */ @@ -404,8 +398,8 @@ class Simulator { // Most consumers will want the entries sorted by startTime, so insert them in that order completeNodeTimingEntries.sort((a, b) => a[1].startTime - b[1].startTime); - // Trimmed version of type `SimulationNodeTiming`. - /** @type {Array<[Node, SimulationNodeTiming]>} */ + // Trimmed version of type `Lantern.Simulation.NodeTiming`. + /** @type {Array<[Node, Lantern.Simulation.NodeTiming]>} */ const nodeTimingEntries = completeNodeTimingEntries.map(([node, timing]) => { return [node, { startTime: timing.startTime, @@ -421,7 +415,7 @@ class Simulator { } /** - * @return {Required} + * @return {Required} */ getOptions() { return this._options; @@ -438,7 +432,7 @@ class Simulator { * * @param {Node} graph * @param {{flexibleOrdering?: boolean, label?: string}=} options - * @return {SimulationResult} + * @return {Lantern.Simulation.Result} */ simulate(graph, options) { if (BaseNode.hasCycle(graph)) { diff --git a/core/lib/lantern/types/lantern.d.ts b/core/lib/lantern/types/lantern.d.ts new file mode 100644 index 000000000000..dd82e855bc6b --- /dev/null +++ b/core/lib/lantern/types/lantern.d.ts @@ -0,0 +1,129 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as LH from '../../../../types/lh.js'; + +type ParsedURL = { + /** + * Equivalent to a `new URL(url).protocol` BUT w/o the trailing colon (:) + */ + scheme: string; + /** + * Equivalent to a `new URL(url).hostname` + */ + host: string; + securityOrigin: string; +}; +type LightriderStatistics = { + /** + * The difference in networkEndTime between the observed Lighthouse networkEndTime and Lightrider's derived networkEndTime. + */ + endTimeDeltaMs: number; + /** + * The time spent making a TCP connection (connect + SSL). Note: this is poorly named. + */ + TCPMs: number; + /** + * The time spent requesting a resource from a remote server, we use this to approx RTT. Note: this is poorly names, it really should be "server response time". + */ + requestMs: number; + /** + * Time to receive the entire response payload starting the clock on receiving the first fragment (first non-header byte). + */ + responseMs: number; +}; + +export class NetworkRequest { + /** + * The canonical network record. + * Users of Lantern must create NetworkRequests matching this interface, + * but can store the source-of-truth for their network model in this `record` + * property. This is then accessible as a read-only property on NetworkNode. + */ + record?: T; + + requestId: string; + connectionId: string; + connectionReused: boolean; + url: string; + protocol: string; + parsedURL: ParsedURL; + documentURL: string; + /** When the renderer process initially discovers a network request, in milliseconds. */ + rendererStartTime: number; + /** + * When the network service is about to handle a request, ie. just before going to the + * HTTP cache or going to the network for DNS/connection setup, in milliseconds. + */ + networkRequestTime: number; + /** When the last byte of the response headers is received, in milliseconds. */ + responseHeadersEndTime: number; + /** When the last byte of the response body is received, in milliseconds. */ + networkEndTime: number; + transferSize: number; + resourceSize: number; + fromDiskCache: boolean; + fromMemoryCache: boolean; + // TODO(15841): remove from lantern. + /** Extra timing information available only when run in Lightrider. */ + lrStatistics: LightriderStatistics | undefined; + finished: boolean; + statusCode: number; + /** The network request that this one redirected to */ + redirectDestination: NetworkRequest | undefined; + failed: boolean; + initiator: LH.Crdp.Network.Initiator; + initiatorRequest: NetworkRequest | undefined; + /** The chain of network requests that redirected to this one */ + redirects: NetworkRequest[] | undefined; + timing: LH.Crdp.Network.ResourceTiming | undefined; + resourceType: LH.Crdp.Network.ResourceType | undefined; + mimeType: string; + priority: LH.Crdp.Network.ResourcePriority; + frameId: string | undefined; + sessionTargetType: LH.Protocol.TargetType | undefined; +} + +export namespace Simulation { + type GraphNode = import('../base-node.js').Node; + type GraphNetworkNode = import('../network-node.js').NetworkNode; + type GraphCPUNode = import('../cpu-node.js').CPUNode; + type Simulator = import('../simulator/simulator.js').Simulator; + + interface MetricCoefficients { + intercept: number; + optimistic: number; + pessimistic: number; + } + + interface Options { + rtt?: number; + throughput?: number; + observedThroughput: number; + maximumConcurrentRequests?: number; + cpuSlowdownMultiplier?: number; + layoutTaskMultiplier?: number; + additionalRttByOrigin?: Map; + serverResponseTimeByOrigin?: Map; + } + + interface NodeTiming { + startTime: number; + endTime: number; + duration: number; + } + + interface Result { + timeInMs: number; + nodeTimings: Map, NodeTiming>; + } + + interface MetricComputationDataInput { + simulator: Simulator; + graph: GraphNode; + processedNavigation: LH.Artifacts.ProcessedNavigation; + } +} diff --git a/core/lib/lantern/types/lantern.js b/core/lib/lantern/types/lantern.js new file mode 100644 index 000000000000..2740c5b56c64 --- /dev/null +++ b/core/lib/lantern/types/lantern.js @@ -0,0 +1,7 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export {}; diff --git a/core/lib/network-request.js b/core/lib/network-request.js index cd0f3c8af9f5..da45a527aa85 100644 --- a/core/lib/network-request.js +++ b/core/lib/network-request.js @@ -53,10 +53,9 @@ */ import * as LH from '../../types/lh.js'; +import * as Lantern from './lantern/types/lantern.js'; import UrlUtils from './url-utils.js'; -/** @template T @typedef {import('../../types/internal/lantern.js').Lantern.NetworkRequest} LanternNetworkRequest */ - // Lightrider X-Header names for timing information. // See: _updateTransferSizeForLightrider and _updateTimingsForLightrider. const HEADER_TCP = 'X-TCPMs'; // Note: this should have been called something like ConnectMs, as it includes SSL. @@ -572,7 +571,7 @@ class NetworkRequest { /** * @param {NetworkRequest} record - * @return {LanternNetworkRequest} + * @return {Lantern.NetworkRequest} */ static asLanternNetworkRequest(record) { return { diff --git a/tsconfig.json b/tsconfig.json index 31c016da62f4..25c4cc93bf70 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,7 @@ "clients/**/*.js", "build/**/*.js", "./types/**/*.d.ts", + "./core/lib/lantern/types/**/*.d.ts", "eslint-local-rules.cjs", "third-party/axe/valid-langs.js", "third-party/esbuild-plugins-polyfills/esbuild-polyfills.js", diff --git a/types/gatherer.d.ts b/types/gatherer.d.ts index 89424d3bd137..8e6bc67db864 100644 --- a/types/gatherer.d.ts +++ b/types/gatherer.d.ts @@ -17,7 +17,7 @@ import Config from './config.js'; import Result from './lhr/lhr.js'; import Protocol from './protocol.js'; import Puppeteer from './puppeteer.js'; -import {Lantern} from '../types/internal/lantern.js'; +import * as Lantern from '../core/lib/lantern/types/lantern.js'; type CrdpEvents = CrdpMappings.Events; type CrdpCommands = CrdpMappings.Commands; diff --git a/types/internal/lantern.d.ts b/types/internal/lantern.d.ts deleted file mode 100644 index dc1873b22cd1..000000000000 --- a/types/internal/lantern.d.ts +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as LH from '../lh.js'; - -declare namespace Lantern { - type ParsedURL = { - /** - * Equivalent to a `new URL(url).protocol` BUT w/o the trailing colon (:) - */ - scheme: string; - /** - * Equivalent to a `new URL(url).hostname` - */ - host: string; - securityOrigin: string; - }; - type LightriderStatistics = { - /** - * The difference in networkEndTime between the observed Lighthouse networkEndTime and Lightrider's derived networkEndTime. - */ - endTimeDeltaMs: number; - /** - * The time spent making a TCP connection (connect + SSL). Note: this is poorly named. - */ - TCPMs: number; - /** - * The time spent requesting a resource from a remote server, we use this to approx RTT. Note: this is poorly names, it really should be "server response time". - */ - requestMs: number; - /** - * Time to receive the entire response payload starting the clock on receiving the first fragment (first non-header byte). - */ - responseMs: number; - }; - class NetworkRequest { - /** - * The canonical network record. - * Users of Lantern must create NetworkRequests matching this interface, - * but can store the source-of-truth for their network model in this `record` - * property. This is then accessible as a read-only property on NetworkNode. - */ - record?: T; - - requestId: string; - connectionId: string; - connectionReused: boolean; - url: string; - protocol: string; - parsedURL: ParsedURL; - documentURL: string; - /** When the renderer process initially discovers a network request, in milliseconds. */ - rendererStartTime: number; - /** - * When the network service is about to handle a request, ie. just before going to the - * HTTP cache or going to the network for DNS/connection setup, in milliseconds. - */ - networkRequestTime: number; - /** When the last byte of the response headers is received, in milliseconds. */ - responseHeadersEndTime: number; - /** When the last byte of the response body is received, in milliseconds. */ - networkEndTime: number; - transferSize: number; - resourceSize: number; - fromDiskCache: boolean; - fromMemoryCache: boolean; - // TODO(15841): remove from lantern. - /** Extra timing information available only when run in Lightrider. */ - lrStatistics: LightriderStatistics | undefined; - finished: boolean; - statusCode: number; - /** The network request that this one redirected to */ - redirectDestination: NetworkRequest | undefined; - failed: boolean; - initiator: LH.Crdp.Network.Initiator; - initiatorRequest: NetworkRequest | undefined; - /** The chain of network requests that redirected to this one */ - redirects: NetworkRequest[] | undefined; - timing: LH.Crdp.Network.ResourceTiming | undefined; - resourceType: LH.Crdp.Network.ResourceType | undefined; - mimeType: string; - priority: LH.Crdp.Network.ResourcePriority; - frameId: string | undefined; - sessionTargetType: LH.Protocol.TargetType | undefined; - } - - export namespace Simulation { - type GraphNode = import('../../core/lib/lantern/base-node.js').Node; - type GraphNetworkNode = import('../../core/lib/lantern/network-node.js').NetworkNode; - type GraphCPUNode = import('../../core/lib/lantern/cpu-node.js').CPUNode; - type Simulator = import('../../core/lib/lantern/simulator/simulator.js').Simulator; - - interface MetricCoefficients { - intercept: number; - optimistic: number; - pessimistic: number; - } - - interface Options { - rtt?: number; - throughput?: number; - observedThroughput: number; - maximumConcurrentRequests?: number; - cpuSlowdownMultiplier?: number; - layoutTaskMultiplier?: number; - additionalRttByOrigin?: Map; - serverResponseTimeByOrigin?: Map; - } - - interface NodeTiming { - startTime: number; - endTime: number; - duration: number; - } - - interface Result { - timeInMs: number; - nodeTimings: Map, NodeTiming>; - } - - interface MetricComputationDataInput { - simulator: Simulator; - graph: GraphNode; - processedNavigation: LH.Artifacts.ProcessedNavigation; - } - } -}