| import esbuild from 'esbuild'; |
| import fs from 'node:fs'; |
| import path from 'node:path'; |
| import { fileURLToPath } from 'node:url'; |
|
|
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
|
|
| const manifestPath = path.resolve( |
| __dirname, |
| '../src/agents/browser/browser-tools-manifest.json', |
| ); |
| const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')); |
|
|
| |
| const excludedToolsFiles = (manifest.exclude || []).map((t) => t.name); |
|
|
| |
| const emptyModulePlugin = { |
| name: 'empty-modules', |
| setup(build) { |
| if (excludedToolsFiles.length === 0) return; |
|
|
| |
| const excludeFilter = new RegExp(`(${excludedToolsFiles.join('|')})\\.js$`); |
|
|
| build.onResolve({ filter: excludeFilter }, (args) => { |
| |
| if ( |
| args.importer.includes('chrome-devtools-mcp') && |
| /[\\/]tools[\\/]/.test(args.importer) |
| ) { |
| return { path: args.path, namespace: 'empty' }; |
| } |
| return null; |
| }); |
|
|
| build.onLoad({ filter: /.*/, namespace: 'empty' }, (_args) => ({ |
| contents: 'export {};', |
| loader: 'js', |
| })); |
| }, |
| }; |
|
|
| async function bundle() { |
| try { |
| const entryPoint = path.resolve( |
| __dirname, |
| '../../../node_modules/chrome-devtools-mcp/build/src/index.js', |
| ); |
| await esbuild.build({ |
| entryPoints: [entryPoint], |
| bundle: true, |
| outfile: path.resolve( |
| __dirname, |
| '../dist/bundled/chrome-devtools-mcp.mjs', |
| ), |
| format: 'esm', |
| platform: 'node', |
| plugins: [emptyModulePlugin], |
| external: [ |
| 'puppeteer-core', |
| '/bundled/*', |
| '../../../node_modules/puppeteer-core/*', |
| ], |
| banner: { |
| js: 'import { createRequire as __createRequire } from "module"; const require = __createRequire(import.meta.url);', |
| }, |
| }); |
|
|
| |
| const srcThirdParty = path.resolve( |
| __dirname, |
| '../../../node_modules/chrome-devtools-mcp/build/src/third_party', |
| ); |
| const destThirdParty = path.resolve( |
| __dirname, |
| '../dist/bundled/third_party', |
| ); |
|
|
| if (fs.existsSync(srcThirdParty)) { |
| if (fs.existsSync(destThirdParty)) { |
| fs.rmSync(destThirdParty, { recursive: true, force: true }); |
| } |
| fs.cpSync(srcThirdParty, destThirdParty, { |
| recursive: true, |
| filter: (src) => { |
| |
| |
| return ( |
| !src.includes('lighthouse-devtools-mcp-bundle.js') && |
| !src.includes('devtools-formatter-worker.js') |
| ); |
| }, |
| }); |
| } else { |
| console.warn(`Warning: third_party assets not found at ${srcThirdParty}`); |
| } |
|
|
| |
| |
| const bundleMcpFile = path.resolve( |
| __dirname, |
| '../dist/bundled/chrome-devtools-mcp.mjs', |
| ); |
| const destThirdPartyIndex = path.resolve( |
| __dirname, |
| '../dist/bundled/third_party/index.js', |
| ); |
|
|
| const sanitizeFile = (filePath) => { |
| if (fs.existsSync(filePath)) { |
| const content = fs.readFileSync(filePath, 'utf8'); |
| const keyPattern = /AIzaSy[A-Za-z0-9_-]{30,40}/; |
| if (keyPattern.test(content)) { |
| console.log(`Sanitizing hardcoded API key in: ${filePath}`); |
| |
| const quotedPattern = /([\x27\x22\x60])AIzaSy[A-Za-z0-9_-]{30,40}\1/g; |
| const sanitizedContent = content.replace( |
| quotedPattern, |
| '(process.env.CRUX_API_KEY || "")', |
| ); |
|
|
| if (keyPattern.test(sanitizedContent)) { |
| throw new Error( |
| `Failed to fully sanitize API key in ${filePath}. The key pattern was detected but could not be safely replaced.`, |
| ); |
| } |
|
|
| fs.writeFileSync(filePath, sanitizedContent, 'utf8'); |
| } |
| } |
| }; |
|
|
| sanitizeFile(bundleMcpFile); |
| sanitizeFile(destThirdPartyIndex); |
| } catch (error) { |
| console.error('Error bundling chrome-devtools-mcp:', error); |
| process.exit(1); |
| } |
| } |
|
|
| bundle(); |
|
|