Rocky_Mountain_Vending/.pnpm-store/v10/files/0b/0db2e7bae9473df31ce51b25940f850f1270556c409d98d3da6c03794fc06e1c1a98bc33b26b21ff9919531437027bb58907bb46a91996a7db0fd62536fa91
DMleadgen 46d973904b
Initial commit: Rocky Mountain Vending website
Next.js website for Rocky Mountain Vending company featuring:
- Product catalog with Stripe integration
- Service areas and parts pages
- Admin dashboard with Clerk authentication
- SEO optimized pages with JSON-LD structured data

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 16:22:15 -07:00

102 lines
No EOL
5 KiB
Text

// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Core from '../core/core.js';
import * as Graph from '../graph/graph.js';
import { Metric, } from './Metric.js';
const mobileSlow4GRtt = 150;
class SpeedIndex extends Metric {
static get coefficients() {
return {
// Note that the optimistic estimate is based on the real observed speed index rather than a
// real lantern graph (and the final estimate will be Math.max(FCP, Speed Index)).
intercept: 0,
optimistic: 1.4,
pessimistic: 0.4,
};
}
static getScaledCoefficients(rttMs) {
// We want to scale our default coefficients based on the speed of the connection.
// We will linearly interpolate coefficients for the passed-in rttMs based on two pre-determined points:
// 1. Baseline point of 30 ms RTT where Speed Index should be a ~50/50 blend of optimistic/pessimistic.
// 30 ms was based on a typical home WiFi connection's actual RTT.
// Coefficients here follow from the fact that the optimistic estimate should be very close
// to reality at this connection speed and the pessimistic estimate compensates for minor
// connection speed differences.
// 2. Default throttled point of 150 ms RTT where the default coefficients have been determined to be most accurate.
// Coefficients here were determined through thorough analysis and linear regression on the
// lantern test data set. See core/scripts/test-lantern.sh for more detail.
// While the coefficients haven't been analyzed at the interpolated points, it's our current best effort.
const defaultCoefficients = this.coefficients;
const defaultRttExcess = mobileSlow4GRtt - 30;
const multiplier = Math.max((rttMs - 30) / defaultRttExcess, 0);
return {
intercept: defaultCoefficients.intercept * multiplier,
optimistic: 0.5 + (defaultCoefficients.optimistic - 0.5) * multiplier,
pessimistic: 0.5 + (defaultCoefficients.pessimistic - 0.5) * multiplier,
};
}
static getOptimisticGraph(dependencyGraph) {
return dependencyGraph;
}
static getPessimisticGraph(dependencyGraph) {
return dependencyGraph;
}
static getEstimateFromSimulation(simulationResult, extras) {
if (!extras.fcpResult) {
throw new Core.LanternError('missing fcpResult');
}
if (extras.observedSpeedIndex === undefined) {
throw new Core.LanternError('missing observedSpeedIndex');
}
const fcpTimeInMs = extras.fcpResult.pessimisticEstimate.timeInMs;
const estimate = extras.optimistic ?
extras.observedSpeedIndex :
SpeedIndex.computeLayoutBasedSpeedIndex(simulationResult.nodeTimings, fcpTimeInMs);
return {
timeInMs: estimate,
nodeTimings: simulationResult.nodeTimings,
};
}
static compute(data, extras) {
const fcpResult = extras?.fcpResult;
if (!fcpResult) {
throw new Core.LanternError('FCP is required to calculate the SpeedIndex metric');
}
const metricResult = super.compute(data, extras);
metricResult.timing = Math.max(metricResult.timing, fcpResult.timing);
return metricResult;
}
/**
* Approximate speed index using layout events from the simulated node timings.
* The layout-based speed index is the weighted average of the endTime of CPU nodes that contained
* a 'Layout' task. log(duration) is used as the weight to stand for "significance" to the page.
*
* If no layout events can be found or the endTime of a CPU task is too early, FCP is used instead.
*
* This approach was determined after evaluating the accuracy/complexity tradeoff of many
* different methods. Read more in the evaluation doc.
*
* @see https://docs.google.com/document/d/1qJWXwxoyVLVadezIp_Tgdk867G3tDNkkVRvUJSH3K1E/edit#
*/
static computeLayoutBasedSpeedIndex(nodeTimings, fcpTimeInMs) {
const layoutWeights = [];
for (const [node, timing] of nodeTimings.entries()) {
if (node.type !== Graph.BaseNode.types.CPU) {
continue;
}
if (node.childEvents.some(x => x.name === 'Layout')) {
const timingWeight = Math.max(Math.log2(timing.endTime - timing.startTime), 0);
layoutWeights.push({ time: timing.endTime, weight: timingWeight });
}
}
const totalWeightedTime = layoutWeights.map(evt => evt.weight * Math.max(evt.time, fcpTimeInMs)).reduce((a, b) => a + b, 0);
const totalWeight = layoutWeights.map(evt => evt.weight).reduce((a, b) => a + b, 0);
if (!totalWeight) {
return fcpTimeInMs;
}
return totalWeightedTime / totalWeight;
}
}
export { SpeedIndex };
//# sourceMappingURL=SpeedIndex.js.map