next
Version:
The React Framework
180 lines (179 loc) • 7.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
handlePageMetadataResponse: null,
registerGetPageMetadataTool: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
handlePageMetadataResponse: function() {
return handlePageMetadataResponse;
},
registerGetPageMetadataTool: function() {
return registerGetPageMetadataTool;
}
});
const _hotreloadertypes = require("../../dev/hot-reloader-types");
const _browsercommunication = require("./utils/browser-communication");
const _mcptelemetrytracker = require("../mcp-telemetry-tracker");
function registerGetPageMetadataTool(server, sendHmrMessage, getActiveConnectionCount) {
server.registerTool('get_page_metadata', {
description: 'Get runtime metadata about what contributes to the current page render from active browser sessions.',
inputSchema: {}
}, async (_request)=>{
// Track telemetry
_mcptelemetrytracker.mcpTelemetryTracker.recordToolCall('mcp/get_page_metadata');
try {
const connectionCount = getActiveConnectionCount();
if (connectionCount === 0) {
return {
content: [
{
type: 'text',
text: 'No browser sessions connected. Please open your application in a browser to retrieve page metadata.'
}
]
};
}
const responses = await (0, _browsercommunication.createBrowserRequest)(_hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.REQUEST_PAGE_METADATA, sendHmrMessage, getActiveConnectionCount, _browsercommunication.DEFAULT_BROWSER_REQUEST_TIMEOUT_MS);
if (responses.length === 0) {
return {
content: [
{
type: 'text',
text: 'No browser sessions responded.'
}
]
};
}
const sessionMetadata = [];
for (const response of responses){
if (response.data) {
// TODO: Add other metadata for the current page render here. Currently, we only have segment trie data.
const pageMetadata = convertSegmentTrieToPageMetadata(response.data);
sessionMetadata.push({
url: response.url,
metadata: pageMetadata
});
}
}
if (sessionMetadata.length === 0) {
return {
content: [
{
type: 'text',
text: `No page metadata available from ${responses.length} browser session(s).`
}
]
};
}
const output = formatPageMetadata(sessionMetadata);
return {
content: [
{
type: 'text',
text: output
}
]
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error: ${error instanceof Error ? error.message : String(error)}`
}
]
};
}
});
}
function handlePageMetadataResponse(requestId, segmentTrieData, url) {
(0, _browsercommunication.handleBrowserPageResponse)(requestId, segmentTrieData, url || '');
}
function convertSegmentTrieToPageMetadata(data) {
const segments = [];
if (data.segmentTrie) {
// Traverse the trie and collect all segments
function traverseTrie(node) {
if (node.value) {
segments.push({
type: node.value.type,
pagePath: node.value.pagePath,
boundaryType: node.value.boundaryType
});
}
for (const childNode of Object.values(node.children)){
if (childNode) {
traverseTrie(childNode);
}
}
}
traverseTrie(data.segmentTrie);
}
return {
segments,
routerType: data.routerType
};
}
function formatPageMetadata(sessionMetadata) {
let output = `# Page metadata from ${sessionMetadata.length} browser session(s)\n\n`;
for (const { url, metadata } of sessionMetadata){
let displayUrl = url;
try {
const urlObj = new URL(url);
displayUrl = urlObj.pathname + urlObj.search + urlObj.hash;
} catch {
// If URL parsing fails, use the original URL
}
output += `## Session: ${displayUrl}\n\n`;
output += `**Router type:** ${metadata.routerType}\n\n`;
if (metadata.segments.length === 0) {
output += '*No segments found*\n\n';
} else {
output += '### Files powering this page:\n\n';
// Ensure consistent output to avoid flaky tests
const sortedSegments = [
...metadata.segments
].sort((a, b)=>{
const typeOrder = (segment)=>{
const type = segment.boundaryType || segment.type;
if (type === 'layout') return 0;
if (type.startsWith('boundary:')) return 1;
if (type === 'page') return 2;
return 3;
};
const aOrder = typeOrder(a);
const bOrder = typeOrder(b);
if (aOrder !== bOrder) return aOrder - bOrder;
return a.pagePath.localeCompare(b.pagePath);
});
for (const segment of sortedSegments){
const path = segment.pagePath;
const isBuiltin = path.startsWith('__next_builtin__');
const type = segment.boundaryType || segment.type;
const isBoundary = type.startsWith('boundary:');
let displayPath = path.replace(/@boundary$/, '').replace(/^__next_builtin__/, '');
if (!isBuiltin && !displayPath.startsWith('app/')) {
displayPath = `app/${displayPath}`;
}
const descriptors = [];
if (isBoundary) descriptors.push('boundary');
if (isBuiltin) descriptors.push('builtin');
const descriptor = descriptors.length > 0 ? ` (${descriptors.join(', ')})` : '';
output += `- ${displayPath}${descriptor}\n`;
}
output += '\n';
}
output += '---\n\n';
}
return output.trim();
}
//# sourceMappingURL=get-page-metadata.js.map