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>
261 lines
No EOL
9.8 KiB
Text
261 lines
No EOL
9.8 KiB
Text
// Copyright 2025 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 Platform from '../../../core/platform/platform.js';
|
|
import * as Types from '../types/types.js';
|
|
import { data as metaHandlerData } from './MetaHandler.js';
|
|
import { data as networkRequestsHandlerData } from './NetworkRequestsHandler.js';
|
|
function completeURL(base, url) {
|
|
if (url.startsWith('data:') || url.startsWith('blob:') || url.startsWith('javascript:') || url.startsWith('mailto:')) {
|
|
return url;
|
|
}
|
|
try {
|
|
return new URL(url, base).href;
|
|
}
|
|
catch { }
|
|
return null;
|
|
}
|
|
const scriptById = new Map();
|
|
export function deps() {
|
|
return ['Meta', 'NetworkRequests'];
|
|
}
|
|
export function reset() {
|
|
scriptById.clear();
|
|
}
|
|
export function handleEvent(event) {
|
|
const getOrMakeScript = (isolate, scriptIdAsNumber) => {
|
|
const scriptId = String(scriptIdAsNumber);
|
|
const key = `${isolate}.${scriptId}`;
|
|
return Platform.MapUtilities.getWithDefault(scriptById, key, () => ({ isolate, scriptId, frame: '', ts: 0 }));
|
|
};
|
|
if (Types.Events.isTargetRundownEvent(event) && event.args.data) {
|
|
const { isolate, scriptId, frame } = event.args.data;
|
|
const script = getOrMakeScript(isolate, scriptId);
|
|
script.frame = frame;
|
|
script.ts = event.ts;
|
|
return;
|
|
}
|
|
if (Types.Events.isV8SourceRundownEvent(event)) {
|
|
const { isolate, scriptId, url, sourceUrl, sourceMapUrl, sourceMapUrlElided } = event.args.data;
|
|
const script = getOrMakeScript(isolate, scriptId);
|
|
script.url = url;
|
|
if (sourceUrl) {
|
|
script.sourceUrl = sourceUrl;
|
|
}
|
|
// Older traces may have data source map urls. Those can be very large, so a change
|
|
// was made to elide them from the trace.
|
|
// If elided, a fresh trace will fetch the source map from the Script model
|
|
// (see TimelinePanel getExistingSourceMap). If not fresh, the source map is resolved
|
|
// instead in this handler via `findCachedRawSourceMap`.
|
|
if (sourceMapUrlElided) {
|
|
script.sourceMapUrlElided = true;
|
|
}
|
|
else if (sourceMapUrl) {
|
|
script.sourceMapUrl = sourceMapUrl;
|
|
}
|
|
return;
|
|
}
|
|
if (Types.Events.isV8SourceRundownSourcesScriptCatchupEvent(event)) {
|
|
const { isolate, scriptId, sourceText } = event.args.data;
|
|
const script = getOrMakeScript(isolate, scriptId);
|
|
script.content = sourceText;
|
|
return;
|
|
}
|
|
if (Types.Events.isV8SourceRundownSourcesLargeScriptCatchupEvent(event)) {
|
|
const { isolate, scriptId, sourceText } = event.args.data;
|
|
const script = getOrMakeScript(isolate, scriptId);
|
|
script.content = (script.content ?? '') + sourceText;
|
|
return;
|
|
}
|
|
}
|
|
function findFrame(meta, frameId) {
|
|
for (const frames of meta.frameByProcessId?.values()) {
|
|
const frame = frames.get(frameId);
|
|
if (frame) {
|
|
return frame;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function findNetworkRequest(networkRequests, script) {
|
|
if (!script.url) {
|
|
return null;
|
|
}
|
|
return networkRequests.find(request => request.args.data.url === script.url) ?? null;
|
|
}
|
|
function computeMappingEndColumns(map) {
|
|
const result = new Map();
|
|
const mappings = map.mappings();
|
|
for (let i = 0; i < mappings.length - 1; i++) {
|
|
const mapping = mappings[i];
|
|
const nextMapping = mappings[i + 1];
|
|
if (mapping.lineNumber === nextMapping.lineNumber) {
|
|
result.set(mapping, nextMapping.columnNumber);
|
|
}
|
|
}
|
|
// Now, all but the last mapping on each line will have a value in this map.
|
|
return result;
|
|
}
|
|
/**
|
|
* Using a script's contents and source map, attribute every generated byte to an authored source file.
|
|
*/
|
|
function computeGeneratedFileSizes(script) {
|
|
if (!script.sourceMap) {
|
|
throw new Error('expected source map');
|
|
}
|
|
const map = script.sourceMap;
|
|
const content = script.content ?? '';
|
|
const contentLength = content.length;
|
|
const lines = content.split('\n');
|
|
const files = {};
|
|
const totalBytes = contentLength;
|
|
let unmappedBytes = totalBytes;
|
|
const mappingEndCols = computeMappingEndColumns(script.sourceMap);
|
|
for (const mapping of map.mappings()) {
|
|
const source = mapping.sourceURL;
|
|
const lineNum = mapping.lineNumber;
|
|
const colNum = mapping.columnNumber;
|
|
const lastColNum = mappingEndCols.get(mapping);
|
|
// Webpack sometimes emits null mappings.
|
|
// https://github.com/mozilla/source-map/pull/303
|
|
if (!source) {
|
|
continue;
|
|
}
|
|
// Lines and columns are zero-based indices. Visually, lines are shown as a 1-based index.
|
|
const line = lines[lineNum];
|
|
if (line === null || line === undefined) {
|
|
const errorMessage = `${map.url()} mapping for line out of bounds: ${lineNum + 1}`;
|
|
return { errorMessage };
|
|
}
|
|
if (colNum > line.length) {
|
|
const errorMessage = `${map.url()} mapping for column out of bounds: ${lineNum + 1}:${colNum}`;
|
|
return { errorMessage };
|
|
}
|
|
let mappingLength = 0;
|
|
if (lastColNum !== undefined) {
|
|
if (lastColNum > line.length) {
|
|
const errorMessage = `${map.url()} mapping for last column out of bounds: ${lineNum + 1}:${lastColNum}`;
|
|
return { errorMessage };
|
|
}
|
|
mappingLength = lastColNum - colNum;
|
|
}
|
|
else {
|
|
// Add +1 to account for the newline.
|
|
mappingLength = line.length - colNum + 1;
|
|
}
|
|
files[source] = (files[source] || 0) + mappingLength;
|
|
unmappedBytes -= mappingLength;
|
|
}
|
|
return {
|
|
files,
|
|
unmappedBytes,
|
|
totalBytes,
|
|
};
|
|
}
|
|
export function getScriptGeneratedSizes(script) {
|
|
if (script.sourceMap && !script.sizes) {
|
|
script.sizes = computeGeneratedFileSizes(script);
|
|
}
|
|
return script.sizes ?? null;
|
|
}
|
|
function findCachedRawSourceMap(script, options) {
|
|
if (options.isFreshRecording || !options.metadata?.sourceMaps) {
|
|
// Exit if this is not a loaded trace w/ source maps in the metadata.
|
|
return;
|
|
}
|
|
// For elided data url source maps, search the metadata source maps by script url.
|
|
if (script.sourceMapUrlElided) {
|
|
if (!script.url) {
|
|
return;
|
|
}
|
|
const cachedSourceMap = options.metadata.sourceMaps.find(m => m.url === script.url);
|
|
if (cachedSourceMap) {
|
|
return cachedSourceMap.sourceMap;
|
|
}
|
|
return;
|
|
}
|
|
if (!script.sourceMapUrl) {
|
|
return;
|
|
}
|
|
// Otherwise, search by source map url.
|
|
// Note: early enhanced traces may have this field set for data urls. Ignore those,
|
|
// as they were never stored in metadata sourcemap.
|
|
const isDataUrl = script.sourceMapUrl.startsWith('data:');
|
|
if (!isDataUrl) {
|
|
const cachedSourceMap = options.metadata.sourceMaps.find(m => m.sourceMapUrl === script.sourceMapUrl);
|
|
if (cachedSourceMap) {
|
|
return cachedSourceMap.sourceMap;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
export async function finalize(options) {
|
|
const meta = metaHandlerData();
|
|
const networkRequests = [...networkRequestsHandlerData().byId.values()];
|
|
const documentUrls = new Set();
|
|
for (const frames of meta.frameByProcessId.values()) {
|
|
for (const frame of frames.values()) {
|
|
documentUrls.add(frame.url);
|
|
}
|
|
}
|
|
for (const script of scriptById.values()) {
|
|
script.request = findNetworkRequest(networkRequests, script) ?? undefined;
|
|
script.inline = !!script.url && documentUrls.has(script.url);
|
|
}
|
|
if (!options.resolveSourceMap) {
|
|
return;
|
|
}
|
|
const promises = [];
|
|
for (const script of scriptById.values()) {
|
|
// No frame or url means the script came from somewhere we don't care about.
|
|
// Note: scripts from inline <SCRIPT> elements use the url of the HTML document,
|
|
// so aren't ignored.
|
|
if (!script.frame || !script.url || (!script.sourceMapUrl && !script.sourceMapUrlElided)) {
|
|
continue;
|
|
}
|
|
const frameUrl = findFrame(meta, script.frame)?.url;
|
|
if (!frameUrl) {
|
|
continue;
|
|
}
|
|
// If there is a `sourceURL` magic comment, resolve the compiledUrl against the frame url.
|
|
// example: `// #sourceURL=foo.js` for target frame https://www.example.com/home -> https://www.example.com/home/foo.js
|
|
let sourceUrl = script.url;
|
|
if (script.sourceUrl) {
|
|
sourceUrl = completeURL(frameUrl, script.sourceUrl) ?? script.sourceUrl;
|
|
}
|
|
let sourceMapUrl;
|
|
if (script.sourceMapUrl) {
|
|
// Resolve the source map url. The value given by v8 may be relative, so resolve it here.
|
|
// This process should match the one in `SourceMapManager.attachSourceMap`.
|
|
sourceMapUrl =
|
|
completeURL(sourceUrl, script.sourceMapUrl);
|
|
if (!sourceMapUrl) {
|
|
continue;
|
|
}
|
|
script.sourceMapUrl = sourceMapUrl;
|
|
}
|
|
const params = {
|
|
scriptId: script.scriptId,
|
|
scriptUrl: script.url,
|
|
sourceUrl: sourceUrl,
|
|
sourceMapUrl: sourceMapUrl ?? '',
|
|
frame: script.frame,
|
|
cachedRawSourceMap: findCachedRawSourceMap(script, options),
|
|
};
|
|
const promise = options.resolveSourceMap(params).then(sourceMap => {
|
|
if (sourceMap) {
|
|
script.sourceMap = sourceMap;
|
|
}
|
|
});
|
|
promises.push(promise.catch(e => {
|
|
console.error('Uncaught error when resolving source map', params, e);
|
|
}));
|
|
}
|
|
await Promise.all(promises);
|
|
}
|
|
export function data() {
|
|
return {
|
|
scripts: [...scriptById.values()],
|
|
};
|
|
}
|
|
//# sourceMappingURL=ScriptsHandler.js.map |