vite-devtools-svelte 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/analyzers/routes.ts","../src/analyzers/assets.ts","../src/analyzers/project.ts","../src/analyzers/components.ts","../src/runtime.ts","../src/mcp/sessions.ts","../src/mcp/issues.ts","../src/mcp/server.ts","../src/template-injector.ts","../src/plugin.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport type { RouteInfo, ParamInfo, RouteFile } from '../types.js'\n\nexport function analyzeRoutes(routesDir: string): RouteInfo[] {\n if (!fs.existsSync(routesDir)) return []\n\n const routes: RouteInfo[] = []\n scanDirectory(routesDir, routesDir, routes)\n return routes.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nfunction scanDirectory(dir: string, rootDir: string, routes: RouteInfo[]): void {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n const files: RouteFile[] = []\n let hasRouteFiles = false\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n scanDirectory(path.join(dir, entry.name), rootDir, routes)\n continue\n }\n\n const routeFile = classifyFile(entry.name, path.join(dir, entry.name))\n if (routeFile) {\n files.push(routeFile)\n hasRouteFiles = true\n }\n }\n\n if (hasRouteFiles) {\n const relativePath = path.relative(rootDir, dir)\n const routePath = buildRoutePath(relativePath)\n const params = extractParams(relativePath)\n\n routes.push({\n id: relativePath || '/',\n path: routePath,\n pattern: routePath,\n segments: routePath.split('/').filter(Boolean),\n hasPage: files.some(f => f.type === 'page'),\n hasLayout: files.some(f => f.type === 'layout'),\n hasServerPage: files.some(f => f.type === 'page-load-server'),\n hasServerLayout: files.some(f => f.type === 'layout-load-server'),\n hasEndpoint: files.some(f => f.type === 'endpoint'),\n hasPageLoad: files.some(f => f.type === 'page-load'),\n hasLayoutLoad: files.some(f => f.type === 'layout-load'),\n params,\n files,\n })\n }\n}\n\nfunction classifyFile(name: string, fullPath: string): RouteFile | null {\n const map: Record<string, RouteFile['type']> = {\n '+page.svelte': 'page',\n '+layout.svelte': 'layout',\n '+page.server.ts': 'page-load-server',\n '+page.server.js': 'page-load-server',\n '+layout.server.ts': 'layout-load-server',\n '+layout.server.js': 'layout-load-server',\n '+page.ts': 'page-load',\n '+page.js': 'page-load',\n '+layout.ts': 'layout-load',\n '+layout.js': 'layout-load',\n '+server.ts': 'endpoint',\n '+server.js': 'endpoint',\n '+error.svelte': 'error',\n }\n\n const type = map[name]\n if (!type) return null\n return { type, path: fullPath }\n}\n\nfunction buildRoutePath(relativePath: string): string {\n if (!relativePath) return '/'\n\n const parts = relativePath.split(path.sep)\n const pathParts = parts.map(part => {\n // SvelteKit group syntax: (group) -> ignored in URL\n if (part.startsWith('(') && part.endsWith(')')) return null\n\n // Dynamic params: [param] -> :param\n if (part.startsWith('[') && part.endsWith(']')) {\n const inner = part.slice(1, -1)\n if (inner.startsWith('...')) return `*${inner.slice(3)}`\n if (inner.startsWith('[') && inner.endsWith(']')) return `:${inner.slice(1, -1)}?`\n return `:${inner}`\n }\n\n return part\n })\n\n return '/' + pathParts.filter(Boolean).join('/')\n}\n\nfunction extractParams(relativePath: string): ParamInfo[] {\n if (!relativePath) return []\n\n const params: ParamInfo[] = []\n const parts = relativePath.split(path.sep)\n\n for (const part of parts) {\n if (!part.startsWith('[') || !part.endsWith(']')) continue\n\n const inner = part.slice(1, -1)\n\n if (inner.startsWith('...')) {\n params.push({ name: inner.slice(3), optional: false, rest: true })\n } else if (inner.startsWith('[') && inner.endsWith(']')) {\n params.push({ name: inner.slice(1, -1), optional: true, rest: false })\n } else {\n const matcherSplit = inner.split('=')\n params.push({\n name: matcherSplit[0],\n optional: false,\n rest: false,\n matcher: matcherSplit[1],\n })\n }\n }\n\n return params\n}\n","import fs from 'fs'\nimport path from 'path'\nimport type { AssetInfo } from '../types.js'\n\nexport const MIME_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject',\n '.otf': 'font/otf',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.json': 'application/json',\n '.xml': 'application/xml',\n '.pdf': 'application/pdf',\n '.txt': 'text/plain',\n '.css': 'text/css',\n '.js': 'text/javascript',\n '.html': 'text/html',\n}\n\nexport function analyzeAssets(staticDir: string): AssetInfo[] {\n if (!fs.existsSync(staticDir)) return []\n\n const assets: AssetInfo[] = []\n scanDir(staticDir, staticDir, assets)\n return assets.sort((a, b) => a.relativePath.localeCompare(b.relativePath))\n}\n\nfunction scanDir(dir: string, rootDir: string, assets: AssetInfo[]): void {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n scanDir(fullPath, rootDir, assets)\n continue\n }\n\n // Skip hidden files\n if (entry.name.startsWith('.')) continue\n\n const stat = fs.statSync(fullPath)\n const ext = path.extname(entry.name).toLowerCase()\n\n assets.push({\n name: entry.name,\n path: fullPath,\n relativePath: path.relative(rootDir, fullPath),\n size: stat.size,\n type: MIME_TYPES[ext] || 'application/octet-stream',\n mtime: stat.mtimeMs,\n })\n }\n}\n","import fs from 'fs'\nimport path from 'path'\nimport type { ProjectInfo } from '../types.js'\n\nconst CACHE_TTL_MS = 5000\nlet _cachedResult: ProjectInfo | null = null\nlet _cachedRoot: string | null = null\nlet _cachedAt = 0\n\nexport function analyzeProject(root: string): ProjectInfo {\n const now = Date.now()\n if (_cachedResult && _cachedRoot === root && now - _cachedAt < CACHE_TTL_MS) {\n return _cachedResult\n }\n const result = _analyzeProjectUncached(root)\n _cachedResult = result\n _cachedRoot = root\n _cachedAt = now\n return result\n}\n\nfunction _analyzeProjectUncached(root: string): ProjectInfo {\n const pkgPath = path.join(root, 'package.json')\n const pkg = fs.existsSync(pkgPath) ? JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) : {}\n\n const deps = pkg.dependencies || {}\n const devDeps = pkg.devDependencies || {}\n\n return {\n name: pkg.name || path.basename(root),\n version: pkg.version || '0.0.0',\n svelteVersion:\n getInstalledVersion(root, 'svelte') || deps.svelte || devDeps.svelte || 'unknown',\n sveltekitVersion:\n getInstalledVersion(root, '@sveltejs/kit') ||\n deps['@sveltejs/kit'] ||\n devDeps['@sveltejs/kit'] ||\n 'unknown',\n viteVersion: getInstalledVersion(root, 'vite') || deps.vite || devDeps.vite || 'unknown',\n dependencies: deps,\n devDependencies: devDeps,\n routesDir: findRoutesDir(root),\n staticDir: findStaticDir(root),\n }\n}\n\nfunction getInstalledVersion(root: string, pkg: string): string | null {\n try {\n const pkgJsonPath = path.join(root, 'node_modules', pkg, 'package.json')\n if (fs.existsSync(pkgJsonPath)) {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n return pkgJson.version\n }\n } catch {\n // ignore\n }\n return null\n}\n\nfunction findRoutesDir(root: string): string {\n const candidates = [path.join(root, 'src', 'routes'), path.join(root, 'src', 'pages')]\n for (const dir of candidates) {\n if (fs.existsSync(dir)) return dir\n }\n return path.join(root, 'src', 'routes')\n}\n\nfunction findStaticDir(root: string): string {\n const candidates = [path.join(root, 'static'), path.join(root, 'public')]\n for (const dir of candidates) {\n if (fs.existsSync(dir)) return dir\n }\n return path.join(root, 'static')\n}\n","import fs from 'fs'\nimport path from 'path'\nimport type { ComponentRelation } from '../types.js'\n\nexport function analyzeComponents(root: string): ComponentRelation[] {\n const srcDir = path.join(root, 'src')\n if (!fs.existsSync(srcDir)) return []\n\n const svelteFiles: string[] = []\n findSvelteFiles(srcDir, svelteFiles)\n\n return svelteFiles.map(file => {\n const content = fs.readFileSync(file, 'utf-8')\n const imports = extractSvelteImports(content, file)\n const name = getComponentName(file)\n\n return {\n file: path.relative(root, file),\n name,\n imports: imports.map(i => path.relative(root, i)),\n }\n })\n}\n\nfunction findSvelteFiles(dir: string, files: string[]): void {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === '.svelte-kit') continue\n findSvelteFiles(fullPath, files)\n } else if (entry.name.endsWith('.svelte')) {\n files.push(fullPath)\n }\n }\n}\n\nfunction extractSvelteImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n const dir = path.dirname(filePath)\n\n // Match: import X from './Component.svelte'\n // Match: import X from '$lib/Component.svelte'\n const importRegex = /import\\s+[\\w{}\\s,*]+\\s+from\\s+['\"]([^'\"]+\\.svelte)['\"]/g\n let match: RegExpExecArray | null\n\n while ((match = importRegex.exec(content)) !== null) {\n const importPath = match[1]\n const resolved = resolveImportPath(importPath, dir, filePath)\n if (resolved) imports.push(resolved)\n }\n\n return imports\n}\n\nfunction resolveImportPath(importPath: string, dir: string, fromFile: string): string | null {\n // Handle $lib alias\n if (importPath.startsWith('$lib/')) {\n const root = findProjectRoot(fromFile)\n if (root) {\n const libPath = path.join(root, 'src', 'lib', importPath.slice(5))\n if (fs.existsSync(libPath)) return libPath\n }\n return null\n }\n\n // Relative import\n if (importPath.startsWith('.')) {\n const resolved = path.resolve(dir, importPath)\n if (fs.existsSync(resolved)) return resolved\n }\n\n return null\n}\n\nfunction findProjectRoot(filePath: string): string | null {\n let dir = path.dirname(filePath)\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, 'package.json'))) return dir\n dir = path.dirname(dir)\n }\n return null\n}\n\nfunction getComponentName(filePath: string): string {\n return path.basename(filePath, '.svelte')\n}\n","// This code is injected into the user's app as a virtual module.\n// It tracks Svelte component mount/unmount and sends data to the Vite server via HMR.\nexport const RUNTIME_MODULE_ID = 'virtual:svelte-devtools-runtime'\nexport const RESOLVED_RUNTIME_ID = '\\0' + RUNTIME_MODULE_ID\n\n// Virtual module ID for the svelte/internal/client wrapper.\n// When user code imports 'svelte/internal/client', it is redirected to this module.\n// The wrapper re-exports everything and overrides key functions for devtools tracking.\nexport const WRAPPER_MODULE_ID = '\\0svelte-devtools:wrapped-client'\n\n/**\n * Wrapper code for svelte/internal/client.\n *\n * Re-exports everything from the real module, then overrides:\n * - push/pop: component lifecycle tracking\n * - tag/tag_proxy: named signal/proxy tracking (Svelte dev mode)\n * - state/derived/proxy: type markers consumed by tag/tag_proxy\n * - user_effect/user_pre_effect: effect tracking\n *\n * This single module replaces all post-compilation regex transforms\n * for reactive tracking, making the approach Svelte-compiler-output agnostic.\n */\nexport const wrapperCode = /* js */ `\nimport * as __svelte_original from 'svelte/internal/client';\nexport * from 'svelte/internal/client';\n\nfunction __dt() {\n return typeof window !== 'undefined' ? window.__SVELTE_DEVTOOLS__ : null;\n}\n\n// Component ID stack (parallel to runtime._stack but local to wrapper)\nconst __idStack = [];\nfunction __currentId() {\n return __idStack.length > 0 ? __idStack[__idStack.length - 1] : null;\n}\n\n// Tracks the most recently created signal for type determination in tag()\nconst __pendingSignal = { ref: null, type: null };\n\n// --- Component Lifecycle ---\n//\n// Observer must not break the observed: every devtools side-effect below is\n// wrapped in try/catch so a bug or an out-of-shape runtime cannot tear down\n// the user's app. The original Svelte function is always called, and its\n// return value always returned, regardless of devtools failures.\n\nexport function push() {\n const result = __svelte_original.push.apply(null, arguments);\n try {\n const dt = __dt();\n if (dt) {\n const file = dt._pendingFile || 'Unknown';\n dt._pendingFile = null;\n const id = dt.register(file);\n __idStack.push(id);\n dt.startInit(id);\n try {\n __svelte_original.user_effect(() => {\n return () => { try { dt.unmount(id); } catch {} };\n });\n } catch {}\n }\n } catch {}\n return result;\n}\n\nexport function pop() {\n // Capture devtools errors but ALWAYS forward to the original pop so the\n // Svelte component stack stays balanced.\n try {\n const dt = __dt();\n if (dt && __idStack.length > 0) {\n const id = __idStack.pop();\n try { dt.endInit(id); } catch {}\n try { dt.registered(id); } catch {}\n }\n } catch {}\n return __svelte_original.pop.apply(null, arguments);\n}\n\n// --- Signal Creation (type markers) ---\n\nexport function state() {\n const signal = __svelte_original.state.apply(null, arguments);\n try {\n __pendingSignal.ref = signal;\n __pendingSignal.type = 'state';\n } catch {}\n return signal;\n}\n\nexport function derived() {\n const signal = __svelte_original.derived.apply(null, arguments);\n try {\n __pendingSignal.ref = signal;\n __pendingSignal.type = 'derived';\n } catch {}\n return signal;\n}\n\nexport function proxy() {\n const p = __svelte_original.proxy.apply(null, arguments);\n try {\n __pendingSignal.ref = p;\n __pendingSignal.type = 'proxy';\n } catch {}\n return p;\n}\n\n// --- Signal Tagging (Svelte dev mode) ---\n\nexport function tag(signal, name) {\n const result = __svelte_original.tag.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n const type = (__pendingSignal.ref === signal) ? __pendingSignal.type : 'state';\n if (type === 'derived') {\n dt.trackDerived(signal, name, cid);\n } else {\n dt.trackState(signal, name, cid);\n }\n }\n __pendingSignal.ref = null;\n __pendingSignal.type = null;\n } catch {}\n return result;\n}\n\nexport function tag_proxy(proxy, name) {\n const result = __svelte_original.tag_proxy.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt.trackProxy(proxy, name, cid);\n }\n __pendingSignal.ref = null;\n __pendingSignal.type = null;\n } catch {}\n return result;\n}\n\n// --- Effect Tracking ---\n\nexport function user_effect() {\n const result = __svelte_original.user_effect.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt._effectCounter = (dt._effectCounter || 0) + 1;\n // Track the effect OBJECT (not the callback). The Svelte runtime\n // populates result.deps with the signals this effect depends on,\n // which is what getReactiveGraph() reads to build edges.\n dt.trackEffect(result, 'effect_' + dt._effectCounter, cid);\n }\n } catch {}\n return result;\n}\n\nexport function user_pre_effect() {\n const result = __svelte_original.user_pre_effect.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt._effectCounter = (dt._effectCounter || 0) + 1;\n dt.trackEffect(result, 'effect_pre_' + dt._effectCounter, cid);\n }\n } catch {}\n return result;\n}\n`\n\nexport const runtimeCode = /* js */ `\nif (typeof window !== 'undefined' && !window.__SVELTE_DEVTOOLS__) {\n const __SVELTE_DT = {\n _nextId: 0,\n _instances: new Map(),\n _stack: [],\n _pendingFile: null,\n _effectCounter: 0,\n _debounceTimer: null,\n _listeners: new Set(),\n\n // Phase 2: Profiling data\n _profiles: new Map(),\n _initStartTimes: new Map(),\n _profileDebounceTimer: null,\n\n // Phase 2: Reactive graph data\n _reactiveNodes: new Map(),\n _reactiveProxies: new Map(),\n\n // Phase 3: State timeline\n _stateTimeline: [],\n _stateSnapshots: new Map(),\n _timelineDebounceTimer: null,\n\n register(file) {\n const id = this._nextId++;\n const parentId = this._stack.length > 0 ? this._stack[this._stack.length - 1] : null;\n const name = file.split('/').pop()?.replace('.svelte', '') || 'Unknown';\n this._instances.set(id, { id, file, name, parentId, mounted: true, children: [] });\n if (parentId !== null) {\n const parent = this._instances.get(parentId);\n if (parent) parent.children.push(id);\n }\n this._stack.push(id);\n this._scheduleUpdate();\n return id;\n },\n\n registered(id) {\n const idx = this._stack.indexOf(id);\n if (idx !== -1) this._stack.splice(idx, 1);\n },\n\n mount(id) {\n const instance = this._instances.get(id);\n if (instance && !instance.mounted) {\n instance.mounted = true;\n this._scheduleUpdate();\n }\n },\n\n unmount(id) {\n const instance = this._instances.get(id);\n if (instance) {\n if (instance.parentId !== null) {\n const parent = this._instances.get(instance.parentId);\n if (parent) {\n parent.children = parent.children.filter(cid => cid !== id);\n }\n }\n this._removeChildren(id);\n this._cleanupReactiveNodes(id);\n this._instances.delete(id);\n }\n this._scheduleUpdate();\n },\n\n _cleanupReactiveNodes(componentId) {\n for (const [nodeId, entry] of this._reactiveNodes) {\n if (entry.meta.componentId === componentId) {\n this._reactiveNodes.delete(nodeId);\n }\n }\n },\n\n _removeChildren(parentId) {\n const parent = this._instances.get(parentId);\n if (!parent) return;\n for (const childId of [...parent.children]) {\n this._removeChildren(childId);\n this._cleanupReactiveNodes(childId);\n this._instances.delete(childId);\n }\n },\n\n _scheduleUpdate() {\n if (this._debounceTimer) clearTimeout(this._debounceTimer);\n this._debounceTimer = setTimeout(() => {\n this._sendUpdate();\n }, 100);\n },\n\n _sendUpdate() {\n const components = [];\n for (const [, instance] of this._instances) {\n if (instance.mounted) {\n components.push({\n id: instance.id,\n file: instance.file,\n name: instance.name,\n parentId: instance.parentId,\n mounted: instance.mounted,\n });\n }\n }\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:components', { components });\n }\n },\n\n getTree() {\n const components = [];\n for (const [, instance] of this._instances) {\n if (instance.mounted) {\n components.push({\n id: instance.id,\n file: instance.file,\n name: instance.name,\n parentId: instance.parentId,\n mounted: instance.mounted,\n });\n }\n }\n return components;\n },\n\n // --- Phase 2: Render Profiling ---\n\n startInit(id) {\n this._initStartTimes.set(id, performance.now());\n },\n\n endInit(id) {\n const start = this._initStartTimes.get(id);\n if (start === undefined) return;\n const initTime = performance.now() - start;\n this._initStartTimes.delete(id);\n const instance = this._instances.get(id);\n if (!instance) return;\n this._profiles.set(id, {\n componentId: id,\n file: instance.file,\n name: instance.name,\n initTime,\n renderCount: 0,\n totalRenderTime: 0,\n lastRenderTime: 0,\n lastRenderAt: Date.now(),\n });\n this._scheduleProfileUpdate();\n },\n\n recordRender(id) {\n const profile = this._profiles.get(id);\n if (!profile) {\n const instance = this._instances.get(id);\n if (!instance) return;\n this._profiles.set(id, {\n componentId: id,\n file: instance.file,\n name: instance.name,\n initTime: 0,\n renderCount: 1,\n totalRenderTime: 0,\n lastRenderTime: 0,\n lastRenderAt: Date.now(),\n });\n } else {\n profile.renderCount++;\n profile.lastRenderAt = Date.now();\n }\n this._scheduleProfileUpdate();\n },\n\n recordRenderTime(id, duration) {\n const profile = this._profiles.get(id);\n if (profile) {\n profile.totalRenderTime += duration;\n profile.lastRenderTime = duration;\n }\n },\n\n _scheduleProfileUpdate() {\n if (this._profileDebounceTimer) clearTimeout(this._profileDebounceTimer);\n this._profileDebounceTimer = setTimeout(() => {\n this._sendProfileUpdate();\n }, 500);\n },\n\n _sendProfileUpdate() {\n const profiles = Array.from(this._profiles.values());\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:profiles', { profiles });\n }\n },\n\n getProfiles() {\n return Array.from(this._profiles.values());\n },\n\n resetProfiles() {\n this._profiles.clear();\n this._scheduleProfileUpdate();\n },\n\n // --- Phase 2: Reactive Graph Tracking ---\n\n trackState(signal, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(signal),\n meta: { id: nodeId, type: 'state', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackProxy(proxy, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveProxies.set(nodeId, new WeakRef(proxy));\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef({ v: '(proxy)', _isProxy: true }),\n meta: { id: nodeId, type: 'state', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackDerived(signal, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(signal),\n meta: { id: nodeId, type: 'derived', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackEffect(effect, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(effect || { v: undefined, _isEffect: true }),\n meta: { id: nodeId, type: 'effect', name, componentId, componentFile: instance ? instance.file : '' }\n });\n return effect;\n },\n\n getReactiveGraph() {\n const nodes = [];\n const edges = [];\n const signalToId = new Map();\n\n for (const [nodeId, entry] of this._reactiveNodes) {\n const signal = entry.signal.deref();\n if (!signal || !this._instances.has(entry.meta.componentId)) {\n this._reactiveNodes.delete(nodeId);\n continue;\n }\n signalToId.set(signal, nodeId);\n const node = { ...entry.meta };\n if (signal._isProxy) {\n const proxyRef = this._reactiveProxies.get(nodeId);\n const proxy = proxyRef?.deref();\n if (proxy) {\n try {\n node.value = Array.isArray(proxy) ? '[' + proxy.length + ']' : '{' + Object.keys(proxy).length + '}';\n } catch { node.value = '(proxy)'; }\n }\n } else if (node.type !== 'effect' && signal.v !== undefined && typeof signal.v !== 'symbol') {\n try {\n const v = signal.v;\n if (typeof v === 'number' || typeof v === 'string' || typeof v === 'boolean' || v === null) {\n node.value = v;\n } else {\n node.value = '(object)';\n }\n } catch { /* ignore */ }\n }\n nodes.push(node);\n }\n\n // Map proxy internal signals to their proxy node ID\n for (const [nodeId, ref] of this._reactiveProxies) {\n const proxy = ref.deref();\n if (!proxy) { this._reactiveProxies.delete(nodeId); continue; }\n const meta = this._reactiveNodes.get(nodeId)?.meta;\n if (!meta || !this._instances.has(meta.componentId)) { this._reactiveProxies.delete(nodeId); continue; }\n }\n\n // Build edges from deps\n const edgeSet = new Set();\n for (const [nodeId, entry] of this._reactiveNodes) {\n const signal = entry.signal.deref();\n if (!signal) continue;\n if (!signal.deps) continue;\n\n const visited = new Set();\n const queue = [...signal.deps];\n while (queue.length > 0) {\n const dep = queue.shift();\n if (!dep || visited.has(dep)) continue;\n visited.add(dep);\n const depId = signalToId.get(dep);\n if (depId) {\n const key = depId + '>' + nodeId;\n if (depId !== nodeId && !edgeSet.has(key)) {\n edgeSet.add(key);\n edges.push({ from: depId, to: nodeId });\n }\n } else if (dep.deps) {\n for (const d of dep.deps) queue.push(d);\n }\n }\n }\n\n return { nodes, edges };\n },\n\n sendReactiveGraph() {\n const graph = this.getReactiveGraph();\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:reactive-graph', graph);\n }\n },\n\n // --- Phase 3: State Timeline ---\n\n _pollStateValues() {\n for (const [nodeId, entry] of this._reactiveNodes) {\n if (entry.meta.type !== 'state') continue;\n if (!this._instances.has(entry.meta.componentId)) {\n this._reactiveNodes.delete(nodeId);\n continue;\n }\n const signal = entry.signal.deref();\n if (!signal || signal.v === undefined) continue;\n try {\n const currentVal = signal.v;\n const prev = this._stateSnapshots.get(nodeId);\n if (prev !== undefined && currentVal === prev) continue;\n const isPrimitive = currentVal === null || typeof currentVal !== 'object';\n let newSnapshot;\n if (isPrimitive) {\n if (prev !== undefined && prev === currentVal) continue;\n newSnapshot = currentVal;\n } else {\n const currStr = JSON.stringify(currentVal);\n const prevStr = this._stateSnapshotStrs?.get(nodeId);\n if (prevStr === currStr) continue;\n newSnapshot = JSON.parse(currStr);\n if (!this._stateSnapshotStrs) this._stateSnapshotStrs = new Map();\n this._stateSnapshotStrs.set(nodeId, currStr);\n }\n if (this._stateTimeline.length >= 500) this._stateTimeline.splice(0, this._stateTimeline.length - 499);\n this._stateTimeline.push({\n id: nodeId,\n name: entry.meta.name,\n componentFile: entry.meta.componentFile,\n oldValue: prev !== undefined ? prev : null,\n newValue: newSnapshot,\n timestamp: Date.now(),\n });\n this._stateSnapshots.set(nodeId, newSnapshot);\n this._scheduleTimelineUpdate();\n } catch { /* ignore non-serializable */ }\n }\n },\n\n _scheduleTimelineUpdate() {\n if (this._timelineDebounceTimer) clearTimeout(this._timelineDebounceTimer);\n this._timelineDebounceTimer = setTimeout(() => {\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:state-timeline', { changes: this._stateTimeline });\n }\n }, 300);\n },\n\n getStateTimeline() {\n return this._stateTimeline;\n },\n\n clearStateTimeline() {\n this._stateTimeline = [];\n this._scheduleTimelineUpdate();\n },\n\n // --- FPS Monitoring ---\n // Uses requestAnimationFrame to measure frame rate with minimal overhead.\n // Only stores timestamps - no allocations per frame beyond a single array push.\n _fpsFrameTimes: [],\n\n _fpsLoop() {\n this._fpsFrameTimes.push(performance.now());\n requestAnimationFrame(() => this._fpsLoop());\n },\n\n _sampleFps() {\n const now = performance.now();\n // Remove frame timestamps older than 1 second\n const cutoff = now - 1000;\n let i = 0;\n while (i < this._fpsFrameTimes.length && this._fpsFrameTimes[i] < cutoff) i++;\n if (i > 0) this._fpsFrameTimes.splice(0, i);\n const fps = this._fpsFrameTimes.length;\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:fps', { timestamp: Date.now(), fps });\n }\n }\n };\n\n window.__SVELTE_DEVTOOLS__ = __SVELTE_DT;\n\n // Poll state values for timeline\n setInterval(() => { __SVELTE_DT._pollStateValues(); }, 200);\n\n // FPS monitoring\n requestAnimationFrame(() => __SVELTE_DT._fpsLoop());\n setInterval(() => __SVELTE_DT._sampleFps(), 500);\n\n // Phase 3: Capture runtime errors\n window.addEventListener('error', (event) => {\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:runtime-error', {\n message: event.message,\n file: event.filename,\n line: event.lineno,\n column: event.colno,\n stack: event.error?.stack || '',\n timestamp: Date.now(),\n });\n }\n });\n window.addEventListener('unhandledrejection', (event) => {\n if (import.meta.hot) {\n const reason = event.reason;\n import.meta.hot.send('svelte-devtools:runtime-error', {\n message: reason?.message || String(reason),\n stack: reason?.stack || '',\n timestamp: Date.now(),\n });\n }\n });\n\n // Listen for reactive graph requests from server\n if (import.meta.hot) {\n import.meta.hot.on('svelte-devtools:request-reactive-graph', () => {\n __SVELTE_DT.sendReactiveGraph();\n });\n import.meta.hot.on('svelte-devtools:request-state-timeline', () => {\n import.meta.hot.send('svelte-devtools:state-timeline', { changes: __SVELTE_DT._stateTimeline });\n });\n import.meta.hot.on('svelte-devtools:clear-state-timeline', () => {\n __SVELTE_DT.clearStateTimeline();\n });\n }\n}\n`\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport crypto from 'node:crypto'\nimport type { RenderProfile, LoadProfile, FpsSample } from '../types.js'\n\nexport interface SessionSnapshot {\n /** componentId -> { renderCount, totalRenderTime } at snapshot moment */\n renderProfiles: Array<{\n componentId: number\n file: string\n name: string\n renderCount: number\n totalRenderTime: number\n }>\n loadProfilesCount: number\n fpsCount: number\n takenAt: number\n}\n\nexport interface SessionRecord {\n id: string\n label: string\n startedAt: number\n endedAt?: number\n persist: boolean\n startSnapshot: SessionSnapshot\n endSnapshot?: SessionSnapshot\n /** load profiles that arrived strictly between startedAt..endedAt */\n loadProfiles: LoadProfile[]\n /** fps samples that arrived strictly between startedAt..endedAt */\n fpsSamples: FpsSample[]\n}\n\nexport interface SessionDelta {\n durationMs: number\n components: Array<{\n componentId: number\n file: string\n name: string\n renderCountDelta: number\n totalRenderTimeDelta: number\n avgRenderTimeDelta: number\n }>\n loadProfiles: {\n count: number\n avgDuration: number\n p95Duration: number\n }\n fps: {\n samples: number\n avg: number\n min: number\n drops: number\n }\n}\n\nexport interface SessionDiff {\n a: { id: string; label: string }\n b: { id: string; label: string }\n render: {\n totalRenderTimeDeltaA: number\n totalRenderTimeDeltaB: number\n diff: number\n verdict: 'improved' | 'regressed' | 'unchanged'\n }\n load: {\n avgA: number\n avgB: number\n diff: number\n verdict: 'improved' | 'regressed' | 'unchanged'\n }\n fps: {\n avgA: number\n avgB: number\n diff: number\n verdict: 'improved' | 'regressed' | 'unchanged'\n }\n}\n\nexport interface MetricGetters {\n getRenderProfiles: () => RenderProfile[]\n getLoadProfiles: () => LoadProfile[]\n getFpsSamples: () => FpsSample[]\n}\n\nconst UNCHANGED_RENDER_THRESHOLD_MS = 1\nconst UNCHANGED_LOAD_THRESHOLD_MS = 5\nconst UNCHANGED_FPS_THRESHOLD = 1\nconst FPS_DROP_THRESHOLD = 30\n\nfunction takeSnapshot(getters: MetricGetters): SessionSnapshot {\n const renderProfiles = getters.getRenderProfiles().map(p => ({\n componentId: p.componentId,\n file: p.file,\n name: p.name,\n renderCount: p.renderCount,\n totalRenderTime: p.totalRenderTime,\n }))\n return {\n renderProfiles,\n loadProfilesCount: getters.getLoadProfiles().length,\n fpsCount: getters.getFpsSamples().length,\n takenAt: Date.now(),\n }\n}\n\nfunction classify(diff: number, threshold: number, lowerIsBetter: boolean):\n 'improved' | 'regressed' | 'unchanged' {\n if (Math.abs(diff) < threshold) return 'unchanged'\n const negativeIsBetter = lowerIsBetter\n if (negativeIsBetter) return diff < 0 ? 'improved' : 'regressed'\n return diff > 0 ? 'improved' : 'regressed'\n}\n\nexport interface SessionStoreOptions {\n persistDir: string\n getters: MetricGetters\n}\n\nexport class SessionStore {\n private sessions = new Map<string, SessionRecord>()\n private active: string | null = null\n private readonly persistDir: string\n private readonly getters: MetricGetters\n\n constructor(opts: SessionStoreOptions) {\n this.persistDir = opts.persistDir\n this.getters = opts.getters\n }\n\n start(label: string, persist: boolean): SessionRecord {\n if (this.active) {\n throw new Error(\n `A session is already active: ${this.active}. Call end_session before starting a new one.`,\n )\n }\n const id = `s_${Date.now().toString(36)}_${crypto.randomBytes(3).toString('hex')}`\n const record: SessionRecord = {\n id,\n label,\n startedAt: Date.now(),\n persist,\n startSnapshot: takeSnapshot(this.getters),\n loadProfiles: [],\n fpsSamples: [],\n }\n this.sessions.set(id, record)\n this.active = id\n return record\n }\n\n /** Called by the plugin whenever a new load profile arrives. */\n recordLoadProfile(p: LoadProfile): void {\n if (!this.active) return\n const rec = this.sessions.get(this.active)\n if (rec) rec.loadProfiles.push(p)\n }\n\n /** Called by the plugin whenever a new fps sample arrives. */\n recordFpsSample(s: FpsSample): void {\n if (!this.active) return\n const rec = this.sessions.get(this.active)\n if (rec) rec.fpsSamples.push(s)\n }\n\n end(keep: 'memory' | 'disk' | 'discard'): SessionRecord {\n if (!this.active) throw new Error('No active session')\n const rec = this.sessions.get(this.active)\n if (!rec) throw new Error('Active session missing from store')\n rec.endedAt = Date.now()\n rec.endSnapshot = takeSnapshot(this.getters)\n this.active = null\n\n if (keep === 'discard') {\n this.sessions.delete(rec.id)\n } else if (keep === 'disk' || rec.persist) {\n this.persistToDisk(rec)\n }\n return rec\n }\n\n get(id: string): SessionRecord | undefined {\n const inMem = this.sessions.get(id)\n if (inMem) return inMem\n return this.loadFromDisk(id)\n }\n\n list(): Array<{\n id: string\n label: string\n startedAt: number\n endedAt?: number\n persisted: boolean\n active: boolean\n }> {\n const seen = new Set<string>()\n const out: Array<{\n id: string\n label: string\n startedAt: number\n endedAt?: number\n persisted: boolean\n active: boolean\n }> = []\n for (const rec of this.sessions.values()) {\n seen.add(rec.id)\n out.push({\n id: rec.id,\n label: rec.label,\n startedAt: rec.startedAt,\n endedAt: rec.endedAt,\n persisted: fs.existsSync(this.pathFor(rec.id)),\n active: this.active === rec.id,\n })\n }\n try {\n if (fs.existsSync(this.persistDir)) {\n for (const name of fs.readdirSync(this.persistDir)) {\n if (!name.endsWith('.json')) continue\n const id = name.slice(0, -5)\n if (seen.has(id)) continue\n try {\n const rec = JSON.parse(fs.readFileSync(path.join(this.persistDir, name), 'utf-8'))\n out.push({\n id: rec.id,\n label: rec.label,\n startedAt: rec.startedAt,\n endedAt: rec.endedAt,\n persisted: true,\n active: false,\n })\n } catch {\n /* skip unreadable session file */\n }\n }\n }\n } catch {\n /* persist dir not accessible */\n }\n return out.sort((a, b) => b.startedAt - a.startedAt)\n }\n\n delete(id: string): boolean {\n const had = this.sessions.delete(id)\n let onDisk = false\n try {\n const p = this.pathFor(id)\n if (fs.existsSync(p)) {\n fs.unlinkSync(p)\n onDisk = true\n }\n } catch {\n /* ignore */\n }\n if (this.active === id) this.active = null\n return had || onDisk\n }\n\n delta(id: string): SessionDelta {\n const rec = this.get(id)\n if (!rec) throw new Error(`Session not found: ${id}`)\n if (!rec.endSnapshot || rec.endedAt === undefined) {\n throw new Error(`Session ${id} has not been ended yet`)\n }\n const startMap = new Map(rec.startSnapshot.renderProfiles.map(p => [p.componentId, p]))\n const components = rec.endSnapshot.renderProfiles\n .map(end => {\n const start = startMap.get(end.componentId)\n const startRenderCount = start?.renderCount ?? 0\n const startTotal = start?.totalRenderTime ?? 0\n const renderCountDelta = end.renderCount - startRenderCount\n const totalRenderTimeDelta = end.totalRenderTime - startTotal\n return {\n componentId: end.componentId,\n file: end.file,\n name: end.name,\n renderCountDelta,\n totalRenderTimeDelta,\n avgRenderTimeDelta:\n renderCountDelta > 0 ? totalRenderTimeDelta / renderCountDelta : 0,\n }\n })\n .filter(c => c.renderCountDelta > 0)\n .sort((a, b) => b.totalRenderTimeDelta - a.totalRenderTimeDelta)\n\n const loadDurations = rec.loadProfiles.map(l => l.duration)\n const loadAvg = avg(loadDurations)\n const loadP95 = percentile(loadDurations, 95)\n\n const fpsValues = rec.fpsSamples.map(s => s.fps)\n const fpsAvg = avg(fpsValues)\n const fpsMin = fpsValues.length ? Math.min(...fpsValues) : 0\n const fpsDrops = fpsValues.filter(f => f < FPS_DROP_THRESHOLD).length\n\n return {\n durationMs: rec.endedAt - rec.startedAt,\n components,\n loadProfiles: { count: rec.loadProfiles.length, avgDuration: loadAvg, p95Duration: loadP95 },\n fps: { samples: fpsValues.length, avg: fpsAvg, min: fpsMin, drops: fpsDrops },\n }\n }\n\n compare(idA: string, idB: string): SessionDiff {\n const a = this.delta(idA)\n const b = this.delta(idB)\n const recA = this.get(idA)!\n const recB = this.get(idB)!\n const totalA = a.components.reduce((s, c) => s + c.totalRenderTimeDelta, 0)\n const totalB = b.components.reduce((s, c) => s + c.totalRenderTimeDelta, 0)\n const renderDiff = totalB - totalA\n const loadDiff = b.loadProfiles.avgDuration - a.loadProfiles.avgDuration\n const fpsDiff = b.fps.avg - a.fps.avg\n return {\n a: { id: recA.id, label: recA.label },\n b: { id: recB.id, label: recB.label },\n render: {\n totalRenderTimeDeltaA: totalA,\n totalRenderTimeDeltaB: totalB,\n diff: renderDiff,\n verdict: classify(renderDiff, UNCHANGED_RENDER_THRESHOLD_MS, true),\n },\n load: {\n avgA: a.loadProfiles.avgDuration,\n avgB: b.loadProfiles.avgDuration,\n diff: loadDiff,\n verdict: classify(loadDiff, UNCHANGED_LOAD_THRESHOLD_MS, true),\n },\n fps: {\n avgA: a.fps.avg,\n avgB: b.fps.avg,\n diff: fpsDiff,\n verdict: classify(fpsDiff, UNCHANGED_FPS_THRESHOLD, false),\n },\n }\n }\n\n private pathFor(id: string): string {\n return path.join(this.persistDir, `${id}.json`)\n }\n\n private persistToDisk(rec: SessionRecord): void {\n try {\n fs.mkdirSync(this.persistDir, { recursive: true })\n fs.writeFileSync(this.pathFor(rec.id), JSON.stringify(rec, null, 2), { mode: 0o600 })\n } catch {\n /* persist failure is non-fatal; the in-memory record stays available */\n }\n }\n\n private loadFromDisk(id: string): SessionRecord | undefined {\n try {\n const raw = fs.readFileSync(this.pathFor(id), 'utf-8')\n return JSON.parse(raw)\n } catch {\n return undefined\n }\n }\n}\n\nfunction avg(xs: number[]): number {\n if (!xs.length) return 0\n return xs.reduce((s, x) => s + x, 0) / xs.length\n}\n\nfunction percentile(xs: number[], p: number): number {\n if (!xs.length) return 0\n const sorted = [...xs].sort((a, b) => a - b)\n const idx = Math.min(sorted.length - 1, Math.floor((p / 100) * sorted.length))\n return sorted[idx]\n}\n","import type {\n RenderProfile,\n ReactiveGraph,\n LoadProfile,\n FpsSample,\n} from '../types.js'\n\nexport type IssueKind =\n | 'slow-component-render'\n | 'over-rendered-component'\n | 'slow-load'\n | 'fps-drop'\n | 'effect-overconnected'\n | 'derived-orphan'\n\nexport interface PerformanceIssue {\n id: string\n kind: IssueKind\n severity: 'low' | 'medium' | 'high'\n summary: string\n file?: string\n line?: number\n metric: Record<string, number>\n /** Tool that returns more detail for this issue. */\n suggestedTool: string\n}\n\nexport interface IssueThresholds {\n /** Per-render time (ms) above which a component render is considered slow. */\n avgRenderTimeMs?: number\n /** Render count above which a component is considered over-rendered. */\n renderCount?: number\n /** Load duration (ms) above which a SvelteKit load is slow. */\n loadDurationMs?: number\n /** FPS below which we record a drop. */\n fpsDropThreshold?: number\n /** Outgoing edge count from an effect above which it is over-connected. */\n effectMaxDeps?: number\n}\n\nconst DEFAULTS: Required<IssueThresholds> = {\n avgRenderTimeMs: 4,\n renderCount: 30,\n loadDurationMs: 200,\n fpsDropThreshold: 40,\n effectMaxDeps: 8,\n}\n\nexport interface IssueInputs {\n renderProfiles: RenderProfile[]\n reactiveGraph: ReactiveGraph\n loadProfiles: LoadProfile[]\n fpsSamples: FpsSample[]\n}\n\nexport function listPerformanceIssues(\n inputs: IssueInputs,\n thresholds: IssueThresholds = {},\n): PerformanceIssue[] {\n const t = { ...DEFAULTS, ...thresholds }\n const out: PerformanceIssue[] = []\n\n for (const p of inputs.renderProfiles) {\n const avg = p.renderCount > 0 ? p.totalRenderTime / p.renderCount : 0\n if (avg >= t.avgRenderTimeMs) {\n out.push({\n id: `slow-render:${p.file}:${p.componentId}`,\n kind: 'slow-component-render',\n severity: avg >= t.avgRenderTimeMs * 4 ? 'high' : avg >= t.avgRenderTimeMs * 2 ? 'medium' : 'low',\n summary: `${p.name} averages ${avg.toFixed(2)}ms per render (${p.renderCount} renders)`,\n file: p.file,\n metric: { avgRenderTimeMs: round(avg), renderCount: p.renderCount, totalRenderTimeMs: round(p.totalRenderTime) },\n suggestedTool: 'get_render_profile',\n })\n }\n if (p.renderCount >= t.renderCount) {\n out.push({\n id: `over-render:${p.file}:${p.componentId}`,\n kind: 'over-rendered-component',\n severity: p.renderCount >= t.renderCount * 8 ? 'high' : p.renderCount >= t.renderCount * 3 ? 'medium' : 'low',\n summary: `${p.name} rendered ${p.renderCount} times`,\n file: p.file,\n metric: { renderCount: p.renderCount, avgRenderTimeMs: round(avg) },\n suggestedTool: 'get_component_hotspots',\n })\n }\n }\n\n for (const l of inputs.loadProfiles) {\n if (l.duration >= t.loadDurationMs) {\n out.push({\n id: `slow-load:${l.route}:${l.timestamp}`,\n kind: 'slow-load',\n severity: l.duration >= t.loadDurationMs * 5 ? 'high' : l.duration >= t.loadDurationMs * 2 ? 'medium' : 'low',\n summary: `${l.type} load for ${l.route} took ${l.duration.toFixed(0)}ms`,\n file: l.file,\n metric: { durationMs: round(l.duration), dataSizeBytes: l.dataSize },\n suggestedTool: 'get_load_waterfall',\n })\n }\n }\n\n const fpsDrops = inputs.fpsSamples.filter(s => s.fps < t.fpsDropThreshold)\n if (fpsDrops.length > 0) {\n const min = Math.min(...fpsDrops.map(s => s.fps))\n out.push({\n id: `fps-drops:${inputs.fpsSamples[0]?.timestamp ?? 0}`,\n kind: 'fps-drop',\n severity: min < 15 ? 'high' : min < 30 ? 'medium' : 'low',\n summary: `${fpsDrops.length} FPS samples below ${t.fpsDropThreshold} (min ${min})`,\n metric: { dropCount: fpsDrops.length, minFps: min, threshold: t.fpsDropThreshold },\n suggestedTool: 'get_fps_drops',\n })\n }\n\n // Reactive graph: count outgoing edges per node\n const outDegree = new Map<string, number>()\n for (const e of inputs.reactiveGraph.edges) {\n outDegree.set(e.from, (outDegree.get(e.from) ?? 0) + 1)\n }\n const inDegree = new Map<string, number>()\n for (const e of inputs.reactiveGraph.edges) {\n inDegree.set(e.to, (inDegree.get(e.to) ?? 0) + 1)\n }\n for (const node of inputs.reactiveGraph.nodes) {\n if (node.type === 'effect') {\n const deps = inDegree.get(node.id) ?? 0\n if (deps >= t.effectMaxDeps) {\n out.push({\n id: `effect-deps:${node.id}`,\n kind: 'effect-overconnected',\n severity: deps >= t.effectMaxDeps * 3 ? 'high' : deps >= t.effectMaxDeps * 2 ? 'medium' : 'low',\n summary: `effect \"${node.name}\" depends on ${deps} reactive values`,\n file: node.componentFile,\n metric: { depCount: deps },\n suggestedTool: 'get_reactive_graph_problems',\n })\n }\n }\n if (node.type === 'derived') {\n const fanout = outDegree.get(node.id) ?? 0\n if (fanout === 0 && (inDegree.get(node.id) ?? 0) > 0) {\n out.push({\n id: `derived-orphan:${node.id}`,\n kind: 'derived-orphan',\n severity: 'low',\n summary: `derived \"${node.name}\" has dependencies but is unused`,\n file: node.componentFile,\n metric: { fanout },\n suggestedTool: 'get_reactive_graph_problems',\n })\n }\n }\n }\n\n return out.sort(compareSeverity)\n}\n\nconst SEV_RANK: Record<PerformanceIssue['severity'], number> = { high: 0, medium: 1, low: 2 }\n\nfunction compareSeverity(a: PerformanceIssue, b: PerformanceIssue): number {\n return SEV_RANK[a.severity] - SEV_RANK[b.severity]\n}\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100\n}\n\nexport interface ReactiveProblems {\n effects: Array<{ id: string; name: string; file: string; depCount: number }>\n orphanDeriveds: Array<{ id: string; name: string; file: string }>\n isolatedNodes: Array<{ id: string; name: string; type: string; file: string }>\n}\n\nexport function summarizeReactiveProblems(graph: ReactiveGraph, t: IssueThresholds = {}): ReactiveProblems {\n const thresh = { ...DEFAULTS, ...t }\n const inDegree = new Map<string, number>()\n const outDegree = new Map<string, number>()\n for (const e of graph.edges) {\n inDegree.set(e.to, (inDegree.get(e.to) ?? 0) + 1)\n outDegree.set(e.from, (outDegree.get(e.from) ?? 0) + 1)\n }\n const effects: ReactiveProblems['effects'] = []\n const orphanDeriveds: ReactiveProblems['orphanDeriveds'] = []\n const isolatedNodes: ReactiveProblems['isolatedNodes'] = []\n for (const node of graph.nodes) {\n const ind = inDegree.get(node.id) ?? 0\n const outd = outDegree.get(node.id) ?? 0\n if (node.type === 'effect' && ind >= thresh.effectMaxDeps) {\n effects.push({ id: node.id, name: node.name, file: node.componentFile, depCount: ind })\n }\n if (node.type === 'derived' && outd === 0 && ind > 0) {\n orphanDeriveds.push({ id: node.id, name: node.name, file: node.componentFile })\n }\n if (ind === 0 && outd === 0) {\n isolatedNodes.push({ id: node.id, name: node.name, type: node.type, file: node.componentFile })\n }\n }\n return { effects, orphanDeriveds, isolatedNodes }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'\nimport { z } from 'zod'\nimport type {\n RenderProfile,\n ReactiveGraph,\n LoadProfile,\n FpsSample,\n ComponentInstance,\n ProjectInfo,\n RouteInfo,\n ComponentRelation,\n} from '../types.js'\nimport { SessionStore } from './sessions.js'\nimport {\n listPerformanceIssues,\n summarizeReactiveProblems,\n type IssueThresholds,\n} from './issues.js'\n\nexport interface McpDeps {\n getProject: () => ProjectInfo\n getRoutes: () => RouteInfo[]\n getLiveComponents: () => ComponentInstance[]\n getComponentRelations: () => ComponentRelation[]\n getRenderProfiles: () => RenderProfile[]\n /** Resolves with the current reactive graph after refreshing from the browser. */\n getReactiveGraph: () => Promise<ReactiveGraph>\n getLoadProfiles: () => LoadProfile[]\n getFpsSamples: () => FpsSample[]\n sessions: SessionStore\n}\n\nconst TEXT = (value: unknown) => ({\n content: [{ type: 'text' as const, text: typeof value === 'string' ? value : JSON.stringify(value, null, 2) }],\n})\n\nexport function buildMcpServer(deps: McpDeps): McpServer {\n const server = new McpServer({\n name: 'vite-devtools-svelte',\n version: '0.1.0',\n })\n\n // --- read tools: issue surface ---\n\n server.registerTool(\n 'list_performance_issues',\n {\n title: 'List performance issues',\n description:\n 'Cross-cuts render/reactive/load/fps metrics and returns ranked issues. The entry point for AI-driven performance audits. Each issue carries `suggestedTool` naming the detail tool to call next.',\n inputSchema: {\n avgRenderTimeMs: z.number().optional(),\n renderCount: z.number().optional(),\n loadDurationMs: z.number().optional(),\n fpsDropThreshold: z.number().optional(),\n effectMaxDeps: z.number().optional(),\n },\n },\n async (args) => {\n const thresholds: IssueThresholds = args\n const reactiveGraph = await deps.getReactiveGraph()\n const issues = listPerformanceIssues(\n {\n renderProfiles: deps.getRenderProfiles(),\n reactiveGraph,\n loadProfiles: deps.getLoadProfiles(),\n fpsSamples: deps.getFpsSamples(),\n },\n thresholds,\n )\n return TEXT({ count: issues.length, issues })\n },\n )\n\n server.registerTool(\n 'get_component_hotspots',\n {\n title: 'Component render hotspots',\n description: 'Top components by total render time, with render count and per-render average.',\n inputSchema: { topN: z.number().int().min(1).max(200).optional() },\n },\n async ({ topN = 20 }) => {\n const list = [...deps.getRenderProfiles()]\n .map(p => ({\n file: p.file,\n name: p.name,\n componentId: p.componentId,\n renderCount: p.renderCount,\n totalRenderTimeMs: round(p.totalRenderTime),\n avgRenderTimeMs: round(p.renderCount > 0 ? p.totalRenderTime / p.renderCount : 0),\n lastRenderTimeMs: round(p.lastRenderTime),\n lastRenderAt: p.lastRenderAt,\n }))\n .sort((a, b) => b.totalRenderTimeMs - a.totalRenderTimeMs)\n .slice(0, topN)\n return TEXT(list)\n },\n )\n\n server.registerTool(\n 'get_reactive_graph_problems',\n {\n title: 'Reactive graph problems',\n description:\n 'Classified reactive graph issues: over-connected effects, orphan deriveds, isolated nodes. Returns categories instead of the full graph.',\n inputSchema: { effectMaxDeps: z.number().int().min(1).optional() },\n },\n async ({ effectMaxDeps }) => {\n const graph = await deps.getReactiveGraph()\n return TEXT(summarizeReactiveProblems(graph, { effectMaxDeps }))\n },\n )\n\n server.registerTool(\n 'get_load_waterfall',\n {\n title: 'SvelteKit load waterfall',\n description: 'Load profiles grouped by route, with timing and data size. Optionally filtered by route.',\n inputSchema: { route: z.string().optional() },\n },\n async ({ route }) => {\n let profiles = deps.getLoadProfiles()\n if (route) profiles = profiles.filter(p => p.route === route)\n const byRoute = new Map<string, LoadProfile[]>()\n for (const p of profiles) {\n const arr = byRoute.get(p.route) ?? []\n arr.push(p)\n byRoute.set(p.route, arr)\n }\n const groups = [...byRoute.entries()].map(([r, ps]) => {\n const durations = ps.map(p => p.duration)\n return {\n route: r,\n file: ps[0]?.file,\n count: ps.length,\n avgDuration: round(avg(durations)),\n maxDuration: round(Math.max(...durations)),\n totalDataBytes: ps.reduce((s, p) => s + p.dataSize, 0),\n samples: ps,\n }\n })\n return TEXT(groups.sort((a, b) => b.avgDuration - a.avgDuration))\n },\n )\n\n server.registerTool(\n 'get_fps_drops',\n {\n title: 'FPS drops',\n description: 'Samples whose FPS fell below `threshold`. Returns timestamp + fps for each.',\n inputSchema: {\n threshold: z.number().min(1).max(120).optional(),\n sinceMs: z.number().optional(),\n },\n },\n async ({ threshold = 40, sinceMs }) => {\n let samples = deps.getFpsSamples()\n if (sinceMs !== undefined) {\n const cutoff = Date.now() - sinceMs\n samples = samples.filter(s => s.timestamp >= cutoff)\n }\n const drops = samples.filter(s => s.fps < threshold)\n return TEXT({\n threshold,\n sampleCount: samples.length,\n dropCount: drops.length,\n minFps: drops.length ? Math.min(...drops.map(s => s.fps)) : null,\n drops,\n })\n },\n )\n\n server.registerTool(\n 'get_render_profile',\n {\n title: 'Render profile for a specific file',\n description: 'Returns render profile entries matching the given component file (substring match).',\n inputSchema: { file: z.string() },\n },\n async ({ file }) => {\n const matches = deps\n .getRenderProfiles()\n .filter(p => p.file.includes(file))\n .map(p => ({\n ...p,\n totalRenderTimeMs: round(p.totalRenderTime),\n avgRenderTimeMs: round(p.renderCount > 0 ? p.totalRenderTime / p.renderCount : 0),\n }))\n return TEXT(matches)\n },\n )\n\n // --- context tools ---\n\n server.registerTool(\n 'get_project_info',\n {\n title: 'Project info',\n description: 'Package name/version, Svelte / SvelteKit / Vite versions, dependency lists.',\n inputSchema: {},\n },\n async () => TEXT(deps.getProject()),\n )\n\n server.registerTool(\n 'get_routes',\n {\n title: 'SvelteKit routes',\n description: 'Static analysis of the SvelteKit routes tree.',\n inputSchema: {},\n },\n async () => TEXT(deps.getRoutes()),\n )\n\n server.registerTool(\n 'get_live_components',\n {\n title: 'Currently mounted components',\n description: 'Component instances with file, parent, mounted status as currently mounted in the browser.',\n inputSchema: {},\n },\n async () => TEXT(deps.getLiveComponents()),\n )\n\n server.registerTool(\n 'get_component_relations',\n {\n title: 'Component import graph',\n description: 'Static import relations between .svelte components.',\n inputSchema: {},\n },\n async () => TEXT(deps.getComponentRelations()),\n )\n\n // --- session tools ---\n\n server.registerTool(\n 'start_session',\n {\n title: 'Start measurement session',\n description:\n 'Begin capturing metrics under a labelled session. Required before compare_sessions. Set `persist:true` to write to disk on end; otherwise the session lives in memory only.',\n inputSchema: {\n label: z.string(),\n persist: z.boolean().optional(),\n },\n },\n async ({ label, persist = false }) => {\n const rec = deps.sessions.start(label, persist)\n return TEXT({ id: rec.id, label: rec.label, startedAt: rec.startedAt, persist: rec.persist })\n },\n )\n\n server.registerTool(\n 'end_session',\n {\n title: 'End current measurement session',\n description:\n 'Closes the active session and returns its delta. `keep` decides disposal: \"memory\" keeps it for this dev-server lifetime, \"disk\" writes to .vite-devtools-svelte/sessions/, \"discard\" deletes it.',\n inputSchema: {\n keep: z.enum(['memory', 'disk', 'discard']).optional(),\n },\n },\n async ({ keep = 'memory' }) => {\n const rec = deps.sessions.end(keep)\n const delta = rec.endedAt ? deps.sessions.delta(rec.id) : null\n return TEXT({\n id: rec.id,\n label: rec.label,\n startedAt: rec.startedAt,\n endedAt: rec.endedAt,\n keep,\n delta,\n })\n },\n )\n\n server.registerTool(\n 'compare_sessions',\n {\n title: 'Compare two sessions',\n description:\n 'Diff render / load / fps metrics between two ended sessions. Each section carries `verdict`: improved | regressed | unchanged.',\n inputSchema: { a: z.string(), b: z.string() },\n },\n async ({ a, b }) => TEXT(deps.sessions.compare(a, b)),\n )\n\n server.registerTool(\n 'list_sessions',\n {\n title: 'List sessions',\n description: 'In-memory + on-disk sessions, most recent first.',\n inputSchema: {},\n },\n async () => TEXT(deps.sessions.list()),\n )\n\n server.registerTool(\n 'load_session',\n {\n title: 'Load a session by id',\n description: 'Returns the full session record (including delta if ended) by id.',\n inputSchema: { id: z.string() },\n },\n async ({ id }) => {\n const rec = deps.sessions.get(id)\n if (!rec) return TEXT({ error: `Session not found: ${id}` })\n const delta = rec.endedAt ? deps.sessions.delta(id) : null\n return TEXT({ ...rec, delta })\n },\n )\n\n server.registerTool(\n 'delete_session',\n {\n title: 'Delete a session',\n description: 'Removes a session from memory and disk.',\n inputSchema: { id: z.string() },\n },\n async ({ id }) => TEXT({ deleted: deps.sessions.delete(id) }),\n )\n\n return server\n}\n\nexport { StreamableHTTPServerTransport }\n\nfunction avg(xs: number[]): number {\n if (!xs.length) return 0\n return xs.reduce((s, x) => s + x, 0) / xs.length\n}\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100\n}\n","/// <reference types=\"@vitejs/devtools-kit\" />\nimport type { Plugin } from 'vite'\n\n/**\n * SvelteKit dev bypasses Vite's `transformIndexHtml`, so `@vitejs/devtools`'s\n * `DevToolsInjection` never reaches the served HTML and the dock is invisible\n * on every SvelteKit page. Tracked upstream at\n * https://github.com/baseballyama/vite-devtools-repl/tree/main/sveltekit-transform-index-html-bypass\n *\n * As a stopgap, SvelteKit inlines `src/app.html` as a JS string literal inside\n * `.svelte-kit/generated/server/internal.js`:\n *\n * templates: {\n * app: ({ head, body, ... }) => \"<!doctype html>...<body>...</body>...\",\n * }\n *\n * That file is loaded through Vite's module pipeline (`vite.ssrLoadModule`),\n * so a regular `transform` hook can rewrite the literal to insert the dock's\n * inject script before `</body>`. The actual `<script>` runs in the browser\n * once the HTML is delivered, so no SSR safety guard on the inject module is\n * needed for this path.\n *\n * This is intentionally narrow — SvelteKit-specific path match plus a\n * structural assertion — and there's a test (`template-injector.test.ts`)\n * that fails if SvelteKit's generated shape changes, so a silent break shows\n * up in CI instead of as a missing dock in production.\n */\n\nexport const SVELTEKIT_INTERNAL_SUFFIX =\n '.svelte-kit/generated/server/internal.js'\n\n/** Marker that the `templates.app` literal in SvelteKit's generated server. */\nexport const TEMPLATE_APP_MARKER = 'templates: {'\n\n/** Where to inject the inject script — escaped because we're editing a JS string literal. */\nconst INJECT_SCRIPT_URL = '/@id/@vitejs/devtools/client/inject'\nconst INJECT_TAG = `<script type=\\\\\"module\\\\\" src=\\\\\"${INJECT_SCRIPT_URL}\\\\\"></script>`\n\n/**\n * `</body>` as it appears inside SvelteKit's generated string literal.\n * SvelteKit emits `app.html` via `JSON.stringify`-style escaping, which leaves\n * `/` alone — only control characters and quotes are escaped. So the literal\n * substring we actually search for is plain `</body>`.\n */\nconst BODY_CLOSE = '</body>'\n\n/**\n * Transform `.svelte-kit/generated/server/internal.js` to add the\n * `@vitejs/devtools` inject script right before `</body>` inside the app\n * template literal. Exposed for unit testing.\n *\n * Returns the new source if a substitution was made, or `null` to signal\n * \"nothing to do\" (already injected, structural marker missing, etc.).\n */\nexport function injectIntoSvelteKitInternal(code: string): string | null {\n // Cheap structural sanity check — bail if SvelteKit changed how it generates\n // the template object. The companion test asserts this branch is reachable.\n if (!code.includes(TEMPLATE_APP_MARKER)) return null\n if (!code.includes(BODY_CLOSE)) return null\n\n // Idempotence: don't double-inject across HMR re-runs.\n if (code.includes(INJECT_SCRIPT_URL)) return null\n\n // Only patch the literal that follows the `templates: {` marker, so a\n // future `</body>` mentioned in unrelated source code won't be touched.\n const markerIdx = code.indexOf(TEMPLATE_APP_MARKER)\n const bodyIdx = code.indexOf(BODY_CLOSE, markerIdx)\n if (bodyIdx === -1) return null\n\n return (\n code.slice(0, bodyIdx) +\n INJECT_TAG +\n code.slice(bodyIdx)\n )\n}\n\n/**\n * Vite plugin: inject `@vitejs/devtools/client/inject` into SvelteKit's\n * dev-only generated server template. Dev-only by construction.\n */\nexport function sveltekitTemplateInjector(): Plugin {\n return {\n name: 'vite-devtools-svelte:sveltekit-template-injector',\n enforce: 'post',\n apply: (_userConfig, env) => env.command === 'serve' && !env.isSsrBuild,\n\n transform(code, id) {\n if (!id.endsWith(SVELTEKIT_INTERNAL_SUFFIX)) return\n const next = injectIntoSvelteKitInternal(code)\n if (next === null) return\n return { code: next, map: null }\n },\n }\n}\n","/// <reference types=\"@vitejs/devtools-kit\" />\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite'\nimport path from 'node:path'\nimport fs from 'node:fs'\nimport net from 'node:net'\nimport crypto from 'node:crypto'\nimport { fileURLToPath } from 'node:url'\nimport { execFile } from 'node:child_process'\nimport { analyzeRoutes } from './analyzers/routes.js'\nimport { analyzeAssets, MIME_TYPES } from './analyzers/assets.js'\nimport { analyzeProject } from './analyzers/project.js'\nimport { analyzeComponents } from './analyzers/components.js'\nimport {\n RUNTIME_MODULE_ID,\n RESOLVED_RUNTIME_ID,\n runtimeCode,\n WRAPPER_MODULE_ID,\n wrapperCode,\n} from './runtime.js'\nimport { SessionStore } from './mcp/sessions.js'\nimport { buildMcpServer, StreamableHTTPServerTransport } from './mcp/server.js'\nimport { sveltekitTemplateInjector } from './template-injector.js'\nimport type {\n ComponentInstance,\n RenderProfile,\n LoadProfile,\n ReactiveGraph,\n StateChange,\n CompilerWarning,\n RuntimeError,\n InspectResult,\n ApiEndpoint,\n ApiResponse,\n ModuleGraphData,\n ModuleNode,\n OGPreview,\n BuildAnalysis,\n BuildChunk,\n FpsSample,\n} from './types.js'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\n/**\n * Validate that a URL does not target private/internal network addresses (SSRF prevention).\n * Allows only http/https schemes and blocks private IP ranges.\n */\nfunction validateExternalUrl(urlStr: string): void {\n let parsed: URL\n try {\n parsed = new URL(urlStr)\n } catch {\n throw new Error(`Invalid URL: ${urlStr}`)\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error(`Blocked URL scheme: ${parsed.protocol}`)\n }\n\n const hostname = parsed.hostname\n // Block IPv6 loopback\n if (hostname === '::1' || hostname === '[::1]') {\n throw new Error('Blocked: loopback address')\n }\n\n // Resolve hostname to check for private IPs\n if (net.isIP(hostname)) {\n if (isPrivateIP(hostname)) {\n throw new Error(`Blocked: private IP address ${hostname}`)\n }\n } else {\n // For domain names, block common internal hostnames\n const lower = hostname.toLowerCase()\n if (lower === 'localhost' || lower.endsWith('.local') || lower.endsWith('.internal')) {\n throw new Error(`Blocked: internal hostname ${hostname}`)\n }\n }\n}\n\nfunction isPrivateIP(ip: string): boolean {\n // IPv4 private ranges\n const parts = ip.split('.').map(Number)\n if (parts.length === 4) {\n // 127.0.0.0/8\n if (parts[0] === 127) return true\n // 10.0.0.0/8\n if (parts[0] === 10) return true\n // 172.16.0.0/12\n if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true\n // 192.168.0.0/16\n if (parts[0] === 192 && parts[1] === 168) return true\n // 169.254.0.0/16 (link-local)\n if (parts[0] === 169 && parts[1] === 254) return true\n // 0.0.0.0\n if (parts.every(p => p === 0)) return true\n }\n return false\n}\n\nexport interface SvelteDevtoolsOptions {\n /**\n * Enable component tracking via code injection.\n * @default true\n */\n componentTracking?: boolean\n}\n\nexport function svelteDevtools(options: SvelteDevtoolsOptions = {}): Plugin[] {\n const { componentTracking = true } = options\n\n let config: ResolvedConfig\n let server: ViteDevServer | undefined\n let root: string\n // Per-process random token used by the HTTP fallback endpoint and asset\n // middleware to authenticate requests. Embedded into the DevTools client\n // HTML via a <meta> tag and required as `x-svelte-devtools-token`.\n // Combined with strict same-origin checks, this prevents arbitrary web\n // pages (and DNS-rebinding attacks against the dev server bound to\n // 0.0.0.0) from invoking inspect-file / open-in-editor / send-api-request.\n const devtoolsToken = crypto.randomUUID()\n\n // Resolve a user-supplied file path strictly under the project root.\n // Symlinks are followed via realpathSync so that symlinks inside the\n // project cannot be used to escape the root sandbox.\n // Throws if the resolved real path is outside the project root.\n function resolveWithinRoot(input: string): string {\n if (typeof input !== 'string' || input.length === 0) {\n throw new Error('Invalid file path')\n }\n const realRoot = fs.realpathSync(root)\n const candidate = path.isAbsolute(input) ? input : path.resolve(root, input)\n let real: string\n try {\n real = fs.realpathSync(candidate)\n } catch {\n throw new Error('File not found')\n }\n if (real !== realRoot && !real.startsWith(realRoot + path.sep)) {\n throw new Error('Forbidden: path outside project root')\n }\n return real\n }\n\n let liveComponents: ComponentInstance[] = []\n let renderProfiles: RenderProfile[] = []\n let loadProfiles: LoadProfile[] = []\n let reactiveGraph: ReactiveGraph = { nodes: [], edges: [] }\n let reactiveGraphResolvers: Array<(graph: ReactiveGraph) => void> = []\n // Phase 3\n let stateTimeline: StateChange[] = []\n let stateTimelineResolvers: Array<(changes: StateChange[]) => void> = []\n let compilerWarnings: CompilerWarning[] = []\n let runtimeErrors: RuntimeError[] = []\n let fpsSamples: FpsSample[] = []\n\n // Session store for AI-driven measurement workflows.\n // Built lazily after `root` is resolved.\n let sessions: SessionStore | null = null\n function getSessions(): SessionStore {\n if (!sessions) {\n sessions = new SessionStore({\n persistDir: path.join(root, 'node_modules', '.vite-devtools-svelte', 'sessions'),\n getters: {\n getRenderProfiles: () => renderProfiles,\n getLoadProfiles: () => loadProfiles,\n getFpsSamples: () => fpsSamples,\n },\n })\n }\n return sessions\n }\n\n // --- Shared RPC handler implementations ---\n // Used by both DevTools Kit RPC registration and HTTP fallback endpoint.\n // Lazily initialized once (handlers close over mutable state so a single instance works).\n let _rpcHandlers: Record<string, (...args: any[]) => Promise<unknown>> | null = null\n function getRpcHandlers(): Record<string, (...args: any[]) => Promise<unknown>> {\n if (_rpcHandlers) return _rpcHandlers\n _rpcHandlers = {\n 'svelte-devtools:get-project': async () => analyzeProject(root),\n\n 'svelte-devtools:get-routes': async () => {\n const projectInfo = analyzeProject(root)\n return analyzeRoutes(projectInfo.routesDir)\n },\n\n 'svelte-devtools:get-assets': async () => {\n const projectInfo = analyzeProject(root)\n return analyzeAssets(projectInfo.staticDir)\n },\n\n 'svelte-devtools:get-component-relations': async () => analyzeComponents(root),\n\n 'svelte-devtools:get-live-components': async () => liveComponents,\n\n 'svelte-devtools:open-in-editor': async (filePath: string, line?: number) => {\n const resolved = resolveWithinRoot(String(filePath))\n if (line && Number(line) > 0) {\n execFile('code', ['--goto', `${resolved}:${Number(line)}`])\n } else {\n execFile('code', [resolved])\n }\n },\n\n 'svelte-devtools:open-reactive-in-editor': async (\n filePath: string,\n name: string,\n type: string,\n ) => {\n const resolved = resolveWithinRoot(String(filePath))\n let line = 0\n try {\n const source = fs.readFileSync(resolved, 'utf-8')\n const lines = source.split('\\n')\n if (String(type) === 'effect') {\n // Find the $effect( declaration\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].includes('$effect(') || lines[i].includes('$effect.pre(')) {\n line = i + 1\n break\n }\n }\n } else {\n // Find the variable declaration: let/const/var {name}\n const escaped = String(name).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const regex = new RegExp(`(?:let|const|var)\\\\s+${escaped}\\\\b`)\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i])) {\n line = i + 1\n break\n }\n }\n }\n } catch {\n /* file not readable */\n }\n if (line > 0) {\n execFile('code', ['--goto', `${resolved}:${line}`])\n } else {\n execFile('code', [resolved])\n }\n },\n\n 'svelte-devtools:get-render-profiles': async () => renderProfiles,\n\n 'svelte-devtools:get-reactive-graph': async () => {\n if (!server) return reactiveGraph\n server.hot.send('svelte-devtools:request-reactive-graph', {})\n return new Promise<ReactiveGraph>(resolve => {\n let resolved = false\n const resolver = (graph: ReactiveGraph) => {\n if (!resolved) {\n resolved = true\n clearTimeout(timeout)\n resolve(graph)\n }\n }\n const timeout = setTimeout(() => {\n resolved = true\n // Remove this resolver to prevent memory leak\n const idx = reactiveGraphResolvers.indexOf(resolver)\n if (idx !== -1) reactiveGraphResolvers.splice(idx, 1)\n resolve(reactiveGraph)\n }, 1000)\n reactiveGraphResolvers.push(resolver)\n })\n },\n\n 'svelte-devtools:get-load-profiles': async () => loadProfiles,\n\n 'svelte-devtools:clear-load-profiles': async () => {\n loadProfiles = []\n },\n\n 'svelte-devtools:get-state-timeline': async () => {\n if (!server) return stateTimeline\n server.hot.send('svelte-devtools:request-state-timeline', {})\n return new Promise<StateChange[]>(resolve => {\n let resolved = false\n const resolver = (changes: StateChange[]) => {\n if (!resolved) {\n resolved = true\n clearTimeout(timeout)\n resolve(changes)\n }\n }\n const timeout = setTimeout(() => {\n resolved = true\n const idx = stateTimelineResolvers.indexOf(resolver)\n if (idx !== -1) stateTimelineResolvers.splice(idx, 1)\n resolve(stateTimeline)\n }, 1000)\n stateTimelineResolvers.push(resolver)\n })\n },\n\n 'svelte-devtools:clear-state-timeline': async () => {\n stateTimeline = []\n server?.hot.send('svelte-devtools:clear-state-timeline', {})\n },\n\n 'svelte-devtools:get-api-endpoints': async () => {\n const projectInfo = analyzeProject(root)\n const routes = analyzeRoutes(projectInfo.routesDir)\n const endpoints: ApiEndpoint[] = []\n for (const route of routes) {\n const serverFile = route.files.find(f => f.type === 'endpoint')\n if (serverFile) {\n let content = ''\n try {\n content = fs.readFileSync(serverFile.path, 'utf-8')\n } catch {\n /* file may not exist */\n }\n const methods: string[] = []\n for (const m of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) {\n if (\n content.includes(`export const ${m}`) ||\n content.includes(`export async function ${m}`) ||\n content.includes(`export function ${m}`)\n ) {\n methods.push(m)\n }\n }\n if (methods.length === 0) methods.push('GET')\n endpoints.push({ route: route.id, path: route.path, methods, file: serverFile.path })\n }\n }\n return endpoints\n },\n\n 'svelte-devtools:send-api-request': async (\n requestUrl: string,\n method: string,\n headers: string,\n body: string,\n ) => {\n const start = performance.now()\n try {\n validateExternalUrl(String(requestUrl))\n const parsedHeaders = headers ? JSON.parse(String(headers)) : {}\n const fetchOpts: RequestInit = { method: String(method), headers: parsedHeaders }\n if (body && String(method) !== 'GET' && String(method) !== 'HEAD')\n fetchOpts.body = String(body)\n const res = await fetch(String(requestUrl), fetchOpts)\n const resBody = await res.text()\n const resHeaders: Record<string, string> = {}\n res.headers.forEach((v, k) => {\n resHeaders[k] = v\n })\n return {\n status: res.status,\n statusText: res.statusText,\n headers: resHeaders,\n body: resBody,\n duration: Math.round((performance.now() - start) * 100) / 100,\n } as ApiResponse\n } catch (e) {\n return {\n status: 0,\n statusText: String(e),\n headers: {},\n body: '',\n duration: Math.round((performance.now() - start) * 100) / 100,\n } as ApiResponse\n }\n },\n\n 'svelte-devtools:get-compiler-warnings': async () => compilerWarnings,\n\n 'svelte-devtools:get-runtime-errors': async () => runtimeErrors,\n\n 'svelte-devtools:clear-errors': async () => {\n compilerWarnings = []\n runtimeErrors = []\n },\n\n 'svelte-devtools:get-svelte-files': async () => {\n const components = analyzeComponents(root)\n return components.map(c => ({ file: c.file, name: c.name }))\n },\n\n 'svelte-devtools:inspect-file': async (filePath: string) => {\n const fp = String(filePath)\n let resolved: string\n try {\n resolved = resolveWithinRoot(fp)\n } catch {\n return { source: '', compiled: '', file: fp } as InspectResult\n }\n let source = ''\n try {\n source = fs.readFileSync(resolved, 'utf-8')\n } catch {\n return { source: '', compiled: '', file: fp } as InspectResult\n }\n let compiled = ''\n let mappings: string | undefined\n let sources: string[] | undefined\n if (server) {\n try {\n const result = await server.transformRequest(resolved)\n compiled = result?.code || ''\n if (result?.map) {\n const map = typeof result.map === 'string' ? JSON.parse(result.map) : result.map\n mappings = map.mappings\n sources = map.sources\n }\n } catch {\n compiled = '// Transform failed'\n }\n }\n return { source, compiled, file: fp, mappings, sources } as InspectResult\n },\n\n 'svelte-devtools:get-module-graph': async () => getModuleGraph(),\n\n 'svelte-devtools:get-og-preview': async (url: string) => getOGPreview(String(url)),\n\n 'svelte-devtools:get-build-analysis': async () => getBuildAnalysis(),\n\n 'svelte-devtools:get-fps': async () => fpsSamples,\n\n 'svelte-devtools:clear-fps': async () => {\n fpsSamples = []\n },\n }\n return _rpcHandlers\n }\n\n const mainPlugin: Plugin = {\n name: 'vite-devtools-svelte',\n enforce: 'pre',\n\n // Vite plugins may expose data through `api` for inter-plugin (and test)\n // consumption. We surface the per-process auth token only — never the\n // RPC handlers themselves — so the test suite can attach the token to\n // mock requests without the production code needing a test-only flag.\n api: {\n getDevtoolsToken: () => devtoolsToken,\n },\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n root = config.root\n },\n\n configureServer(devServer) {\n server = devServer\n\n // Defensive caps on runtime-supplied data: even though the runtime\n // already trims its own buffers, an out-of-spec or compromised runtime\n // could hand us unbounded payloads and inflate dev-server memory.\n const MAX_LIVE_COMPONENTS = 5000\n const MAX_RENDER_PROFILES = 5000\n const MAX_STATE_TIMELINE = 500\n const MAX_REACTIVE_NODES = 5000\n const MAX_REACTIVE_EDGES = 20000\n\n server.hot.on('svelte-devtools:components', (data: { components: ComponentInstance[] }) => {\n const arr = Array.isArray(data?.components) ? data.components : []\n liveComponents = arr.length > MAX_LIVE_COMPONENTS ? arr.slice(-MAX_LIVE_COMPONENTS) : arr\n })\n\n server.hot.on('svelte-devtools:profiles', (data: { profiles: RenderProfile[] }) => {\n const arr = Array.isArray(data?.profiles) ? data.profiles : []\n renderProfiles = arr.length > MAX_RENDER_PROFILES ? arr.slice(-MAX_RENDER_PROFILES) : arr\n })\n\n server.hot.on('svelte-devtools:state-timeline', (data: { changes: StateChange[] }) => {\n const arr = Array.isArray(data?.changes) ? data.changes : []\n stateTimeline = arr.length > MAX_STATE_TIMELINE ? arr.slice(-MAX_STATE_TIMELINE) : arr\n // Snapshot then reset before resolving so concurrent requests that\n // push during the resolve loop are not silently dropped.\n const pending = stateTimelineResolvers\n stateTimelineResolvers = []\n for (const resolve of pending) resolve(stateTimeline)\n })\n\n server.hot.on('svelte-devtools:fps', (data: FpsSample) => {\n fpsSamples.push(data)\n if (fpsSamples.length > 1200) fpsSamples = fpsSamples.slice(-1200)\n getSessions().recordFpsSample(data)\n })\n\n server.hot.on('svelte-devtools:runtime-error', (data: RuntimeError) => {\n runtimeErrors.push(data)\n if (runtimeErrors.length > 200) runtimeErrors = runtimeErrors.slice(-200)\n })\n\n server.hot.on('svelte-devtools:reactive-graph', (data: ReactiveGraph) => {\n const nodes = Array.isArray(data?.nodes) ? data.nodes : []\n const edges = Array.isArray(data?.edges) ? data.edges : []\n reactiveGraph = {\n nodes: nodes.length > MAX_REACTIVE_NODES ? nodes.slice(0, MAX_REACTIVE_NODES) : nodes,\n edges: edges.length > MAX_REACTIVE_EDGES ? edges.slice(0, MAX_REACTIVE_EDGES) : edges,\n }\n const pending = reactiveGraphResolvers\n reactiveGraphResolvers = []\n for (const resolve of pending) resolve(reactiveGraph)\n })\n\n // Build the same-origin allow-list once. The dev server only serves\n // its own origin, so any cross-origin request to our endpoints is\n // rejected. This blocks both casual CSRF from arbitrary tabs and the\n // DNS-rebinding scenario where the dev server is bound to 0.0.0.0.\n const buildAllowedOrigins = (): Set<string> => {\n const set = new Set<string>()\n const serverCfg = server?.config?.server ?? config?.server\n const port = serverCfg?.port ?? 5173\n const proto = serverCfg?.https ? 'https' : 'http'\n for (const host of ['localhost', '127.0.0.1', '[::1]']) {\n set.add(`${proto}://${host}`)\n set.add(`${proto}://${host}:${port}`)\n }\n return set\n }\n\n const isAuthorizedRequest = (req: {\n headers: Record<string, string | string[] | undefined>\n }): boolean => {\n const allowed = buildAllowedOrigins()\n const origin = req.headers.origin\n const referer = req.headers.referer\n const sourceOrigin = (() => {\n if (typeof origin === 'string' && origin) return origin\n if (typeof referer === 'string' && referer) {\n try {\n return new URL(referer).origin\n } catch {\n return null\n }\n }\n return null\n })()\n // Same-origin browser requests sent by `fetch` from same-origin pages\n // typically include Origin; tests / curl may omit both — we still\n // require the explicit token header to compensate.\n if (sourceOrigin !== null && !allowed.has(sourceOrigin)) return false\n const tokenHeader = req.headers['x-svelte-devtools-token']\n const token = Array.isArray(tokenHeader) ? tokenHeader[0] : tokenHeader\n return token === devtoolsToken\n }\n\n // Serve the DevTools client UI. Inject the per-process token into\n // index.html as a <meta> tag so the client can attach it to RPC calls.\n const clientDir = path.resolve(__dirname, 'client')\n server.middlewares.use('/.svelte-devtools', (req, res, next) => {\n const reqUrl = req.url || '/'\n const urlPath = reqUrl.split('?')[0]\n const isIndex = urlPath === '/' || urlPath === '' || urlPath === '/index.html'\n const filePath = isIndex\n ? path.join(clientDir, 'index.html')\n : path.join(clientDir, urlPath)\n\n try {\n const stat = fs.statSync(filePath)\n if (stat.isFile()) {\n const ext = path.extname(filePath).toLowerCase()\n res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')\n if (isIndex) {\n const html = fs.readFileSync(filePath, 'utf-8')\n const tokenMeta = `<meta name=\"svelte-devtools-token\" content=\"${devtoolsToken}\">`\n const injected = html.includes('</head>')\n ? html.replace('</head>', ` ${tokenMeta}\\n</head>`)\n : `${tokenMeta}\\n${html}`\n res.end(injected)\n } else {\n fs.createReadStream(filePath).pipe(res)\n }\n return\n }\n } catch {\n /* file doesn't exist, fall through */\n }\n next()\n })\n\n // RPC fallback endpoint for when DevTools Kit RPC is not available.\n // Authorized via same-origin Origin/Referer + per-process token.\n server.middlewares.use('/__svelte-devtools/rpc', (req, res) => {\n if (req.method !== 'POST') {\n res.statusCode = 405\n res.end('Method not allowed')\n return\n }\n if (!isAuthorizedRequest(req as any)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n // Reject content types other than JSON to keep CSRF surface small.\n const ct = req.headers['content-type']\n const ctStr = Array.isArray(ct) ? ct[0] : ct\n if (!ctStr || !ctStr.includes('application/json')) {\n res.statusCode = 415\n res.end('Unsupported Media Type')\n return\n }\n\n let body = ''\n let aborted = false\n const MAX_BODY = 1_000_000 // 1 MB cap to avoid trivial DoS via huge requests\n req.on('data', (chunk: Buffer) => {\n if (aborted) return\n body += chunk.toString()\n if (body.length > MAX_BODY) {\n aborted = true\n res.statusCode = 413\n res.end('Payload Too Large')\n }\n })\n req.on('end', async () => {\n if (aborted) return\n try {\n const { method, args } = JSON.parse(body)\n const handlers = getRpcHandlers()\n const handler = handlers[method]\n if (!handler) throw new Error(`Unknown RPC method: ${method}`)\n const result = await handler(...args)\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(result))\n } catch (e) {\n res.statusCode = 500\n res.end(JSON.stringify({ error: String(e) }))\n }\n })\n })\n\n // Serve asset files for preview. Authorized via same-origin policy.\n server.middlewares.use('/__svelte-devtools/asset', (req, res) => {\n if (!isAuthorizedRequest(req as any)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n const reqUrl = req.url || ''\n const queryStart = reqUrl.indexOf('?')\n const queryString = queryStart >= 0 ? reqUrl.slice(queryStart) : ''\n const params = new URLSearchParams(queryString)\n const filePath = params.get('path')\n if (!filePath) {\n res.statusCode = 400\n res.end('Missing path parameter')\n return\n }\n\n // Security: only serve files from static dir (resolve symlinks to prevent traversal)\n const projectInfo = analyzeProject(root)\n const realStaticDir = fs.realpathSync(projectInfo.staticDir)\n const resolvedPath = path.resolve(filePath)\n let realPath: string\n try {\n realPath = fs.realpathSync(resolvedPath)\n } catch {\n res.statusCode = 404\n res.end('Not found')\n return\n }\n if (!realPath.startsWith(realStaticDir + path.sep) && realPath !== realStaticDir) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n\n try {\n const stat = fs.statSync(realPath)\n if (!stat.isFile()) throw new Error('Not a file')\n const ext = path.extname(realPath).toLowerCase()\n res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')\n fs.createReadStream(realPath).pipe(res)\n } catch {\n res.statusCode = 404\n res.end('Not found')\n }\n })\n\n // MCP endpoint: lets AI agents (Claude Code etc.) read metrics + run\n // measurement sessions over the Streamable HTTP transport. Auth reuses\n // the same per-process token; same-origin is *not* required because MCP\n // clients are local processes that don't run inside a browser tab and\n // can't be redirected by a hostile origin (they only speak to URLs the\n // user explicitly configured via `claude mcp add`).\n const mcpServerFactory = () =>\n buildMcpServer({\n getProject: () => analyzeProject(root),\n getRoutes: () => {\n const projectInfo = analyzeProject(root)\n return analyzeRoutes(projectInfo.routesDir)\n },\n getLiveComponents: () => liveComponents,\n getComponentRelations: () => analyzeComponents(root),\n getRenderProfiles: () => renderProfiles,\n getReactiveGraph: () => getRpcHandlers()['svelte-devtools:get-reactive-graph']() as Promise<ReactiveGraph>,\n getLoadProfiles: () => loadProfiles,\n getFpsSamples: () => fpsSamples,\n sessions: getSessions(),\n })\n\n // Print a one-line `claude mcp add` snippet once the dev server is\n // actually listening — that's when we know the resolved port.\n devServer.httpServer?.once('listening', () => {\n try {\n const addr = devServer.httpServer?.address()\n if (!addr || typeof addr === 'string') return\n const proto = devServer.config.server?.https ? 'https' : 'http'\n // For wildcard / loopback bindings prefer the literal `localhost`\n // so the printed URL parses as-is. Brackets aren't enough for `::`\n // (wildcard) and `::1` is just a more verbose form of loopback.\n const loopbackOrWildcard =\n addr.address === '::' ||\n addr.address === '0.0.0.0' ||\n addr.address === '::1' ||\n addr.address === '127.0.0.1'\n const host = loopbackOrWildcard\n ? 'localhost'\n : addr.family === 'IPv6'\n ? `[${addr.address}]`\n : addr.address\n const url = `${proto}://${host}:${addr.port}/__svelte-devtools/mcp`\n const cmd = `claude mcp add --transport http svelte ${url} --header x-svelte-devtools-token:${devtoolsToken}`\n devServer.config.logger.info('')\n devServer.config.logger.info(` svelte-devtools MCP ready — register with Claude Code:`)\n devServer.config.logger.info(` ${cmd}`)\n devServer.config.logger.info('')\n } catch {\n /* logging is best-effort */\n }\n })\n\n server.middlewares.use('/__svelte-devtools/mcp', async (req, res) => {\n const tokenHeader = req.headers['x-svelte-devtools-token']\n const token = Array.isArray(tokenHeader) ? tokenHeader[0] : tokenHeader\n if (token !== devtoolsToken) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n // Build a fresh server+transport per request. Stateless mode in the\n // SDK still keeps per-instance bookkeeping that gets corrupted when\n // the same transport handles multiple requests, so reusing one\n // breaks the second call onward.\n const mcpServer = mcpServerFactory()\n const mcpTransport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: true,\n })\n mcpTransport.onerror = err => {\n devServer.config.logger.error(\n `[svelte-devtools] MCP transport error: ${err.stack || err.message}`,\n )\n }\n try {\n await mcpServer.connect(mcpTransport)\n // The SDK consumes the request body via @hono/node-server inside\n // handleRequest; pre-reading would leave the stream empty.\n await mcpTransport.handleRequest(req as any, res as any)\n } catch (e) {\n devServer.config.logger.error(\n `[svelte-devtools] MCP handler error: ${\n e instanceof Error ? e.stack || e.message : String(e)\n }`,\n )\n if (!res.headersSent) {\n res.statusCode = 500\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ error: String(e) }))\n }\n } finally {\n await mcpTransport.close().catch(() => {})\n await mcpServer.close().catch(() => {})\n }\n })\n },\n\n // Virtual module resolution: runtime + svelte/internal/client wrapper.\n // dev only — never resolve our virtual modules during production build.\n resolveId(id, importer) {\n if (config?.command !== 'serve') return undefined\n if (id === RUNTIME_MODULE_ID) return RESOLVED_RUNTIME_ID\n if (\n componentTracking &&\n id === 'svelte/internal/client' &&\n importer &&\n !importer.includes('node_modules') &&\n !importer.startsWith('\\0')\n ) {\n return WRAPPER_MODULE_ID\n }\n return undefined\n },\n\n load(id) {\n if (config?.command !== 'serve') return undefined\n if (id === RESOLVED_RUNTIME_ID) return runtimeCode\n if (id === WRAPPER_MODULE_ID) return wrapperCode\n return undefined\n },\n\n // Inject the runtime into the user's app\n transformIndexHtml() {\n if (config.command !== 'serve') return []\n return [\n {\n tag: 'script',\n attrs: { type: 'module' },\n children: `import '${RUNTIME_MODULE_ID}'`,\n injectTo: 'head-prepend',\n },\n ]\n },\n\n // DevTools integration\n devtools: {\n setup(ctx) {\n const clientDir = path.resolve(__dirname, 'client')\n ctx.views.hostStatic('/.svelte-devtools/', clientDir)\n\n ctx.docks.register({\n id: 'svelte-devtools',\n title: 'Svelte',\n icon: 'simple-icons:svelte',\n type: 'iframe',\n url: '/.svelte-devtools/',\n category: 'framework',\n })\n\n // Register all RPC functions from shared handlers\n const handlers = getRpcHandlers()\n for (const [name, handler] of Object.entries(handlers)) {\n ctx.rpc.register({ name, handler })\n }\n },\n },\n }\n\n // --- Phase 4 helper functions ---\n\n function getModuleGraph(): ModuleGraphData {\n if (!server) return { modules: [], cycles: [] }\n const modules: ModuleNode[] = []\n const idMap = new Map<string, ModuleNode>()\n const moduleById = new Map<string, ModuleNode>()\n\n // Try different Vite moduleGraph APIs (v8 uses environments)\n const allModules: Array<{ file?: string | null; importedModules: Set<any> }> = []\n try {\n // Vite 8: use environments\n for (const env of Object.values(server.environments || {})) {\n if (env && 'moduleGraph' in env) {\n const mg = (env as any).moduleGraph\n if (mg?.idToModuleMap) {\n for (const mod of mg.idToModuleMap.values()) allModules.push(mod)\n }\n }\n }\n } catch {\n /* ignore */\n }\n\n // Fallback: try legacy moduleGraph\n if (allModules.length === 0) {\n try {\n const mg = (server as any).moduleGraph\n if (mg?.idToModuleMap) {\n for (const mod of mg.idToModuleMap.values()) allModules.push(mod)\n }\n } catch {\n /* ignore */\n }\n }\n\n for (const mod of allModules) {\n if (!mod.file || mod.file.includes('node_modules')) continue\n const relFile = path.relative(root, mod.file)\n if (relFile.startsWith('..')) continue\n if (idMap.has(mod.file)) continue // deduplicate\n const ext = path.extname(mod.file).toLowerCase()\n const type =\n ext === '.svelte'\n ? 'svelte'\n : ext === '.ts' || ext === '.js'\n ? ext === '.ts'\n ? 'ts'\n : 'js'\n : ext === '.css'\n ? 'css'\n : 'other'\n let size: number | undefined\n try {\n size = fs.statSync(mod.file).size\n } catch {\n /* ignore */\n }\n const node: ModuleNode = {\n id: relFile,\n file: mod.file,\n type: type as ModuleNode['type'],\n importedBy: [],\n imports: [],\n size,\n }\n idMap.set(mod.file, node)\n moduleById.set(relFile, node)\n modules.push(node)\n }\n\n // Build edges using Sets for O(1) dedup\n for (const mod of allModules) {\n if (!mod.file || !idMap.has(mod.file)) continue\n const node = idMap.get(mod.file)!\n const importsSet = new Set(node.imports)\n for (const imp of mod.importedModules) {\n if (imp.file && idMap.has(imp.file)) {\n const impNode = idMap.get(imp.file)!\n const relImp = impNode.id\n if (!importsSet.has(relImp)) {\n importsSet.add(relImp)\n node.imports.push(relImp)\n }\n if (!impNode.importedBy.includes(node.id)) {\n impNode.importedBy.push(node.id)\n }\n }\n }\n }\n\n // Detect cycles (DFS) using Map for O(1) node lookup, push/pop to avoid array copies\n const cycles: string[][] = []\n const visited = new Set<string>()\n const stack = new Set<string>()\n const pathBuf: string[] = []\n function dfs(id: string) {\n if (stack.has(id)) {\n const cycleStart = pathBuf.indexOf(id)\n if (cycleStart >= 0 && pathBuf.length - cycleStart > 0) {\n const cycle = pathBuf.slice(cycleStart).concat(id)\n if (cycle.length > 2) cycles.push(cycle) // skip self-references\n }\n return\n }\n if (visited.has(id)) return\n visited.add(id)\n stack.add(id)\n pathBuf.push(id)\n const node = moduleById.get(id)\n if (node) for (const imp of node.imports) dfs(imp)\n pathBuf.pop()\n stack.delete(id)\n }\n for (const m of modules) dfs(m.id)\n\n // Mark cyclic modules\n const cyclicIds = new Set(cycles.flat())\n for (const m of modules) if (cyclicIds.has(m.id)) m.isCyclic = true\n\n return { modules, cycles }\n }\n\n async function getOGPreview(url: string): Promise<OGPreview> {\n const preview: OGPreview = { url, title: '', description: '', image: '', tags: [], issues: [] }\n try {\n validateExternalUrl(url)\n const res = await fetch(url)\n const html = await res.text()\n // Parse meta tags (attribute-order independent; matches both <meta ...> and <meta ... />)\n const metaRegex = /<meta\\s+([^>]*?)\\/?>/gi\n const propRegex = /(?:property|name)=[\"']([^\"']+)[\"']/\n const contentRegex = /content=[\"']([^\"']+)[\"']/\n let match\n while ((match = metaRegex.exec(html)) !== null) {\n const attrs = match[1]\n const propMatch = attrs.match(propRegex)\n const contentMatch = attrs.match(contentRegex)\n if (propMatch && contentMatch) {\n const prop = propMatch[1]\n const content = contentMatch[1]\n preview.tags.push({ property: prop, content })\n if (prop === 'og:title') preview.title = content\n else if (prop === 'og:description') preview.description = content\n else if (prop === 'og:image') preview.image = content\n }\n }\n // Fallback title\n if (!preview.title) {\n const titleMatch = html.match(/<title>([^<]+)<\\/title>/i)\n if (titleMatch) preview.title = titleMatch[1]\n }\n // Fallback description\n if (!preview.description) {\n const descTag = preview.tags.find(t => t.property === 'description')\n if (descTag) preview.description = descTag.content\n }\n // Issues\n if (!preview.title) preview.issues.push('Missing og:title or <title>')\n if (!preview.description) preview.issues.push('Missing og:description or meta description')\n if (!preview.image) preview.issues.push('Missing og:image')\n if (!preview.tags.some(t => t.property === 'og:url')) preview.issues.push('Missing og:url')\n if (!preview.tags.some(t => t.property === 'og:type')) preview.issues.push('Missing og:type')\n } catch (e) {\n preview.issues.push(`Failed to fetch: ${String(e)}`)\n }\n return preview\n }\n\n function getBuildAnalysis(): BuildAnalysis {\n const buildDir = path.resolve(root, '.svelte-kit/output')\n const clientDir = path.resolve(root, 'build/client') // common SvelteKit build output\n const chunks: BuildChunk[] = []\n\n // Try to find built assets\n for (const dir of [buildDir, clientDir, path.resolve(root, 'build')]) {\n try {\n const walkDir = (d: string) => {\n for (const entry of fs.readdirSync(d, { withFileTypes: true })) {\n const full = path.join(d, entry.name)\n if (entry.isDirectory()) {\n walkDir(full)\n continue\n }\n const ext = path.extname(entry.name).toLowerCase()\n if (['.js', '.css', '.html'].includes(ext)) {\n const stat = fs.statSync(full)\n chunks.push({\n name: entry.name,\n file: path.relative(root, full),\n size: stat.size,\n modules: [],\n isEntry: entry.name.includes('index') || entry.name.includes('start'),\n })\n }\n }\n }\n walkDir(dir)\n } catch {\n /* directory doesn't exist or not readable */\n }\n }\n\n chunks.sort((a, b) => b.size - a.size)\n return { chunks, totalSize: chunks.reduce((s, c) => s + c.size, 0), timestamp: Date.now() }\n }\n\n // Minimal component tracking transform plugin.\n // Only injects the file path before $.push() so the runtime wrapper knows\n // which component file is being initialized. All reactive tracking (state,\n // derived, proxy, effect) is handled by the svelte/internal/client wrapper.\n const trackingPlugin: Plugin = {\n name: 'vite-devtools-svelte:tracking',\n enforce: 'post',\n\n transform(code, id) {\n if (!componentTracking) return null\n if (!id.endsWith('.svelte')) return null\n if (id.includes('node_modules')) return null\n if (config?.command !== 'serve') return null\n if (!code.includes('$.push(')) return null\n\n const safeId = JSON.stringify(id)\n\n const importLine = `import '${RUNTIME_MODULE_ID}';\\n`\n\n const modified =\n importLine +\n code.replace(\n /(\\$\\.push\\([^)]+\\);?)/,\n `if (typeof window !== 'undefined' && window.__SVELTE_DEVTOOLS__) { window.__SVELTE_DEVTOOLS__._pendingFile = ${safeId}; }\\n$1`,\n )\n\n return { code: modified, map: null }\n },\n }\n\n // Load function profiling transform plugin\n const loadProfilePlugin: Plugin = {\n name: 'vite-devtools-svelte:load-profile',\n enforce: 'post',\n\n transform(code, id) {\n if (config?.command !== 'serve') return null\n // Only transform SvelteKit load files\n const isServerLoad = /\\+page\\.server\\.[tj]s$/.test(id) || /\\+layout\\.server\\.[tj]s$/.test(id)\n const isUniversalLoad = /\\+(page|layout)\\.[tj]s$/.test(id) && !id.includes('.server.')\n if (!isServerLoad && !isUniversalLoad) return null\n if (id.includes('node_modules')) return null\n // Must have an exported load function\n if (!code.includes('export') || !code.includes('load')) return null\n\n const loadType = isServerLoad ? 'server' : 'universal'\n // Determine route from file path\n const routesMatch = id.match(/routes(.*)\\/\\+/)\n const route = routesMatch ? routesMatch[1] || '/' : '/'\n const safeRoute = JSON.stringify(route)\n const safeFile = JSON.stringify(id)\n const safeType = JSON.stringify(loadType)\n\n // Replace the exported load function with a profiled version.\n // Supports both `export const load = ...` and `export (async) function load(...)` patterns.\n let transformed = code.replace(/export\\s+const\\s+load\\s*=\\s*/, `const __original_load = `)\n\n if (transformed === code) {\n // Try `export function load` / `export async function load` pattern\n transformed = code.replace(\n /export\\s+(async\\s+)?function\\s+load\\s*\\(/,\n `const __original_load = $1function __load_impl(`,\n )\n }\n\n if (transformed === code) return null // no match found\n\n const profiledExport = `\nexport const load = async (event) => {\n const __start = performance.now();\n const __result = await __original_load(event);\n const __duration = performance.now() - __start;\n const __dataSize = JSON.stringify(__result || {}).length;\n if (typeof globalThis.__svelte_devtools_record_load === 'function') {\n globalThis.__svelte_devtools_record_load(${safeRoute}, ${safeFile}, ${safeType}, __duration, __dataSize);\n }\n return __result;\n};\n`\n return { code: transformed + profiledExport, map: null }\n },\n }\n\n // Register load profiling hook on server\n const loadProfileServerPlugin: Plugin = {\n name: 'vite-devtools-svelte:load-profile-server',\n\n configureServer() {\n // Make the recording function available globally on the server\n ;(globalThis as Record<string, unknown>).__svelte_devtools_record_load = (\n route: string,\n file: string,\n type: string,\n duration: number,\n dataSize: number,\n ) => {\n const entry: LoadProfile = {\n route,\n file,\n type: type as 'server' | 'universal',\n duration: Math.round(duration * 100) / 100,\n dataSize,\n timestamp: Date.now(),\n }\n loadProfiles.push(entry)\n // Keep only last 200 entries\n if (loadProfiles.length > 200) {\n loadProfiles = loadProfiles.slice(-200)\n }\n getSessions().recordLoadProfile(entry)\n }\n },\n }\n\n // Compiler warning capture plugin\n const warningCapturePlugin: Plugin = {\n name: 'vite-devtools-svelte:warning-capture',\n enforce: 'post',\n\n configResolved(resolvedConfig) {\n // Intercept Svelte compiler warnings from the logger\n const originalWarn = resolvedConfig.logger.warn\n resolvedConfig.logger.warn = (msg: string, options?: { timestamp?: boolean }) => {\n // Svelte compiler warnings usually contain file paths and codes\n if (msg.includes('.svelte') && config?.command === 'serve') {\n const fileMatch = msg.match(/(?:^|\\s)((?:\\/|\\.\\/|\\w:)[^\\s:]+\\.svelte)(?::(\\d+):(\\d+))?/)\n const codeMatch = msg.match(/\\(([a-z0-9_-]+)\\)/)\n compilerWarnings.push({\n code: codeMatch?.[1] || 'unknown',\n // oxlint-disable-next-line no-control-regex -- intentional: strip ANSI escape sequences\n message: msg.replace(/\\x1b\\[[0-9;]*m/g, '').trim(),\n file: fileMatch?.[1] || '',\n line: fileMatch?.[2] ? parseInt(fileMatch[2]) : undefined,\n column: fileMatch?.[3] ? parseInt(fileMatch[3]) : undefined,\n })\n if (compilerWarnings.length > 500) compilerWarnings = compilerWarnings.slice(-500)\n }\n originalWarn(msg, options)\n }\n },\n }\n\n return [\n mainPlugin,\n trackingPlugin,\n loadProfilePlugin,\n loadProfileServerPlugin,\n warningCapturePlugin,\n sveltekitTemplateInjector(),\n ]\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/analyzers/routes.ts","../src/analyzers/assets.ts","../src/analyzers/project.ts","../src/analyzers/components.ts","../src/runtime.ts","../src/mcp/sessions.ts","../src/mcp/issues.ts","../src/mcp/server.ts","../src/template-injector.ts","../src/plugin.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport type { RouteInfo, ParamInfo, RouteFile } from '../types.js'\n\nexport function analyzeRoutes(routesDir: string): RouteInfo[] {\n if (!fs.existsSync(routesDir)) return []\n\n const routes: RouteInfo[] = []\n scanDirectory(routesDir, routesDir, routes)\n return routes.sort((a, b) => a.path.localeCompare(b.path))\n}\n\nfunction scanDirectory(dir: string, rootDir: string, routes: RouteInfo[]): void {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n const files: RouteFile[] = []\n let hasRouteFiles = false\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n scanDirectory(path.join(dir, entry.name), rootDir, routes)\n continue\n }\n\n const routeFile = classifyFile(entry.name, path.join(dir, entry.name))\n if (routeFile) {\n files.push(routeFile)\n hasRouteFiles = true\n }\n }\n\n if (hasRouteFiles) {\n const relativePath = path.relative(rootDir, dir)\n const routePath = buildRoutePath(relativePath)\n const params = extractParams(relativePath)\n\n routes.push({\n id: relativePath || '/',\n path: routePath,\n pattern: routePath,\n segments: routePath.split('/').filter(Boolean),\n hasPage: files.some(f => f.type === 'page'),\n hasLayout: files.some(f => f.type === 'layout'),\n hasServerPage: files.some(f => f.type === 'page-load-server'),\n hasServerLayout: files.some(f => f.type === 'layout-load-server'),\n hasEndpoint: files.some(f => f.type === 'endpoint'),\n hasPageLoad: files.some(f => f.type === 'page-load'),\n hasLayoutLoad: files.some(f => f.type === 'layout-load'),\n params,\n files,\n })\n }\n}\n\nfunction classifyFile(name: string, fullPath: string): RouteFile | null {\n const map: Record<string, RouteFile['type']> = {\n '+page.svelte': 'page',\n '+layout.svelte': 'layout',\n '+page.server.ts': 'page-load-server',\n '+page.server.js': 'page-load-server',\n '+layout.server.ts': 'layout-load-server',\n '+layout.server.js': 'layout-load-server',\n '+page.ts': 'page-load',\n '+page.js': 'page-load',\n '+layout.ts': 'layout-load',\n '+layout.js': 'layout-load',\n '+server.ts': 'endpoint',\n '+server.js': 'endpoint',\n '+error.svelte': 'error',\n }\n\n const type = map[name]\n if (!type) return null\n return { type, path: fullPath }\n}\n\nfunction buildRoutePath(relativePath: string): string {\n if (!relativePath) return '/'\n\n const parts = relativePath.split(path.sep)\n const pathParts = parts.map(part => {\n // SvelteKit group syntax: (group) -> ignored in URL\n if (part.startsWith('(') && part.endsWith(')')) return null\n\n // Dynamic params: [param] -> :param\n if (part.startsWith('[') && part.endsWith(']')) {\n const inner = part.slice(1, -1)\n if (inner.startsWith('...')) return `*${inner.slice(3)}`\n if (inner.startsWith('[') && inner.endsWith(']')) return `:${inner.slice(1, -1)}?`\n return `:${inner}`\n }\n\n return part\n })\n\n return '/' + pathParts.filter(Boolean).join('/')\n}\n\nfunction extractParams(relativePath: string): ParamInfo[] {\n if (!relativePath) return []\n\n const params: ParamInfo[] = []\n const parts = relativePath.split(path.sep)\n\n for (const part of parts) {\n if (!part.startsWith('[') || !part.endsWith(']')) continue\n\n const inner = part.slice(1, -1)\n\n if (inner.startsWith('...')) {\n params.push({ name: inner.slice(3), optional: false, rest: true })\n } else if (inner.startsWith('[') && inner.endsWith(']')) {\n params.push({ name: inner.slice(1, -1), optional: true, rest: false })\n } else {\n const matcherSplit = inner.split('=')\n params.push({\n name: matcherSplit[0],\n optional: false,\n rest: false,\n matcher: matcherSplit[1],\n })\n }\n }\n\n return params\n}\n","import fs from 'fs'\nimport path from 'path'\nimport type { AssetInfo } from '../types.js'\n\nexport const MIME_TYPES: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject',\n '.otf': 'font/otf',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.json': 'application/json',\n '.xml': 'application/xml',\n '.pdf': 'application/pdf',\n '.txt': 'text/plain',\n '.css': 'text/css',\n '.js': 'text/javascript',\n '.html': 'text/html',\n}\n\nexport function analyzeAssets(staticDir: string): AssetInfo[] {\n if (!fs.existsSync(staticDir)) return []\n\n const assets: AssetInfo[] = []\n scanDir(staticDir, staticDir, assets)\n return assets.sort((a, b) => a.relativePath.localeCompare(b.relativePath))\n}\n\nfunction scanDir(dir: string, rootDir: string, assets: AssetInfo[]): void {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n scanDir(fullPath, rootDir, assets)\n continue\n }\n\n // Skip hidden files\n if (entry.name.startsWith('.')) continue\n\n const stat = fs.statSync(fullPath)\n const ext = path.extname(entry.name).toLowerCase()\n\n assets.push({\n name: entry.name,\n path: fullPath,\n relativePath: path.relative(rootDir, fullPath),\n size: stat.size,\n type: MIME_TYPES[ext] || 'application/octet-stream',\n mtime: stat.mtimeMs,\n })\n }\n}\n","import fs from 'fs'\nimport path from 'path'\nimport type { ProjectInfo } from '../types.js'\n\nconst CACHE_TTL_MS = 5000\nlet _cachedResult: ProjectInfo | null = null\nlet _cachedRoot: string | null = null\nlet _cachedAt = 0\n\nexport function analyzeProject(root: string): ProjectInfo {\n const now = Date.now()\n if (_cachedResult && _cachedRoot === root && now - _cachedAt < CACHE_TTL_MS) {\n return _cachedResult\n }\n const result = _analyzeProjectUncached(root)\n _cachedResult = result\n _cachedRoot = root\n _cachedAt = now\n return result\n}\n\nfunction _analyzeProjectUncached(root: string): ProjectInfo {\n const pkgPath = path.join(root, 'package.json')\n const pkg = fs.existsSync(pkgPath) ? JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) : {}\n\n const deps = pkg.dependencies || {}\n const devDeps = pkg.devDependencies || {}\n\n return {\n name: pkg.name || path.basename(root),\n version: pkg.version || '0.0.0',\n svelteVersion:\n getInstalledVersion(root, 'svelte') || deps.svelte || devDeps.svelte || 'unknown',\n sveltekitVersion:\n getInstalledVersion(root, '@sveltejs/kit') ||\n deps['@sveltejs/kit'] ||\n devDeps['@sveltejs/kit'] ||\n 'unknown',\n viteVersion: getInstalledVersion(root, 'vite') || deps.vite || devDeps.vite || 'unknown',\n dependencies: deps,\n devDependencies: devDeps,\n routesDir: findRoutesDir(root),\n staticDir: findStaticDir(root),\n }\n}\n\nfunction getInstalledVersion(root: string, pkg: string): string | null {\n try {\n const pkgJsonPath = path.join(root, 'node_modules', pkg, 'package.json')\n if (fs.existsSync(pkgJsonPath)) {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))\n return pkgJson.version\n }\n } catch {\n // ignore\n }\n return null\n}\n\nfunction findRoutesDir(root: string): string {\n const candidates = [path.join(root, 'src', 'routes'), path.join(root, 'src', 'pages')]\n for (const dir of candidates) {\n if (fs.existsSync(dir)) return dir\n }\n return path.join(root, 'src', 'routes')\n}\n\nfunction findStaticDir(root: string): string {\n const candidates = [path.join(root, 'static'), path.join(root, 'public')]\n for (const dir of candidates) {\n if (fs.existsSync(dir)) return dir\n }\n return path.join(root, 'static')\n}\n","import fs from 'fs'\nimport path from 'path'\nimport type { ComponentRelation } from '../types.js'\n\nexport function analyzeComponents(root: string): ComponentRelation[] {\n const srcDir = path.join(root, 'src')\n if (!fs.existsSync(srcDir)) return []\n\n const svelteFiles: string[] = []\n findSvelteFiles(srcDir, svelteFiles)\n\n return svelteFiles.map(file => {\n const content = fs.readFileSync(file, 'utf-8')\n const imports = extractSvelteImports(content, file)\n const name = getComponentName(file)\n\n return {\n file: path.relative(root, file),\n name,\n imports: imports.map(i => path.relative(root, i)),\n }\n })\n}\n\nfunction findSvelteFiles(dir: string, files: string[]): void {\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === '.svelte-kit') continue\n findSvelteFiles(fullPath, files)\n } else if (entry.name.endsWith('.svelte')) {\n files.push(fullPath)\n }\n }\n}\n\nfunction extractSvelteImports(content: string, filePath: string): string[] {\n const imports: string[] = []\n const dir = path.dirname(filePath)\n\n // Match: import X from './Component.svelte'\n // Match: import X from '$lib/Component.svelte'\n const importRegex = /import\\s+[\\w{}\\s,*]+\\s+from\\s+['\"]([^'\"]+\\.svelte)['\"]/g\n let match: RegExpExecArray | null\n\n while ((match = importRegex.exec(content)) !== null) {\n const importPath = match[1]\n const resolved = resolveImportPath(importPath, dir, filePath)\n if (resolved) imports.push(resolved)\n }\n\n return imports\n}\n\nfunction resolveImportPath(importPath: string, dir: string, fromFile: string): string | null {\n // Handle $lib alias\n if (importPath.startsWith('$lib/')) {\n const root = findProjectRoot(fromFile)\n if (root) {\n const libPath = path.join(root, 'src', 'lib', importPath.slice(5))\n if (fs.existsSync(libPath)) return libPath\n }\n return null\n }\n\n // Relative import\n if (importPath.startsWith('.')) {\n const resolved = path.resolve(dir, importPath)\n if (fs.existsSync(resolved)) return resolved\n }\n\n return null\n}\n\nfunction findProjectRoot(filePath: string): string | null {\n let dir = path.dirname(filePath)\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, 'package.json'))) return dir\n dir = path.dirname(dir)\n }\n return null\n}\n\nfunction getComponentName(filePath: string): string {\n return path.basename(filePath, '.svelte')\n}\n","// This code is injected into the user's app as a virtual module.\n// It tracks Svelte component mount/unmount and sends data to the Vite server via HMR.\nexport const RUNTIME_MODULE_ID = 'virtual:svelte-devtools-runtime'\nexport const RESOLVED_RUNTIME_ID = '\\0' + RUNTIME_MODULE_ID\n\n// Virtual module ID for the svelte/internal/client wrapper.\n// When user code imports 'svelte/internal/client', it is redirected to this module.\n// The wrapper re-exports everything and overrides key functions for devtools tracking.\nexport const WRAPPER_MODULE_ID = '\\0svelte-devtools:wrapped-client'\n\n/**\n * Wrapper code for svelte/internal/client.\n *\n * Re-exports everything from the real module, then overrides:\n * - push/pop: component lifecycle tracking\n * - tag/tag_proxy: named signal/proxy tracking (Svelte dev mode)\n * - state/derived/proxy: type markers consumed by tag/tag_proxy\n * - user_effect/user_pre_effect: effect tracking\n * - template_effect/deferred_template_effect: render count/time profiling\n * - each/if/key/await/component/boundary: block-callback owner attribution\n *\n * This single module replaces all post-compilation regex transforms\n * for reactive tracking, making the approach Svelte-compiler-output agnostic.\n */\nexport const wrapperCode = /* js */ `\nimport * as __svelte_original from 'svelte/internal/client';\nexport * from 'svelte/internal/client';\n\nfunction __dt() {\n return typeof window !== 'undefined' ? window.__SVELTE_DEVTOOLS__ : null;\n}\n\n// Component ID stack (parallel to runtime._stack but local to wrapper)\nconst __idStack = [];\nfunction __currentId() {\n return __idStack.length > 0 ? __idStack[__idStack.length - 1] : null;\n}\n\n// Tracks the most recently created signal for type determination in tag()\nconst __pendingSignal = { ref: null, type: null };\n\n// --- Component Lifecycle ---\n//\n// Observer must not break the observed: every devtools side-effect below is\n// wrapped in try/catch so a bug or an out-of-shape runtime cannot tear down\n// the user's app. The original Svelte function is always called, and its\n// return value always returned, regardless of devtools failures.\n\nexport function push() {\n const result = __svelte_original.push.apply(null, arguments);\n try {\n const dt = __dt();\n if (dt) {\n const file = dt._pendingFile || 'Unknown';\n dt._pendingFile = null;\n const id = dt.register(file);\n __idStack.push(id);\n dt.startInit(id);\n try {\n __svelte_original.user_effect(() => {\n return () => { try { dt.unmount(id); } catch {} };\n });\n } catch {}\n }\n } catch {}\n return result;\n}\n\nexport function pop() {\n // Capture devtools errors but ALWAYS forward to the original pop so the\n // Svelte component stack stays balanced.\n try {\n const dt = __dt();\n if (dt && __idStack.length > 0) {\n const id = __idStack.pop();\n try { dt.endInit(id); } catch {}\n try { dt.registered(id); } catch {}\n }\n } catch {}\n return __svelte_original.pop.apply(null, arguments);\n}\n\n// --- Signal Creation (type markers) ---\n\nexport function state() {\n const signal = __svelte_original.state.apply(null, arguments);\n try {\n __pendingSignal.ref = signal;\n __pendingSignal.type = 'state';\n } catch {}\n return signal;\n}\n\nexport function derived() {\n const signal = __svelte_original.derived.apply(null, arguments);\n try {\n __pendingSignal.ref = signal;\n __pendingSignal.type = 'derived';\n } catch {}\n return signal;\n}\n\nexport function proxy() {\n const p = __svelte_original.proxy.apply(null, arguments);\n try {\n __pendingSignal.ref = p;\n __pendingSignal.type = 'proxy';\n } catch {}\n return p;\n}\n\n// --- Signal Tagging (Svelte dev mode) ---\n\nexport function tag(signal, name) {\n const result = __svelte_original.tag.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n const type = (__pendingSignal.ref === signal) ? __pendingSignal.type : 'state';\n if (type === 'derived') {\n dt.trackDerived(signal, name, cid);\n } else {\n dt.trackState(signal, name, cid);\n }\n }\n __pendingSignal.ref = null;\n __pendingSignal.type = null;\n } catch {}\n return result;\n}\n\nexport function tag_proxy(proxy, name) {\n const result = __svelte_original.tag_proxy.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt.trackProxy(proxy, name, cid);\n }\n __pendingSignal.ref = null;\n __pendingSignal.type = null;\n } catch {}\n return result;\n}\n\n// --- Effect Tracking ---\n\nexport function user_effect() {\n const result = __svelte_original.user_effect.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt._effectCounter = (dt._effectCounter || 0) + 1;\n // Track the effect OBJECT (not the callback). The Svelte runtime\n // populates result.deps with the signals this effect depends on,\n // which is what getReactiveGraph() reads to build edges.\n dt.trackEffect(result, 'effect_' + dt._effectCounter, cid);\n }\n } catch {}\n return result;\n}\n\nexport function user_pre_effect() {\n const result = __svelte_original.user_pre_effect.apply(null, arguments);\n try {\n const dt = __dt();\n const cid = __currentId();\n if (dt && cid !== null) {\n dt._effectCounter = (dt._effectCounter || 0) + 1;\n dt.trackEffect(result, 'effect_pre_' + dt._effectCounter, cid);\n }\n } catch {}\n return result;\n}\n\n// --- Render Profiling ---\n//\n// Svelte 5 has no virtual DOM: the compiler wraps every dynamic part of a\n// template in a template_effect (deferred_template_effect for <svelte:head>\n// <title>). A re-run of such an effect IS the component updating the DOM, so\n// these two functions are the measurement points for renders / render time.\n//\n// The first run of an effect is the mount-time paint, already covered by\n// initTime, so it is skipped (initialRun). One state change re-runs several\n// effects of the same component, so durations are pooled per microtask and\n// recorded once per flush: recordRender() +1, recordRenderTime() the sum.\n\nconst __pendingRenderDurations = new Map();\nlet __renderFlushScheduled = false;\n\nfunction __flushRenderDurations() {\n __renderFlushScheduled = false;\n const dt = __dt();\n for (const [cid, duration] of __pendingRenderDurations) {\n if (dt) {\n try { dt.recordRender(cid); } catch {}\n try { dt.recordRenderTime(cid, duration); } catch {}\n }\n }\n __pendingRenderDurations.clear();\n}\n\nfunction __recordRenderDuration(cid, duration) {\n __pendingRenderDurations.set(cid, (__pendingRenderDurations.get(cid) || 0) + duration);\n if (!__renderFlushScheduled) {\n __renderFlushScheduled = true;\n queueMicrotask(__flushRenderDurations);\n }\n}\n\n// Returns a (possibly new) args array whose first element times each re-run\n// of the effect closure. The owning component is whatever id is on top of\n// __idStack at effect-creation time. User exceptions propagate untouched;\n// only the args are built inside try so the original is called exactly once.\nfunction __wrapTemplateEffect(args) {\n const cid = __currentId();\n const fn = args[0];\n if (cid === null || typeof fn !== 'function') return args;\n const wrapped = Array.prototype.slice.call(args);\n let initialRun = true;\n wrapped[0] = function () {\n if (initialRun) {\n initialRun = false;\n return fn.apply(this, arguments);\n }\n const start = performance.now();\n try {\n return fn.apply(this, arguments);\n } finally {\n try { __recordRenderDuration(cid, performance.now() - start); } catch {}\n }\n };\n return wrapped;\n}\n\nexport function template_effect() {\n let args = arguments;\n try { args = __wrapTemplateEffect(arguments); } catch {}\n return __svelte_original.template_effect.apply(null, args);\n}\n\nexport function deferred_template_effect() {\n let args = arguments;\n try { args = __wrapTemplateEffect(arguments); } catch {}\n return __svelte_original.deferred_template_effect.apply(null, args);\n}\n\n// --- Block Attribution ---\n//\n// Svelte creates render effects synchronously at creation time. At mount this\n// happens during the component function (between push/pop), so __idStack has\n// the owner. But effects for {#each} items added later or re-created {#if}\n// branches are created during a batch flush, when the stack is empty — they\n// would never be attributed. Block helpers themselves ARE always called\n// during their owner's init (or inside an outer block's callback), so the\n// owner id is on the stack at block-creation time. __wrapBlock captures it\n// and re-pushes it around every function argument the block invokes later,\n// so effects created inside land on the innermost owner. Child components\n// push their own id on top, keeping nested attribution correct.\n\nfunction __wrapBlockFn(fn, cid) {\n return function () {\n let pushed = false;\n try { __idStack.push(cid); pushed = true; } catch {}\n try {\n return fn.apply(this, arguments);\n } finally {\n if (pushed) { try { __idStack.pop(); } catch {} }\n }\n };\n}\n\nfunction __wrapBlock(args) {\n const cid = __currentId();\n if (cid === null) return args;\n const wrapped = Array.prototype.slice.call(args);\n for (let i = 0; i < wrapped.length; i++) {\n if (typeof wrapped[i] === 'function') wrapped[i] = __wrapBlockFn(wrapped[i], cid);\n }\n return wrapped;\n}\n\nexport function each() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original.each.apply(null, args);\n}\n\nexport function key() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original.key.apply(null, args);\n}\n\nexport function component() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original.component.apply(null, args);\n}\n\nexport function boundary() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original.boundary.apply(null, args);\n}\n\n// 'if' and 'await' are reserved words, so they cannot be declared as\n// function names and are exported via aliases instead.\nfunction __if_block() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original['if'].apply(null, args);\n}\n\nfunction __await_block() {\n let args = arguments;\n try { args = __wrapBlock(arguments); } catch {}\n return __svelte_original['await'].apply(null, args);\n}\n\nexport { __if_block as if, __await_block as await };\n`\n\nexport const runtimeCode = /* js */ `\nif (typeof window !== 'undefined' && !window.__SVELTE_DEVTOOLS__) {\n const __SVELTE_DT = {\n _nextId: 0,\n _instances: new Map(),\n _stack: [],\n _pendingFile: null,\n _effectCounter: 0,\n _debounceTimer: null,\n _listeners: new Set(),\n\n // Phase 2: Profiling data\n _profiles: new Map(),\n _initStartTimes: new Map(),\n _profileDebounceTimer: null,\n\n // Phase 2: Reactive graph data\n _reactiveNodes: new Map(),\n _reactiveProxies: new Map(),\n\n // Phase 3: State timeline\n _stateTimeline: [],\n _stateSnapshots: new Map(),\n _timelineDebounceTimer: null,\n\n register(file) {\n const id = this._nextId++;\n const parentId = this._stack.length > 0 ? this._stack[this._stack.length - 1] : null;\n const name = file.split('/').pop()?.replace('.svelte', '') || 'Unknown';\n this._instances.set(id, { id, file, name, parentId, mounted: true, children: [] });\n if (parentId !== null) {\n const parent = this._instances.get(parentId);\n if (parent) parent.children.push(id);\n }\n this._stack.push(id);\n this._scheduleUpdate();\n return id;\n },\n\n registered(id) {\n const idx = this._stack.indexOf(id);\n if (idx !== -1) this._stack.splice(idx, 1);\n },\n\n mount(id) {\n const instance = this._instances.get(id);\n if (instance && !instance.mounted) {\n instance.mounted = true;\n this._scheduleUpdate();\n }\n },\n\n unmount(id) {\n const instance = this._instances.get(id);\n if (instance) {\n if (instance.parentId !== null) {\n const parent = this._instances.get(instance.parentId);\n if (parent) {\n parent.children = parent.children.filter(cid => cid !== id);\n }\n }\n this._removeChildren(id);\n this._cleanupComponent(id);\n }\n this._scheduleUpdate();\n this._scheduleProfileUpdate();\n },\n\n // Remounts get a fresh id, so entries keyed by a dead id would otherwise\n // survive forever — every per-component map must be purged here.\n _cleanupComponent(id) {\n this._cleanupReactiveNodes(id);\n this._instances.delete(id);\n this._profiles.delete(id);\n this._initStartTimes.delete(id);\n },\n\n _cleanupReactiveNodes(componentId) {\n for (const [nodeId, entry] of this._reactiveNodes) {\n if (entry.meta.componentId === componentId) {\n this._reactiveNodes.delete(nodeId);\n this._reactiveProxies.delete(nodeId);\n this._stateSnapshots.delete(nodeId);\n if (this._stateSnapshotStrs) this._stateSnapshotStrs.delete(nodeId);\n }\n }\n },\n\n _removeChildren(parentId) {\n const parent = this._instances.get(parentId);\n if (!parent) return;\n for (const childId of [...parent.children]) {\n this._removeChildren(childId);\n this._cleanupComponent(childId);\n }\n },\n\n _scheduleUpdate() {\n if (this._debounceTimer) clearTimeout(this._debounceTimer);\n this._debounceTimer = setTimeout(() => {\n this._sendUpdate();\n }, 100);\n },\n\n _sendUpdate() {\n const components = [];\n for (const [, instance] of this._instances) {\n if (instance.mounted) {\n components.push({\n id: instance.id,\n file: instance.file,\n name: instance.name,\n parentId: instance.parentId,\n mounted: instance.mounted,\n });\n }\n }\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:components', { components });\n }\n },\n\n getTree() {\n const components = [];\n for (const [, instance] of this._instances) {\n if (instance.mounted) {\n components.push({\n id: instance.id,\n file: instance.file,\n name: instance.name,\n parentId: instance.parentId,\n mounted: instance.mounted,\n });\n }\n }\n return components;\n },\n\n // --- Phase 2: Render Profiling ---\n\n startInit(id) {\n this._initStartTimes.set(id, performance.now());\n },\n\n endInit(id) {\n const start = this._initStartTimes.get(id);\n if (start === undefined) return;\n const initTime = performance.now() - start;\n this._initStartTimes.delete(id);\n const instance = this._instances.get(id);\n if (!instance) return;\n this._profiles.set(id, {\n componentId: id,\n file: instance.file,\n name: instance.name,\n initTime,\n renderCount: 0,\n totalRenderTime: 0,\n lastRenderTime: 0,\n lastRenderAt: Date.now(),\n });\n this._scheduleProfileUpdate();\n },\n\n recordRender(id) {\n const profile = this._profiles.get(id);\n if (!profile) {\n const instance = this._instances.get(id);\n if (!instance) return;\n this._profiles.set(id, {\n componentId: id,\n file: instance.file,\n name: instance.name,\n initTime: 0,\n renderCount: 1,\n totalRenderTime: 0,\n lastRenderTime: 0,\n lastRenderAt: Date.now(),\n });\n } else {\n profile.renderCount++;\n profile.lastRenderAt = Date.now();\n }\n this._scheduleProfileUpdate();\n },\n\n recordRenderTime(id, duration) {\n const profile = this._profiles.get(id);\n if (profile) {\n profile.totalRenderTime += duration;\n profile.lastRenderTime = duration;\n }\n },\n\n _scheduleProfileUpdate() {\n if (this._profileDebounceTimer) clearTimeout(this._profileDebounceTimer);\n this._profileDebounceTimer = setTimeout(() => {\n this._sendProfileUpdate();\n }, 500);\n },\n\n _sendProfileUpdate() {\n const profiles = Array.from(this._profiles.values());\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:profiles', { profiles });\n }\n },\n\n getProfiles() {\n return Array.from(this._profiles.values());\n },\n\n resetProfiles() {\n this._profiles.clear();\n this._scheduleProfileUpdate();\n },\n\n // --- Phase 2: Reactive Graph Tracking ---\n\n trackState(signal, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(signal),\n meta: { id: nodeId, type: 'state', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackProxy(proxy, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveProxies.set(nodeId, new WeakRef(proxy));\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef({ v: '(proxy)', _isProxy: true }),\n meta: { id: nodeId, type: 'state', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackDerived(signal, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(signal),\n meta: { id: nodeId, type: 'derived', name, componentId, componentFile: instance ? instance.file : '' }\n });\n },\n\n trackEffect(effect, name, componentId) {\n const instance = this._instances.get(componentId);\n const nodeId = componentId + ':' + name;\n this._reactiveNodes.set(nodeId, {\n signal: new WeakRef(effect || { v: undefined, _isEffect: true }),\n meta: { id: nodeId, type: 'effect', name, componentId, componentFile: instance ? instance.file : '' }\n });\n return effect;\n },\n\n getReactiveGraph() {\n const nodes = [];\n const edges = [];\n const signalToId = new Map();\n\n for (const [nodeId, entry] of this._reactiveNodes) {\n const signal = entry.signal.deref();\n if (!signal || !this._instances.has(entry.meta.componentId)) {\n this._reactiveNodes.delete(nodeId);\n continue;\n }\n signalToId.set(signal, nodeId);\n const node = { ...entry.meta };\n if (signal._isProxy) {\n const proxyRef = this._reactiveProxies.get(nodeId);\n const proxy = proxyRef?.deref();\n if (proxy) {\n try {\n node.value = Array.isArray(proxy) ? '[' + proxy.length + ']' : '{' + Object.keys(proxy).length + '}';\n } catch { node.value = '(proxy)'; }\n }\n } else if (node.type !== 'effect' && signal.v !== undefined && typeof signal.v !== 'symbol') {\n try {\n const v = signal.v;\n if (typeof v === 'number' || typeof v === 'string' || typeof v === 'boolean' || v === null) {\n node.value = v;\n } else {\n node.value = '(object)';\n }\n } catch { /* ignore */ }\n }\n nodes.push(node);\n }\n\n // Map proxy internal signals to their proxy node ID\n for (const [nodeId, ref] of this._reactiveProxies) {\n const proxy = ref.deref();\n if (!proxy) { this._reactiveProxies.delete(nodeId); continue; }\n const meta = this._reactiveNodes.get(nodeId)?.meta;\n if (!meta || !this._instances.has(meta.componentId)) { this._reactiveProxies.delete(nodeId); continue; }\n }\n\n // Build edges from deps\n const edgeSet = new Set();\n for (const [nodeId, entry] of this._reactiveNodes) {\n const signal = entry.signal.deref();\n if (!signal) continue;\n if (!signal.deps) continue;\n\n const visited = new Set();\n const queue = [...signal.deps];\n while (queue.length > 0) {\n const dep = queue.shift();\n if (!dep || visited.has(dep)) continue;\n visited.add(dep);\n const depId = signalToId.get(dep);\n if (depId) {\n const key = depId + '>' + nodeId;\n if (depId !== nodeId && !edgeSet.has(key)) {\n edgeSet.add(key);\n edges.push({ from: depId, to: nodeId });\n }\n } else if (dep.deps) {\n for (const d of dep.deps) queue.push(d);\n }\n }\n }\n\n return { nodes, edges };\n },\n\n sendReactiveGraph() {\n const graph = this.getReactiveGraph();\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:reactive-graph', graph);\n }\n },\n\n // --- Phase 3: State Timeline ---\n\n _pollStateValues() {\n for (const [nodeId, entry] of this._reactiveNodes) {\n if (entry.meta.type !== 'state') continue;\n if (!this._instances.has(entry.meta.componentId)) {\n this._reactiveNodes.delete(nodeId);\n continue;\n }\n const signal = entry.signal.deref();\n if (!signal || signal.v === undefined) continue;\n try {\n const currentVal = signal.v;\n const prev = this._stateSnapshots.get(nodeId);\n if (prev !== undefined && currentVal === prev) continue;\n const isPrimitive = currentVal === null || typeof currentVal !== 'object';\n let newSnapshot;\n if (isPrimitive) {\n if (prev !== undefined && prev === currentVal) continue;\n newSnapshot = currentVal;\n } else {\n const currStr = JSON.stringify(currentVal);\n const prevStr = this._stateSnapshotStrs?.get(nodeId);\n if (prevStr === currStr) continue;\n newSnapshot = JSON.parse(currStr);\n if (!this._stateSnapshotStrs) this._stateSnapshotStrs = new Map();\n this._stateSnapshotStrs.set(nodeId, currStr);\n }\n if (this._stateTimeline.length >= 500) this._stateTimeline.splice(0, this._stateTimeline.length - 499);\n this._stateTimeline.push({\n id: nodeId,\n name: entry.meta.name,\n componentFile: entry.meta.componentFile,\n oldValue: prev !== undefined ? prev : null,\n newValue: newSnapshot,\n timestamp: Date.now(),\n });\n this._stateSnapshots.set(nodeId, newSnapshot);\n this._scheduleTimelineUpdate();\n } catch { /* ignore non-serializable */ }\n }\n },\n\n _scheduleTimelineUpdate() {\n if (this._timelineDebounceTimer) clearTimeout(this._timelineDebounceTimer);\n this._timelineDebounceTimer = setTimeout(() => {\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:state-timeline', { changes: this._stateTimeline });\n }\n }, 300);\n },\n\n getStateTimeline() {\n return this._stateTimeline;\n },\n\n clearStateTimeline() {\n this._stateTimeline = [];\n this._scheduleTimelineUpdate();\n },\n\n // --- FPS Monitoring ---\n // Uses requestAnimationFrame to measure frame rate with minimal overhead.\n // Only stores timestamps - no allocations per frame beyond a single array push.\n _fpsFrameTimes: [],\n\n _fpsLoop() {\n this._fpsFrameTimes.push(performance.now());\n requestAnimationFrame(() => this._fpsLoop());\n },\n\n _sampleFps() {\n const now = performance.now();\n // Remove frame timestamps older than 1 second\n const cutoff = now - 1000;\n let i = 0;\n while (i < this._fpsFrameTimes.length && this._fpsFrameTimes[i] < cutoff) i++;\n if (i > 0) this._fpsFrameTimes.splice(0, i);\n const fps = this._fpsFrameTimes.length;\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:fps', { timestamp: Date.now(), fps });\n }\n }\n };\n\n window.__SVELTE_DEVTOOLS__ = __SVELTE_DT;\n\n // Poll state values for timeline\n setInterval(() => { __SVELTE_DT._pollStateValues(); }, 200);\n\n // FPS monitoring\n requestAnimationFrame(() => __SVELTE_DT._fpsLoop());\n setInterval(() => __SVELTE_DT._sampleFps(), 500);\n\n // Phase 3: Capture runtime errors\n window.addEventListener('error', (event) => {\n if (import.meta.hot) {\n import.meta.hot.send('svelte-devtools:runtime-error', {\n message: event.message,\n file: event.filename,\n line: event.lineno,\n column: event.colno,\n stack: event.error?.stack || '',\n timestamp: Date.now(),\n });\n }\n });\n window.addEventListener('unhandledrejection', (event) => {\n if (import.meta.hot) {\n const reason = event.reason;\n import.meta.hot.send('svelte-devtools:runtime-error', {\n message: reason?.message || String(reason),\n stack: reason?.stack || '',\n timestamp: Date.now(),\n });\n }\n });\n\n // Listen for reactive graph requests from server\n if (import.meta.hot) {\n import.meta.hot.on('svelte-devtools:request-reactive-graph', () => {\n __SVELTE_DT.sendReactiveGraph();\n });\n import.meta.hot.on('svelte-devtools:request-state-timeline', () => {\n import.meta.hot.send('svelte-devtools:state-timeline', { changes: __SVELTE_DT._stateTimeline });\n });\n import.meta.hot.on('svelte-devtools:clear-state-timeline', () => {\n __SVELTE_DT.clearStateTimeline();\n });\n }\n}\n`\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport crypto from 'node:crypto'\nimport type { RenderProfile, LoadProfile, FpsSample } from '../types.js'\n\nexport interface SessionSnapshot {\n /** componentId -> { renderCount, totalRenderTime } at snapshot moment */\n renderProfiles: Array<{\n componentId: number\n file: string\n name: string\n renderCount: number\n totalRenderTime: number\n }>\n loadProfilesCount: number\n fpsCount: number\n takenAt: number\n}\n\nexport interface SessionRecord {\n id: string\n label: string\n startedAt: number\n endedAt?: number\n persist: boolean\n startSnapshot: SessionSnapshot\n endSnapshot?: SessionSnapshot\n /** load profiles that arrived strictly between startedAt..endedAt */\n loadProfiles: LoadProfile[]\n /** fps samples that arrived strictly between startedAt..endedAt */\n fpsSamples: FpsSample[]\n}\n\nexport interface SessionDelta {\n durationMs: number\n components: Array<{\n componentId: number\n file: string\n name: string\n renderCountDelta: number\n totalRenderTimeDelta: number\n avgRenderTimeDelta: number\n }>\n loadProfiles: {\n count: number\n avgDuration: number\n p95Duration: number\n }\n fps: {\n samples: number\n avg: number\n min: number\n drops: number\n }\n}\n\nexport interface SessionDiff {\n a: { id: string; label: string }\n b: { id: string; label: string }\n render: {\n totalRenderTimeDeltaA: number\n totalRenderTimeDeltaB: number\n diff: number\n verdict: 'improved' | 'regressed' | 'unchanged'\n }\n load: {\n avgA: number\n avgB: number\n diff: number\n verdict: 'improved' | 'regressed' | 'unchanged'\n }\n fps: {\n avgA: number\n avgB: number\n diff: number\n verdict: 'improved' | 'regressed' | 'unchanged'\n }\n}\n\nexport interface MetricGetters {\n getRenderProfiles: () => RenderProfile[]\n getLoadProfiles: () => LoadProfile[]\n getFpsSamples: () => FpsSample[]\n}\n\nconst UNCHANGED_RENDER_THRESHOLD_MS = 1\nconst UNCHANGED_LOAD_THRESHOLD_MS = 5\nconst UNCHANGED_FPS_THRESHOLD = 1\nconst FPS_DROP_THRESHOLD = 30\n\nfunction takeSnapshot(getters: MetricGetters): SessionSnapshot {\n const renderProfiles = getters.getRenderProfiles().map(p => ({\n componentId: p.componentId,\n file: p.file,\n name: p.name,\n renderCount: p.renderCount,\n totalRenderTime: p.totalRenderTime,\n }))\n return {\n renderProfiles,\n loadProfilesCount: getters.getLoadProfiles().length,\n fpsCount: getters.getFpsSamples().length,\n takenAt: Date.now(),\n }\n}\n\nfunction classify(\n diff: number,\n threshold: number,\n lowerIsBetter: boolean,\n): 'improved' | 'regressed' | 'unchanged' {\n if (Math.abs(diff) < threshold) return 'unchanged'\n const negativeIsBetter = lowerIsBetter\n if (negativeIsBetter) return diff < 0 ? 'improved' : 'regressed'\n return diff > 0 ? 'improved' : 'regressed'\n}\n\nexport interface SessionStoreOptions {\n persistDir: string\n getters: MetricGetters\n}\n\nexport class SessionStore {\n private sessions = new Map<string, SessionRecord>()\n private active: string | null = null\n private readonly persistDir: string\n private readonly getters: MetricGetters\n\n constructor(opts: SessionStoreOptions) {\n this.persistDir = opts.persistDir\n this.getters = opts.getters\n }\n\n start(label: string, persist: boolean): SessionRecord {\n if (this.active) {\n throw new Error(\n `A session is already active: ${this.active}. Call end_session before starting a new one.`,\n )\n }\n const id = `s_${Date.now().toString(36)}_${crypto.randomBytes(3).toString('hex')}`\n const record: SessionRecord = {\n id,\n label,\n startedAt: Date.now(),\n persist,\n startSnapshot: takeSnapshot(this.getters),\n loadProfiles: [],\n fpsSamples: [],\n }\n this.sessions.set(id, record)\n this.active = id\n return record\n }\n\n /** Called by the plugin whenever a new load profile arrives. */\n recordLoadProfile(p: LoadProfile): void {\n if (!this.active) return\n const rec = this.sessions.get(this.active)\n if (rec) rec.loadProfiles.push(p)\n }\n\n /** Called by the plugin whenever a new fps sample arrives. */\n recordFpsSample(s: FpsSample): void {\n if (!this.active) return\n const rec = this.sessions.get(this.active)\n if (rec) rec.fpsSamples.push(s)\n }\n\n end(keep: 'memory' | 'disk' | 'discard'): SessionRecord {\n if (!this.active) throw new Error('No active session')\n const rec = this.sessions.get(this.active)\n if (!rec) throw new Error('Active session missing from store')\n rec.endedAt = Date.now()\n rec.endSnapshot = takeSnapshot(this.getters)\n this.active = null\n\n if (keep === 'discard') {\n this.sessions.delete(rec.id)\n } else if (keep === 'disk' || rec.persist) {\n this.persistToDisk(rec)\n }\n return rec\n }\n\n get(id: string): SessionRecord | undefined {\n const inMem = this.sessions.get(id)\n if (inMem) return inMem\n return this.loadFromDisk(id)\n }\n\n list(): Array<{\n id: string\n label: string\n startedAt: number\n endedAt?: number\n persisted: boolean\n active: boolean\n }> {\n const seen = new Set<string>()\n const out: Array<{\n id: string\n label: string\n startedAt: number\n endedAt?: number\n persisted: boolean\n active: boolean\n }> = []\n for (const rec of this.sessions.values()) {\n seen.add(rec.id)\n out.push({\n id: rec.id,\n label: rec.label,\n startedAt: rec.startedAt,\n endedAt: rec.endedAt,\n persisted: fs.existsSync(this.pathFor(rec.id)),\n active: this.active === rec.id,\n })\n }\n try {\n if (fs.existsSync(this.persistDir)) {\n for (const name of fs.readdirSync(this.persistDir)) {\n if (!name.endsWith('.json')) continue\n const id = name.slice(0, -5)\n if (seen.has(id)) continue\n try {\n const rec = JSON.parse(fs.readFileSync(path.join(this.persistDir, name), 'utf-8'))\n out.push({\n id: rec.id,\n label: rec.label,\n startedAt: rec.startedAt,\n endedAt: rec.endedAt,\n persisted: true,\n active: false,\n })\n } catch {\n /* skip unreadable session file */\n }\n }\n }\n } catch {\n /* persist dir not accessible */\n }\n return out.sort((a, b) => b.startedAt - a.startedAt)\n }\n\n delete(id: string): boolean {\n const had = this.sessions.delete(id)\n let onDisk = false\n try {\n const p = this.pathFor(id)\n if (fs.existsSync(p)) {\n fs.unlinkSync(p)\n onDisk = true\n }\n } catch {\n /* ignore */\n }\n if (this.active === id) this.active = null\n return had || onDisk\n }\n\n delta(id: string): SessionDelta {\n const rec = this.get(id)\n if (!rec) throw new Error(`Session not found: ${id}`)\n if (!rec.endSnapshot || rec.endedAt === undefined) {\n throw new Error(`Session ${id} has not been ended yet`)\n }\n const startMap = new Map(rec.startSnapshot.renderProfiles.map(p => [p.componentId, p]))\n const components = rec.endSnapshot.renderProfiles\n .map(end => {\n const start = startMap.get(end.componentId)\n const startRenderCount = start?.renderCount ?? 0\n const startTotal = start?.totalRenderTime ?? 0\n const renderCountDelta = end.renderCount - startRenderCount\n const totalRenderTimeDelta = end.totalRenderTime - startTotal\n return {\n componentId: end.componentId,\n file: end.file,\n name: end.name,\n renderCountDelta,\n totalRenderTimeDelta,\n avgRenderTimeDelta: renderCountDelta > 0 ? totalRenderTimeDelta / renderCountDelta : 0,\n }\n })\n .filter(c => c.renderCountDelta > 0)\n .sort((a, b) => b.totalRenderTimeDelta - a.totalRenderTimeDelta)\n\n const loadDurations = rec.loadProfiles.map(l => l.duration)\n const loadAvg = avg(loadDurations)\n const loadP95 = percentile(loadDurations, 95)\n\n const fpsValues = rec.fpsSamples.map(s => s.fps)\n const fpsAvg = avg(fpsValues)\n const fpsMin = fpsValues.length ? Math.min(...fpsValues) : 0\n const fpsDrops = fpsValues.filter(f => f < FPS_DROP_THRESHOLD).length\n\n return {\n durationMs: rec.endedAt - rec.startedAt,\n components,\n loadProfiles: { count: rec.loadProfiles.length, avgDuration: loadAvg, p95Duration: loadP95 },\n fps: { samples: fpsValues.length, avg: fpsAvg, min: fpsMin, drops: fpsDrops },\n }\n }\n\n compare(idA: string, idB: string): SessionDiff {\n const a = this.delta(idA)\n const b = this.delta(idB)\n const recA = this.get(idA)!\n const recB = this.get(idB)!\n const totalA = a.components.reduce((s, c) => s + c.totalRenderTimeDelta, 0)\n const totalB = b.components.reduce((s, c) => s + c.totalRenderTimeDelta, 0)\n const renderDiff = totalB - totalA\n const loadDiff = b.loadProfiles.avgDuration - a.loadProfiles.avgDuration\n const fpsDiff = b.fps.avg - a.fps.avg\n return {\n a: { id: recA.id, label: recA.label },\n b: { id: recB.id, label: recB.label },\n render: {\n totalRenderTimeDeltaA: totalA,\n totalRenderTimeDeltaB: totalB,\n diff: renderDiff,\n verdict: classify(renderDiff, UNCHANGED_RENDER_THRESHOLD_MS, true),\n },\n load: {\n avgA: a.loadProfiles.avgDuration,\n avgB: b.loadProfiles.avgDuration,\n diff: loadDiff,\n verdict: classify(loadDiff, UNCHANGED_LOAD_THRESHOLD_MS, true),\n },\n fps: {\n avgA: a.fps.avg,\n avgB: b.fps.avg,\n diff: fpsDiff,\n verdict: classify(fpsDiff, UNCHANGED_FPS_THRESHOLD, false),\n },\n }\n }\n\n private pathFor(id: string): string {\n return path.join(this.persistDir, `${id}.json`)\n }\n\n private persistToDisk(rec: SessionRecord): void {\n try {\n fs.mkdirSync(this.persistDir, { recursive: true })\n fs.writeFileSync(this.pathFor(rec.id), JSON.stringify(rec, null, 2), { mode: 0o600 })\n } catch {\n /* persist failure is non-fatal; the in-memory record stays available */\n }\n }\n\n private loadFromDisk(id: string): SessionRecord | undefined {\n try {\n const raw = fs.readFileSync(this.pathFor(id), 'utf-8')\n return JSON.parse(raw)\n } catch {\n return undefined\n }\n }\n}\n\nfunction avg(xs: number[]): number {\n if (!xs.length) return 0\n return xs.reduce((s, x) => s + x, 0) / xs.length\n}\n\nfunction percentile(xs: number[], p: number): number {\n if (!xs.length) return 0\n const sorted = [...xs].sort((a, b) => a - b)\n const idx = Math.min(sorted.length - 1, Math.floor((p / 100) * sorted.length))\n return sorted[idx]\n}\n","import type { RenderProfile, ReactiveGraph, LoadProfile, FpsSample } from '../types.js'\n\nexport type IssueKind =\n | 'slow-component-render'\n | 'over-rendered-component'\n | 'slow-load'\n | 'fps-drop'\n | 'effect-overconnected'\n | 'derived-orphan'\n\nexport interface PerformanceIssue {\n id: string\n kind: IssueKind\n severity: 'low' | 'medium' | 'high'\n summary: string\n file?: string\n line?: number\n metric: Record<string, number>\n /** Tool that returns more detail for this issue. */\n suggestedTool: string\n}\n\nexport interface IssueThresholds {\n /** Per-render time (ms) above which a component render is considered slow. */\n avgRenderTimeMs?: number\n /** Render count above which a component is considered over-rendered. */\n renderCount?: number\n /** Load duration (ms) above which a SvelteKit load is slow. */\n loadDurationMs?: number\n /** FPS below which we record a drop. */\n fpsDropThreshold?: number\n /** Outgoing edge count from an effect above which it is over-connected. */\n effectMaxDeps?: number\n}\n\nconst DEFAULTS: Required<IssueThresholds> = {\n avgRenderTimeMs: 4,\n renderCount: 30,\n loadDurationMs: 200,\n fpsDropThreshold: 40,\n effectMaxDeps: 8,\n}\n\nexport interface IssueInputs {\n renderProfiles: RenderProfile[]\n reactiveGraph: ReactiveGraph\n loadProfiles: LoadProfile[]\n fpsSamples: FpsSample[]\n}\n\nexport function listPerformanceIssues(\n inputs: IssueInputs,\n thresholds: IssueThresholds = {},\n): PerformanceIssue[] {\n const t = { ...DEFAULTS, ...thresholds }\n const out: PerformanceIssue[] = []\n\n for (const p of inputs.renderProfiles) {\n const avg = p.renderCount > 0 ? p.totalRenderTime / p.renderCount : 0\n if (avg >= t.avgRenderTimeMs) {\n out.push({\n id: `slow-render:${p.file}:${p.componentId}`,\n kind: 'slow-component-render',\n severity:\n avg >= t.avgRenderTimeMs * 4 ? 'high' : avg >= t.avgRenderTimeMs * 2 ? 'medium' : 'low',\n summary: `${p.name} averages ${avg.toFixed(2)}ms per render (${p.renderCount} renders)`,\n file: p.file,\n metric: {\n avgRenderTimeMs: round(avg),\n renderCount: p.renderCount,\n totalRenderTimeMs: round(p.totalRenderTime),\n },\n suggestedTool: 'get_render_profile',\n })\n }\n if (p.renderCount >= t.renderCount) {\n out.push({\n id: `over-render:${p.file}:${p.componentId}`,\n kind: 'over-rendered-component',\n severity:\n p.renderCount >= t.renderCount * 8\n ? 'high'\n : p.renderCount >= t.renderCount * 3\n ? 'medium'\n : 'low',\n summary: `${p.name} rendered ${p.renderCount} times`,\n file: p.file,\n metric: { renderCount: p.renderCount, avgRenderTimeMs: round(avg) },\n suggestedTool: 'get_component_hotspots',\n })\n }\n }\n\n for (const l of inputs.loadProfiles) {\n if (l.duration >= t.loadDurationMs) {\n out.push({\n id: `slow-load:${l.route}:${l.timestamp}`,\n kind: 'slow-load',\n severity:\n l.duration >= t.loadDurationMs * 5\n ? 'high'\n : l.duration >= t.loadDurationMs * 2\n ? 'medium'\n : 'low',\n summary: `${l.type} load for ${l.route} took ${l.duration.toFixed(0)}ms`,\n file: l.file,\n metric: { durationMs: round(l.duration), dataSizeBytes: l.dataSize },\n suggestedTool: 'get_load_waterfall',\n })\n }\n }\n\n const fpsDrops = inputs.fpsSamples.filter(s => s.fps < t.fpsDropThreshold)\n if (fpsDrops.length > 0) {\n const min = Math.min(...fpsDrops.map(s => s.fps))\n out.push({\n id: `fps-drops:${inputs.fpsSamples[0]?.timestamp ?? 0}`,\n kind: 'fps-drop',\n severity: min < 15 ? 'high' : min < 30 ? 'medium' : 'low',\n summary: `${fpsDrops.length} FPS samples below ${t.fpsDropThreshold} (min ${min})`,\n metric: { dropCount: fpsDrops.length, minFps: min, threshold: t.fpsDropThreshold },\n suggestedTool: 'get_fps_drops',\n })\n }\n\n // Reactive graph: count outgoing edges per node\n const outDegree = new Map<string, number>()\n for (const e of inputs.reactiveGraph.edges) {\n outDegree.set(e.from, (outDegree.get(e.from) ?? 0) + 1)\n }\n const inDegree = new Map<string, number>()\n for (const e of inputs.reactiveGraph.edges) {\n inDegree.set(e.to, (inDegree.get(e.to) ?? 0) + 1)\n }\n for (const node of inputs.reactiveGraph.nodes) {\n if (node.type === 'effect') {\n const deps = inDegree.get(node.id) ?? 0\n if (deps >= t.effectMaxDeps) {\n out.push({\n id: `effect-deps:${node.id}`,\n kind: 'effect-overconnected',\n severity:\n deps >= t.effectMaxDeps * 3 ? 'high' : deps >= t.effectMaxDeps * 2 ? 'medium' : 'low',\n summary: `effect \"${node.name}\" depends on ${deps} reactive values`,\n file: node.componentFile,\n metric: { depCount: deps },\n suggestedTool: 'get_reactive_graph_problems',\n })\n }\n }\n if (node.type === 'derived') {\n const fanout = outDegree.get(node.id) ?? 0\n if (fanout === 0 && (inDegree.get(node.id) ?? 0) > 0) {\n out.push({\n id: `derived-orphan:${node.id}`,\n kind: 'derived-orphan',\n severity: 'low',\n summary: `derived \"${node.name}\" has dependencies but is unused`,\n file: node.componentFile,\n metric: { fanout },\n suggestedTool: 'get_reactive_graph_problems',\n })\n }\n }\n }\n\n return out.sort(compareSeverity)\n}\n\nconst SEV_RANK: Record<PerformanceIssue['severity'], number> = { high: 0, medium: 1, low: 2 }\n\nfunction compareSeverity(a: PerformanceIssue, b: PerformanceIssue): number {\n return SEV_RANK[a.severity] - SEV_RANK[b.severity]\n}\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100\n}\n\nexport interface ReactiveProblems {\n effects: Array<{ id: string; name: string; file: string; depCount: number }>\n orphanDeriveds: Array<{ id: string; name: string; file: string }>\n isolatedNodes: Array<{ id: string; name: string; type: string; file: string }>\n}\n\nexport function summarizeReactiveProblems(\n graph: ReactiveGraph,\n t: IssueThresholds = {},\n): ReactiveProblems {\n const thresh = { ...DEFAULTS, ...t }\n const inDegree = new Map<string, number>()\n const outDegree = new Map<string, number>()\n for (const e of graph.edges) {\n inDegree.set(e.to, (inDegree.get(e.to) ?? 0) + 1)\n outDegree.set(e.from, (outDegree.get(e.from) ?? 0) + 1)\n }\n const effects: ReactiveProblems['effects'] = []\n const orphanDeriveds: ReactiveProblems['orphanDeriveds'] = []\n const isolatedNodes: ReactiveProblems['isolatedNodes'] = []\n for (const node of graph.nodes) {\n const ind = inDegree.get(node.id) ?? 0\n const outd = outDegree.get(node.id) ?? 0\n if (node.type === 'effect' && ind >= thresh.effectMaxDeps) {\n effects.push({ id: node.id, name: node.name, file: node.componentFile, depCount: ind })\n }\n if (node.type === 'derived' && outd === 0 && ind > 0) {\n orphanDeriveds.push({ id: node.id, name: node.name, file: node.componentFile })\n }\n if (ind === 0 && outd === 0) {\n isolatedNodes.push({\n id: node.id,\n name: node.name,\n type: node.type,\n file: node.componentFile,\n })\n }\n }\n return { effects, orphanDeriveds, isolatedNodes }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'\nimport { z } from 'zod'\nimport type {\n RenderProfile,\n ReactiveGraph,\n LoadProfile,\n FpsSample,\n ComponentInstance,\n ProjectInfo,\n RouteInfo,\n ComponentRelation,\n} from '../types.js'\nimport { SessionStore } from './sessions.js'\nimport { listPerformanceIssues, summarizeReactiveProblems, type IssueThresholds } from './issues.js'\n\nexport interface McpDeps {\n getProject: () => ProjectInfo\n getRoutes: () => RouteInfo[]\n getLiveComponents: () => ComponentInstance[]\n getComponentRelations: () => ComponentRelation[]\n getRenderProfiles: () => RenderProfile[]\n /** Resolves with the current reactive graph after refreshing from the browser. */\n getReactiveGraph: () => Promise<ReactiveGraph>\n getLoadProfiles: () => LoadProfile[]\n getFpsSamples: () => FpsSample[]\n sessions: SessionStore\n}\n\nconst TEXT = (value: unknown) => ({\n content: [\n {\n type: 'text' as const,\n text: typeof value === 'string' ? value : JSON.stringify(value, null, 2),\n },\n ],\n})\n\nexport function buildMcpServer(deps: McpDeps): McpServer {\n const server = new McpServer({\n name: 'vite-devtools-svelte',\n version: '0.1.0',\n })\n\n // --- read tools: issue surface ---\n\n server.registerTool(\n 'list_performance_issues',\n {\n title: 'List performance issues',\n description:\n 'Cross-cuts render/reactive/load/fps metrics and returns ranked issues. The entry point for AI-driven performance audits. Each issue carries `suggestedTool` naming the detail tool to call next.',\n inputSchema: {\n avgRenderTimeMs: z.number().optional(),\n renderCount: z.number().optional(),\n loadDurationMs: z.number().optional(),\n fpsDropThreshold: z.number().optional(),\n effectMaxDeps: z.number().optional(),\n },\n },\n async args => {\n const thresholds: IssueThresholds = args\n const reactiveGraph = await deps.getReactiveGraph()\n const issues = listPerformanceIssues(\n {\n renderProfiles: deps.getRenderProfiles(),\n reactiveGraph,\n loadProfiles: deps.getLoadProfiles(),\n fpsSamples: deps.getFpsSamples(),\n },\n thresholds,\n )\n return TEXT({ count: issues.length, issues })\n },\n )\n\n server.registerTool(\n 'get_component_hotspots',\n {\n title: 'Component render hotspots',\n description: 'Top components by total render time, with render count and per-render average.',\n inputSchema: { topN: z.number().int().min(1).max(200).optional() },\n },\n async ({ topN = 20 }) => {\n const list = [...deps.getRenderProfiles()]\n .map(p => ({\n file: p.file,\n name: p.name,\n componentId: p.componentId,\n renderCount: p.renderCount,\n totalRenderTimeMs: round(p.totalRenderTime),\n avgRenderTimeMs: round(p.renderCount > 0 ? p.totalRenderTime / p.renderCount : 0),\n lastRenderTimeMs: round(p.lastRenderTime),\n lastRenderAt: p.lastRenderAt,\n }))\n .sort((a, b) => b.totalRenderTimeMs - a.totalRenderTimeMs)\n .slice(0, topN)\n return TEXT(list)\n },\n )\n\n server.registerTool(\n 'get_reactive_graph_problems',\n {\n title: 'Reactive graph problems',\n description:\n 'Classified reactive graph issues: over-connected effects, orphan deriveds, isolated nodes. Returns categories instead of the full graph.',\n inputSchema: { effectMaxDeps: z.number().int().min(1).optional() },\n },\n async ({ effectMaxDeps }) => {\n const graph = await deps.getReactiveGraph()\n return TEXT(summarizeReactiveProblems(graph, { effectMaxDeps }))\n },\n )\n\n server.registerTool(\n 'get_load_waterfall',\n {\n title: 'SvelteKit load waterfall',\n description:\n 'Load profiles grouped by route, with timing and data size. Optionally filtered by route.',\n inputSchema: { route: z.string().optional() },\n },\n async ({ route }) => {\n let profiles = deps.getLoadProfiles()\n if (route) profiles = profiles.filter(p => p.route === route)\n const byRoute = new Map<string, LoadProfile[]>()\n for (const p of profiles) {\n const arr = byRoute.get(p.route) ?? []\n arr.push(p)\n byRoute.set(p.route, arr)\n }\n const groups = [...byRoute.entries()].map(([r, ps]) => {\n const durations = ps.map(p => p.duration)\n return {\n route: r,\n file: ps[0]?.file,\n count: ps.length,\n avgDuration: round(avg(durations)),\n maxDuration: round(Math.max(...durations)),\n totalDataBytes: ps.reduce((s, p) => s + p.dataSize, 0),\n samples: ps,\n }\n })\n return TEXT(groups.sort((a, b) => b.avgDuration - a.avgDuration))\n },\n )\n\n server.registerTool(\n 'get_fps_drops',\n {\n title: 'FPS drops',\n description: 'Samples whose FPS fell below `threshold`. Returns timestamp + fps for each.',\n inputSchema: {\n threshold: z.number().min(1).max(120).optional(),\n sinceMs: z.number().optional(),\n },\n },\n async ({ threshold = 40, sinceMs }) => {\n let samples = deps.getFpsSamples()\n if (sinceMs !== undefined) {\n const cutoff = Date.now() - sinceMs\n samples = samples.filter(s => s.timestamp >= cutoff)\n }\n const drops = samples.filter(s => s.fps < threshold)\n return TEXT({\n threshold,\n sampleCount: samples.length,\n dropCount: drops.length,\n minFps: drops.length ? Math.min(...drops.map(s => s.fps)) : null,\n drops,\n })\n },\n )\n\n server.registerTool(\n 'get_render_profile',\n {\n title: 'Render profile for a specific file',\n description:\n 'Returns render profile entries matching the given component file (substring match).',\n inputSchema: { file: z.string() },\n },\n async ({ file }) => {\n const matches = deps\n .getRenderProfiles()\n .filter(p => p.file.includes(file))\n .map(p => ({\n ...p,\n totalRenderTimeMs: round(p.totalRenderTime),\n avgRenderTimeMs: round(p.renderCount > 0 ? p.totalRenderTime / p.renderCount : 0),\n }))\n return TEXT(matches)\n },\n )\n\n // --- context tools ---\n\n server.registerTool(\n 'get_project_info',\n {\n title: 'Project info',\n description: 'Package name/version, Svelte / SvelteKit / Vite versions, dependency lists.',\n inputSchema: {},\n },\n async () => TEXT(deps.getProject()),\n )\n\n server.registerTool(\n 'get_routes',\n {\n title: 'SvelteKit routes',\n description: 'Static analysis of the SvelteKit routes tree.',\n inputSchema: {},\n },\n async () => TEXT(deps.getRoutes()),\n )\n\n server.registerTool(\n 'get_live_components',\n {\n title: 'Currently mounted components',\n description:\n 'Component instances with file, parent, mounted status as currently mounted in the browser.',\n inputSchema: {},\n },\n async () => TEXT(deps.getLiveComponents()),\n )\n\n server.registerTool(\n 'get_component_relations',\n {\n title: 'Component import graph',\n description: 'Static import relations between .svelte components.',\n inputSchema: {},\n },\n async () => TEXT(deps.getComponentRelations()),\n )\n\n // --- session tools ---\n\n server.registerTool(\n 'start_session',\n {\n title: 'Start measurement session',\n description:\n 'Begin capturing metrics under a labelled session. Required before compare_sessions. Set `persist:true` to write to disk on end; otherwise the session lives in memory only.',\n inputSchema: {\n label: z.string(),\n persist: z.boolean().optional(),\n },\n },\n async ({ label, persist = false }) => {\n const rec = deps.sessions.start(label, persist)\n return TEXT({ id: rec.id, label: rec.label, startedAt: rec.startedAt, persist: rec.persist })\n },\n )\n\n server.registerTool(\n 'end_session',\n {\n title: 'End current measurement session',\n description:\n 'Closes the active session and returns its delta. `keep` decides disposal: \"memory\" keeps it for this dev-server lifetime, \"disk\" writes to .vite-devtools-svelte/sessions/, \"discard\" deletes it.',\n inputSchema: {\n keep: z.enum(['memory', 'disk', 'discard']).optional(),\n },\n },\n async ({ keep = 'memory' }) => {\n const rec = deps.sessions.end(keep)\n const delta = rec.endedAt ? deps.sessions.delta(rec.id) : null\n return TEXT({\n id: rec.id,\n label: rec.label,\n startedAt: rec.startedAt,\n endedAt: rec.endedAt,\n keep,\n delta,\n })\n },\n )\n\n server.registerTool(\n 'compare_sessions',\n {\n title: 'Compare two sessions',\n description:\n 'Diff render / load / fps metrics between two ended sessions. Each section carries `verdict`: improved | regressed | unchanged.',\n inputSchema: { a: z.string(), b: z.string() },\n },\n async ({ a, b }) => TEXT(deps.sessions.compare(a, b)),\n )\n\n server.registerTool(\n 'list_sessions',\n {\n title: 'List sessions',\n description: 'In-memory + on-disk sessions, most recent first.',\n inputSchema: {},\n },\n async () => TEXT(deps.sessions.list()),\n )\n\n server.registerTool(\n 'load_session',\n {\n title: 'Load a session by id',\n description: 'Returns the full session record (including delta if ended) by id.',\n inputSchema: { id: z.string() },\n },\n async ({ id }) => {\n const rec = deps.sessions.get(id)\n if (!rec) return TEXT({ error: `Session not found: ${id}` })\n const delta = rec.endedAt ? deps.sessions.delta(id) : null\n return TEXT({ ...rec, delta })\n },\n )\n\n server.registerTool(\n 'delete_session',\n {\n title: 'Delete a session',\n description: 'Removes a session from memory and disk.',\n inputSchema: { id: z.string() },\n },\n async ({ id }) => TEXT({ deleted: deps.sessions.delete(id) }),\n )\n\n return server\n}\n\nexport { StreamableHTTPServerTransport }\n\nfunction avg(xs: number[]): number {\n if (!xs.length) return 0\n return xs.reduce((s, x) => s + x, 0) / xs.length\n}\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100\n}\n","/// <reference types=\"@vitejs/devtools-kit\" />\nimport type { Plugin } from 'vite'\n\n/**\n * SvelteKit dev bypasses Vite's `transformIndexHtml`, so `@vitejs/devtools`'s\n * `DevToolsInjection` never reaches the served HTML and the dock is invisible\n * on every SvelteKit page. Tracked upstream at\n * https://github.com/baseballyama/vite-devtools-repl/tree/main/sveltekit-transform-index-html-bypass\n *\n * As a stopgap, SvelteKit inlines `src/app.html` as a JS string literal inside\n * `.svelte-kit/generated/server/internal.js`:\n *\n * templates: {\n * app: ({ head, body, ... }) => \"<!doctype html>...<body>...</body>...\",\n * }\n *\n * That file is loaded through Vite's module pipeline (`vite.ssrLoadModule`),\n * so a regular `transform` hook can rewrite the literal to insert the dock's\n * inject script before `</body>`. The actual `<script>` runs in the browser\n * once the HTML is delivered, so no SSR safety guard on the inject module is\n * needed for this path.\n *\n * This is intentionally narrow — SvelteKit-specific path match plus a\n * structural assertion — and there's a test (`template-injector.test.ts`)\n * that fails if SvelteKit's generated shape changes, so a silent break shows\n * up in CI instead of as a missing dock in production.\n */\n\nexport const SVELTEKIT_INTERNAL_SUFFIX = '.svelte-kit/generated/server/internal.js'\n\n/** Marker that the `templates.app` literal in SvelteKit's generated server. */\nexport const TEMPLATE_APP_MARKER = 'templates: {'\n\n/** Where to inject the inject script — escaped because we're editing a JS string literal. */\nconst INJECT_SCRIPT_URL = '/@id/@vitejs/devtools/client/inject'\nconst INJECT_TAG = `<script type=\\\\\"module\\\\\" src=\\\\\"${INJECT_SCRIPT_URL}\\\\\"></script>`\n\n/**\n * `</body>` as it appears inside SvelteKit's generated string literal.\n * SvelteKit emits `app.html` via `JSON.stringify`-style escaping, which leaves\n * `/` alone — only control characters and quotes are escaped. So the literal\n * substring we actually search for is plain `</body>`.\n */\nconst BODY_CLOSE = '</body>'\n\n/**\n * Transform `.svelte-kit/generated/server/internal.js` to add the\n * `@vitejs/devtools` inject script right before `</body>` inside the app\n * template literal. Exposed for unit testing.\n *\n * Returns the new source if a substitution was made, or `null` to signal\n * \"nothing to do\" (already injected, structural marker missing, etc.).\n */\nexport function injectIntoSvelteKitInternal(code: string): string | null {\n // Cheap structural sanity check — bail if SvelteKit changed how it generates\n // the template object. The companion test asserts this branch is reachable.\n if (!code.includes(TEMPLATE_APP_MARKER)) return null\n if (!code.includes(BODY_CLOSE)) return null\n\n // Idempotence: don't double-inject across HMR re-runs.\n if (code.includes(INJECT_SCRIPT_URL)) return null\n\n // Only patch the literal that follows the `templates: {` marker, so a\n // future `</body>` mentioned in unrelated source code won't be touched.\n const markerIdx = code.indexOf(TEMPLATE_APP_MARKER)\n const bodyIdx = code.indexOf(BODY_CLOSE, markerIdx)\n if (bodyIdx === -1) return null\n\n return code.slice(0, bodyIdx) + INJECT_TAG + code.slice(bodyIdx)\n}\n\n/**\n * Vite plugin: inject `@vitejs/devtools/client/inject` into SvelteKit's\n * dev-only generated server template. Dev-only by construction.\n */\nexport function sveltekitTemplateInjector(): Plugin {\n return {\n name: 'vite-devtools-svelte:sveltekit-template-injector',\n enforce: 'post',\n apply: (_userConfig, env) => env.command === 'serve' && !env.isSsrBuild,\n\n transform(code, id) {\n if (!id.endsWith(SVELTEKIT_INTERNAL_SUFFIX)) return\n const next = injectIntoSvelteKitInternal(code)\n if (next === null) return\n return { code: next, map: null }\n },\n }\n}\n","/// <reference types=\"@vitejs/devtools-kit\" />\nimport type { Plugin, ResolvedConfig, ViteDevServer } from 'vite'\nimport path from 'node:path'\nimport fs from 'node:fs'\nimport net from 'node:net'\nimport crypto from 'node:crypto'\nimport { fileURLToPath } from 'node:url'\nimport { execFile } from 'node:child_process'\nimport { analyzeRoutes } from './analyzers/routes.js'\nimport { analyzeAssets, MIME_TYPES } from './analyzers/assets.js'\nimport { analyzeProject } from './analyzers/project.js'\nimport { analyzeComponents } from './analyzers/components.js'\nimport {\n RUNTIME_MODULE_ID,\n RESOLVED_RUNTIME_ID,\n runtimeCode,\n WRAPPER_MODULE_ID,\n wrapperCode,\n} from './runtime.js'\nimport { SessionStore } from './mcp/sessions.js'\nimport { buildMcpServer, StreamableHTTPServerTransport } from './mcp/server.js'\nimport { sveltekitTemplateInjector } from './template-injector.js'\nimport type {\n ComponentInstance,\n RenderProfile,\n LoadProfile,\n ReactiveGraph,\n StateChange,\n CompilerWarning,\n RuntimeError,\n InspectResult,\n ApiEndpoint,\n ApiResponse,\n ModuleGraphData,\n ModuleNode,\n OGPreview,\n BuildAnalysis,\n BuildChunk,\n FpsSample,\n} from './types.js'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\n/**\n * Validate that a URL does not target private/internal network addresses (SSRF prevention).\n * Allows only http/https schemes and blocks private IP ranges.\n */\nfunction validateExternalUrl(urlStr: string): void {\n let parsed: URL\n try {\n parsed = new URL(urlStr)\n } catch {\n throw new Error(`Invalid URL: ${urlStr}`)\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error(`Blocked URL scheme: ${parsed.protocol}`)\n }\n\n const hostname = parsed.hostname\n // Block IPv6 loopback\n if (hostname === '::1' || hostname === '[::1]') {\n throw new Error('Blocked: loopback address')\n }\n\n // Resolve hostname to check for private IPs\n if (net.isIP(hostname)) {\n if (isPrivateIP(hostname)) {\n throw new Error(`Blocked: private IP address ${hostname}`)\n }\n } else {\n // For domain names, block common internal hostnames\n const lower = hostname.toLowerCase()\n if (lower === 'localhost' || lower.endsWith('.local') || lower.endsWith('.internal')) {\n throw new Error(`Blocked: internal hostname ${hostname}`)\n }\n }\n}\n\nfunction isPrivateIP(ip: string): boolean {\n // IPv4 private ranges\n const parts = ip.split('.').map(Number)\n if (parts.length === 4) {\n // 127.0.0.0/8\n if (parts[0] === 127) return true\n // 10.0.0.0/8\n if (parts[0] === 10) return true\n // 172.16.0.0/12\n if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true\n // 192.168.0.0/16\n if (parts[0] === 192 && parts[1] === 168) return true\n // 169.254.0.0/16 (link-local)\n if (parts[0] === 169 && parts[1] === 254) return true\n // 0.0.0.0\n if (parts.every(p => p === 0)) return true\n }\n return false\n}\n\nexport interface SvelteDevtoolsOptions {\n /**\n * Enable component tracking via code injection.\n * @default true\n */\n componentTracking?: boolean\n}\n\nexport function svelteDevtools(options: SvelteDevtoolsOptions = {}): Plugin[] {\n const { componentTracking = true } = options\n\n let config: ResolvedConfig\n let server: ViteDevServer | undefined\n let root: string\n // Per-process random token used by the HTTP fallback endpoint and asset\n // middleware to authenticate requests. Embedded into the DevTools client\n // HTML via a <meta> tag and required as `x-svelte-devtools-token`.\n // Combined with strict same-origin checks, this prevents arbitrary web\n // pages (and DNS-rebinding attacks against the dev server bound to\n // 0.0.0.0) from invoking inspect-file / open-in-editor / send-api-request.\n const devtoolsToken = crypto.randomUUID()\n\n // Resolve a user-supplied file path strictly under the project root.\n // Symlinks are followed via realpathSync so that symlinks inside the\n // project cannot be used to escape the root sandbox.\n // Throws if the resolved real path is outside the project root.\n function resolveWithinRoot(input: string): string {\n if (typeof input !== 'string' || input.length === 0) {\n throw new Error('Invalid file path')\n }\n const realRoot = fs.realpathSync(root)\n const candidate = path.isAbsolute(input) ? input : path.resolve(root, input)\n let real: string\n try {\n real = fs.realpathSync(candidate)\n } catch {\n throw new Error('File not found')\n }\n if (real !== realRoot && !real.startsWith(realRoot + path.sep)) {\n throw new Error('Forbidden: path outside project root')\n }\n return real\n }\n\n let liveComponents: ComponentInstance[] = []\n let renderProfiles: RenderProfile[] = []\n let loadProfiles: LoadProfile[] = []\n let reactiveGraph: ReactiveGraph = { nodes: [], edges: [] }\n let reactiveGraphResolvers: Array<(graph: ReactiveGraph) => void> = []\n // Phase 3\n let stateTimeline: StateChange[] = []\n let stateTimelineResolvers: Array<(changes: StateChange[]) => void> = []\n let compilerWarnings: CompilerWarning[] = []\n let runtimeErrors: RuntimeError[] = []\n let fpsSamples: FpsSample[] = []\n\n // Session store for AI-driven measurement workflows.\n // Built lazily after `root` is resolved.\n let sessions: SessionStore | null = null\n function getSessions(): SessionStore {\n if (!sessions) {\n sessions = new SessionStore({\n persistDir: path.join(root, 'node_modules', '.vite-devtools-svelte', 'sessions'),\n getters: {\n getRenderProfiles: () => renderProfiles,\n getLoadProfiles: () => loadProfiles,\n getFpsSamples: () => fpsSamples,\n },\n })\n }\n return sessions\n }\n\n // --- Shared RPC handler implementations ---\n // Used by both DevTools Kit RPC registration and HTTP fallback endpoint.\n // Lazily initialized once (handlers close over mutable state so a single instance works).\n let _rpcHandlers: Record<string, (...args: any[]) => Promise<unknown>> | null = null\n function getRpcHandlers(): Record<string, (...args: any[]) => Promise<unknown>> {\n if (_rpcHandlers) return _rpcHandlers\n _rpcHandlers = {\n 'svelte-devtools:get-project': async () => analyzeProject(root),\n\n 'svelte-devtools:get-routes': async () => {\n const projectInfo = analyzeProject(root)\n return analyzeRoutes(projectInfo.routesDir)\n },\n\n 'svelte-devtools:get-assets': async () => {\n const projectInfo = analyzeProject(root)\n return analyzeAssets(projectInfo.staticDir)\n },\n\n 'svelte-devtools:get-component-relations': async () => analyzeComponents(root),\n\n 'svelte-devtools:get-live-components': async () => liveComponents,\n\n 'svelte-devtools:open-in-editor': async (filePath: string, line?: number) => {\n const resolved = resolveWithinRoot(String(filePath))\n if (line && Number(line) > 0) {\n execFile('code', ['--goto', `${resolved}:${Number(line)}`])\n } else {\n execFile('code', [resolved])\n }\n },\n\n 'svelte-devtools:open-reactive-in-editor': async (\n filePath: string,\n name: string,\n type: string,\n ) => {\n const resolved = resolveWithinRoot(String(filePath))\n let line = 0\n try {\n const source = fs.readFileSync(resolved, 'utf-8')\n const lines = source.split('\\n')\n if (String(type) === 'effect') {\n // Find the $effect( declaration\n for (let i = 0; i < lines.length; i++) {\n if (lines[i].includes('$effect(') || lines[i].includes('$effect.pre(')) {\n line = i + 1\n break\n }\n }\n } else {\n // Find the variable declaration: let/const/var {name}\n const escaped = String(name).replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const regex = new RegExp(`(?:let|const|var)\\\\s+${escaped}\\\\b`)\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i])) {\n line = i + 1\n break\n }\n }\n }\n } catch {\n /* file not readable */\n }\n if (line > 0) {\n execFile('code', ['--goto', `${resolved}:${line}`])\n } else {\n execFile('code', [resolved])\n }\n },\n\n 'svelte-devtools:get-render-profiles': async () => renderProfiles,\n\n 'svelte-devtools:get-reactive-graph': async () => {\n if (!server) return reactiveGraph\n server.hot.send('svelte-devtools:request-reactive-graph', {})\n return new Promise<ReactiveGraph>(resolve => {\n let resolved = false\n const resolver = (graph: ReactiveGraph) => {\n if (!resolved) {\n resolved = true\n clearTimeout(timeout)\n resolve(graph)\n }\n }\n const timeout = setTimeout(() => {\n resolved = true\n // Remove this resolver to prevent memory leak\n const idx = reactiveGraphResolvers.indexOf(resolver)\n if (idx !== -1) reactiveGraphResolvers.splice(idx, 1)\n resolve(reactiveGraph)\n }, 1000)\n reactiveGraphResolvers.push(resolver)\n })\n },\n\n 'svelte-devtools:get-load-profiles': async () => loadProfiles,\n\n 'svelte-devtools:clear-load-profiles': async () => {\n loadProfiles = []\n },\n\n 'svelte-devtools:get-state-timeline': async () => {\n if (!server) return stateTimeline\n server.hot.send('svelte-devtools:request-state-timeline', {})\n return new Promise<StateChange[]>(resolve => {\n let resolved = false\n const resolver = (changes: StateChange[]) => {\n if (!resolved) {\n resolved = true\n clearTimeout(timeout)\n resolve(changes)\n }\n }\n const timeout = setTimeout(() => {\n resolved = true\n const idx = stateTimelineResolvers.indexOf(resolver)\n if (idx !== -1) stateTimelineResolvers.splice(idx, 1)\n resolve(stateTimeline)\n }, 1000)\n stateTimelineResolvers.push(resolver)\n })\n },\n\n 'svelte-devtools:clear-state-timeline': async () => {\n stateTimeline = []\n server?.hot.send('svelte-devtools:clear-state-timeline', {})\n },\n\n 'svelte-devtools:get-api-endpoints': async () => {\n const projectInfo = analyzeProject(root)\n const routes = analyzeRoutes(projectInfo.routesDir)\n const endpoints: ApiEndpoint[] = []\n for (const route of routes) {\n const serverFile = route.files.find(f => f.type === 'endpoint')\n if (serverFile) {\n let content = ''\n try {\n content = fs.readFileSync(serverFile.path, 'utf-8')\n } catch {\n /* file may not exist */\n }\n const methods: string[] = []\n for (const m of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) {\n if (\n content.includes(`export const ${m}`) ||\n content.includes(`export async function ${m}`) ||\n content.includes(`export function ${m}`)\n ) {\n methods.push(m)\n }\n }\n if (methods.length === 0) methods.push('GET')\n endpoints.push({ route: route.id, path: route.path, methods, file: serverFile.path })\n }\n }\n return endpoints\n },\n\n 'svelte-devtools:send-api-request': async (\n requestUrl: string,\n method: string,\n headers: string,\n body: string,\n ) => {\n const start = performance.now()\n try {\n validateExternalUrl(String(requestUrl))\n const parsedHeaders = headers ? JSON.parse(String(headers)) : {}\n const fetchOpts: RequestInit = { method: String(method), headers: parsedHeaders }\n if (body && String(method) !== 'GET' && String(method) !== 'HEAD')\n fetchOpts.body = String(body)\n const res = await fetch(String(requestUrl), fetchOpts)\n const resBody = await res.text()\n const resHeaders: Record<string, string> = {}\n res.headers.forEach((v, k) => {\n resHeaders[k] = v\n })\n return {\n status: res.status,\n statusText: res.statusText,\n headers: resHeaders,\n body: resBody,\n duration: Math.round((performance.now() - start) * 100) / 100,\n } as ApiResponse\n } catch (e) {\n return {\n status: 0,\n statusText: String(e),\n headers: {},\n body: '',\n duration: Math.round((performance.now() - start) * 100) / 100,\n } as ApiResponse\n }\n },\n\n 'svelte-devtools:get-compiler-warnings': async () => compilerWarnings,\n\n 'svelte-devtools:get-runtime-errors': async () => runtimeErrors,\n\n 'svelte-devtools:clear-errors': async () => {\n compilerWarnings = []\n runtimeErrors = []\n },\n\n 'svelte-devtools:get-svelte-files': async () => {\n const components = analyzeComponents(root)\n return components.map(c => ({ file: c.file, name: c.name }))\n },\n\n 'svelte-devtools:inspect-file': async (filePath: string) => {\n const fp = String(filePath)\n let resolved: string\n try {\n resolved = resolveWithinRoot(fp)\n } catch {\n return { source: '', compiled: '', file: fp } as InspectResult\n }\n let source = ''\n try {\n source = fs.readFileSync(resolved, 'utf-8')\n } catch {\n return { source: '', compiled: '', file: fp } as InspectResult\n }\n let compiled = ''\n let mappings: string | undefined\n let sources: string[] | undefined\n if (server) {\n try {\n const result = await server.transformRequest(resolved)\n compiled = result?.code || ''\n if (result?.map) {\n const map = typeof result.map === 'string' ? JSON.parse(result.map) : result.map\n mappings = map.mappings\n sources = map.sources\n }\n } catch {\n compiled = '// Transform failed'\n }\n }\n return { source, compiled, file: fp, mappings, sources } as InspectResult\n },\n\n 'svelte-devtools:get-module-graph': async () => getModuleGraph(),\n\n 'svelte-devtools:get-og-preview': async (url: string) => getOGPreview(String(url)),\n\n 'svelte-devtools:get-build-analysis': async () => getBuildAnalysis(),\n\n 'svelte-devtools:get-fps': async () => fpsSamples,\n\n 'svelte-devtools:clear-fps': async () => {\n fpsSamples = []\n },\n }\n return _rpcHandlers\n }\n\n const mainPlugin: Plugin = {\n name: 'vite-devtools-svelte',\n enforce: 'pre',\n\n // Vite plugins may expose data through `api` for inter-plugin (and test)\n // consumption. We surface the per-process auth token only — never the\n // RPC handlers themselves — so the test suite can attach the token to\n // mock requests without the production code needing a test-only flag.\n api: {\n getDevtoolsToken: () => devtoolsToken,\n },\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n root = config.root\n },\n\n configureServer(devServer) {\n server = devServer\n\n // Defensive caps on runtime-supplied data: even though the runtime\n // already trims its own buffers, an out-of-spec or compromised runtime\n // could hand us unbounded payloads and inflate dev-server memory.\n const MAX_LIVE_COMPONENTS = 5000\n const MAX_RENDER_PROFILES = 5000\n const MAX_STATE_TIMELINE = 500\n const MAX_REACTIVE_NODES = 5000\n const MAX_REACTIVE_EDGES = 20000\n\n server.hot.on('svelte-devtools:components', (data: { components: ComponentInstance[] }) => {\n const arr = Array.isArray(data?.components) ? data.components : []\n liveComponents = arr.length > MAX_LIVE_COMPONENTS ? arr.slice(-MAX_LIVE_COMPONENTS) : arr\n })\n\n server.hot.on('svelte-devtools:profiles', (data: { profiles: RenderProfile[] }) => {\n const arr = Array.isArray(data?.profiles) ? data.profiles : []\n renderProfiles = arr.length > MAX_RENDER_PROFILES ? arr.slice(-MAX_RENDER_PROFILES) : arr\n })\n\n server.hot.on('svelte-devtools:state-timeline', (data: { changes: StateChange[] }) => {\n const arr = Array.isArray(data?.changes) ? data.changes : []\n stateTimeline = arr.length > MAX_STATE_TIMELINE ? arr.slice(-MAX_STATE_TIMELINE) : arr\n // Snapshot then reset before resolving so concurrent requests that\n // push during the resolve loop are not silently dropped.\n const pending = stateTimelineResolvers\n stateTimelineResolvers = []\n for (const resolve of pending) resolve(stateTimeline)\n })\n\n server.hot.on('svelte-devtools:fps', (data: FpsSample) => {\n fpsSamples.push(data)\n if (fpsSamples.length > 1200) fpsSamples = fpsSamples.slice(-1200)\n getSessions().recordFpsSample(data)\n })\n\n server.hot.on('svelte-devtools:runtime-error', (data: RuntimeError) => {\n runtimeErrors.push(data)\n if (runtimeErrors.length > 200) runtimeErrors = runtimeErrors.slice(-200)\n })\n\n server.hot.on('svelte-devtools:reactive-graph', (data: ReactiveGraph) => {\n const nodes = Array.isArray(data?.nodes) ? data.nodes : []\n const edges = Array.isArray(data?.edges) ? data.edges : []\n reactiveGraph = {\n nodes: nodes.length > MAX_REACTIVE_NODES ? nodes.slice(0, MAX_REACTIVE_NODES) : nodes,\n edges: edges.length > MAX_REACTIVE_EDGES ? edges.slice(0, MAX_REACTIVE_EDGES) : edges,\n }\n const pending = reactiveGraphResolvers\n reactiveGraphResolvers = []\n for (const resolve of pending) resolve(reactiveGraph)\n })\n\n // Build the same-origin allow-list once. The dev server only serves\n // its own origin, so any cross-origin request to our endpoints is\n // rejected. This blocks both casual CSRF from arbitrary tabs and the\n // DNS-rebinding scenario where the dev server is bound to 0.0.0.0.\n const buildAllowedOrigins = (): Set<string> => {\n const set = new Set<string>()\n const serverCfg = server?.config?.server ?? config?.server\n const port = serverCfg?.port ?? 5173\n const proto = serverCfg?.https ? 'https' : 'http'\n for (const host of ['localhost', '127.0.0.1', '[::1]']) {\n set.add(`${proto}://${host}`)\n set.add(`${proto}://${host}:${port}`)\n }\n return set\n }\n\n const isAuthorizedRequest = (req: {\n headers: Record<string, string | string[] | undefined>\n }): boolean => {\n const allowed = buildAllowedOrigins()\n const origin = req.headers.origin\n const referer = req.headers.referer\n const sourceOrigin = (() => {\n if (typeof origin === 'string' && origin) return origin\n if (typeof referer === 'string' && referer) {\n try {\n return new URL(referer).origin\n } catch {\n return null\n }\n }\n return null\n })()\n // Same-origin browser requests sent by `fetch` from same-origin pages\n // typically include Origin; tests / curl may omit both — we still\n // require the explicit token header to compensate.\n if (sourceOrigin !== null && !allowed.has(sourceOrigin)) return false\n const tokenHeader = req.headers['x-svelte-devtools-token']\n const token = Array.isArray(tokenHeader) ? tokenHeader[0] : tokenHeader\n return token === devtoolsToken\n }\n\n // Serve the DevTools client UI. Inject the per-process token into\n // index.html as a <meta> tag so the client can attach it to RPC calls.\n const clientDir = path.resolve(__dirname, 'client')\n server.middlewares.use('/.svelte-devtools', (req, res, next) => {\n const reqUrl = req.url || '/'\n const urlPath = reqUrl.split('?')[0]\n const isIndex = urlPath === '/' || urlPath === '' || urlPath === '/index.html'\n const filePath = isIndex\n ? path.join(clientDir, 'index.html')\n : path.join(clientDir, urlPath)\n\n try {\n const stat = fs.statSync(filePath)\n if (stat.isFile()) {\n const ext = path.extname(filePath).toLowerCase()\n res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')\n if (isIndex) {\n const html = fs.readFileSync(filePath, 'utf-8')\n const tokenMeta = `<meta name=\"svelte-devtools-token\" content=\"${devtoolsToken}\">`\n const injected = html.includes('</head>')\n ? html.replace('</head>', ` ${tokenMeta}\\n</head>`)\n : `${tokenMeta}\\n${html}`\n res.end(injected)\n } else {\n fs.createReadStream(filePath).pipe(res)\n }\n return\n }\n } catch {\n /* file doesn't exist, fall through */\n }\n next()\n })\n\n // RPC fallback endpoint for when DevTools Kit RPC is not available.\n // Authorized via same-origin Origin/Referer + per-process token.\n server.middlewares.use('/__svelte-devtools/rpc', (req, res) => {\n if (req.method !== 'POST') {\n res.statusCode = 405\n res.end('Method not allowed')\n return\n }\n if (!isAuthorizedRequest(req as any)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n // Reject content types other than JSON to keep CSRF surface small.\n const ct = req.headers['content-type']\n const ctStr = Array.isArray(ct) ? ct[0] : ct\n if (!ctStr || !ctStr.includes('application/json')) {\n res.statusCode = 415\n res.end('Unsupported Media Type')\n return\n }\n\n let body = ''\n let aborted = false\n const MAX_BODY = 1_000_000 // 1 MB cap to avoid trivial DoS via huge requests\n req.on('data', (chunk: Buffer) => {\n if (aborted) return\n body += chunk.toString()\n if (body.length > MAX_BODY) {\n aborted = true\n res.statusCode = 413\n res.end('Payload Too Large')\n }\n })\n req.on('end', async () => {\n if (aborted) return\n try {\n const { method, args } = JSON.parse(body)\n const handlers = getRpcHandlers()\n const handler = handlers[method]\n if (!handler) throw new Error(`Unknown RPC method: ${method}`)\n const result = await handler(...args)\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(result))\n } catch (e) {\n res.statusCode = 500\n res.end(JSON.stringify({ error: String(e) }))\n }\n })\n })\n\n // Serve asset files for preview. Authorized via same-origin policy.\n server.middlewares.use('/__svelte-devtools/asset', (req, res) => {\n if (!isAuthorizedRequest(req as any)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n const reqUrl = req.url || ''\n const queryStart = reqUrl.indexOf('?')\n const queryString = queryStart >= 0 ? reqUrl.slice(queryStart) : ''\n const params = new URLSearchParams(queryString)\n const filePath = params.get('path')\n if (!filePath) {\n res.statusCode = 400\n res.end('Missing path parameter')\n return\n }\n\n // Security: only serve files from static dir (resolve symlinks to prevent traversal)\n const projectInfo = analyzeProject(root)\n const realStaticDir = fs.realpathSync(projectInfo.staticDir)\n const resolvedPath = path.resolve(filePath)\n let realPath: string\n try {\n realPath = fs.realpathSync(resolvedPath)\n } catch {\n res.statusCode = 404\n res.end('Not found')\n return\n }\n if (!realPath.startsWith(realStaticDir + path.sep) && realPath !== realStaticDir) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n\n try {\n const stat = fs.statSync(realPath)\n if (!stat.isFile()) throw new Error('Not a file')\n const ext = path.extname(realPath).toLowerCase()\n res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')\n fs.createReadStream(realPath).pipe(res)\n } catch {\n res.statusCode = 404\n res.end('Not found')\n }\n })\n\n // MCP endpoint: lets AI agents (Claude Code etc.) read metrics + run\n // measurement sessions over the Streamable HTTP transport. Auth reuses\n // the same per-process token; same-origin is *not* required because MCP\n // clients are local processes that don't run inside a browser tab and\n // can't be redirected by a hostile origin (they only speak to URLs the\n // user explicitly configured via `claude mcp add`).\n const mcpServerFactory = () =>\n buildMcpServer({\n getProject: () => analyzeProject(root),\n getRoutes: () => {\n const projectInfo = analyzeProject(root)\n return analyzeRoutes(projectInfo.routesDir)\n },\n getLiveComponents: () => liveComponents,\n getComponentRelations: () => analyzeComponents(root),\n getRenderProfiles: () => renderProfiles,\n getReactiveGraph: () =>\n getRpcHandlers()['svelte-devtools:get-reactive-graph']() as Promise<ReactiveGraph>,\n getLoadProfiles: () => loadProfiles,\n getFpsSamples: () => fpsSamples,\n sessions: getSessions(),\n })\n\n // Print a one-line `claude mcp add` snippet once the dev server is\n // actually listening — that's when we know the resolved port.\n devServer.httpServer?.once('listening', () => {\n try {\n const addr = devServer.httpServer?.address()\n if (!addr || typeof addr === 'string') return\n const proto = devServer.config.server?.https ? 'https' : 'http'\n // For wildcard / loopback bindings prefer the literal `localhost`\n // so the printed URL parses as-is. Brackets aren't enough for `::`\n // (wildcard) and `::1` is just a more verbose form of loopback.\n const loopbackOrWildcard =\n addr.address === '::' ||\n addr.address === '0.0.0.0' ||\n addr.address === '::1' ||\n addr.address === '127.0.0.1'\n const host = loopbackOrWildcard\n ? 'localhost'\n : addr.family === 'IPv6'\n ? `[${addr.address}]`\n : addr.address\n const url = `${proto}://${host}:${addr.port}/__svelte-devtools/mcp`\n const cmd = `claude mcp add --transport http svelte ${url} --header x-svelte-devtools-token:${devtoolsToken}`\n devServer.config.logger.info('')\n devServer.config.logger.info(` svelte-devtools MCP ready — register with Claude Code:`)\n devServer.config.logger.info(` ${cmd}`)\n devServer.config.logger.info('')\n } catch {\n /* logging is best-effort */\n }\n })\n\n server.middlewares.use('/__svelte-devtools/mcp', async (req, res) => {\n const tokenHeader = req.headers['x-svelte-devtools-token']\n const token = Array.isArray(tokenHeader) ? tokenHeader[0] : tokenHeader\n if (token !== devtoolsToken) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n // Build a fresh server+transport per request. Stateless mode in the\n // SDK still keeps per-instance bookkeeping that gets corrupted when\n // the same transport handles multiple requests, so reusing one\n // breaks the second call onward.\n const mcpServer = mcpServerFactory()\n const mcpTransport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: true,\n })\n mcpTransport.onerror = err => {\n devServer.config.logger.error(\n `[svelte-devtools] MCP transport error: ${err.stack || err.message}`,\n )\n }\n try {\n await mcpServer.connect(mcpTransport)\n // The SDK consumes the request body via @hono/node-server inside\n // handleRequest; pre-reading would leave the stream empty.\n await mcpTransport.handleRequest(req as any, res as any)\n } catch (e) {\n devServer.config.logger.error(\n `[svelte-devtools] MCP handler error: ${\n e instanceof Error ? e.stack || e.message : String(e)\n }`,\n )\n if (!res.headersSent) {\n res.statusCode = 500\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ error: String(e) }))\n }\n } finally {\n await mcpTransport.close().catch(() => {})\n await mcpServer.close().catch(() => {})\n }\n })\n },\n\n // Virtual module resolution: runtime + svelte/internal/client wrapper.\n // dev only — never resolve our virtual modules during production build.\n resolveId(id, importer) {\n if (config?.command !== 'serve') return undefined\n if (id === RUNTIME_MODULE_ID) return RESOLVED_RUNTIME_ID\n if (\n componentTracking &&\n id === 'svelte/internal/client' &&\n importer &&\n !importer.includes('node_modules') &&\n !importer.startsWith('\\0')\n ) {\n return WRAPPER_MODULE_ID\n }\n return undefined\n },\n\n load(id) {\n if (config?.command !== 'serve') return undefined\n if (id === RESOLVED_RUNTIME_ID) return runtimeCode\n if (id === WRAPPER_MODULE_ID) return wrapperCode\n return undefined\n },\n\n // Inject the runtime into the user's app\n transformIndexHtml() {\n if (config.command !== 'serve') return []\n return [\n {\n tag: 'script',\n attrs: { type: 'module' },\n children: `import '${RUNTIME_MODULE_ID}'`,\n injectTo: 'head-prepend',\n },\n ]\n },\n\n // DevTools integration\n devtools: {\n setup(ctx) {\n const clientDir = path.resolve(__dirname, 'client')\n ctx.views.hostStatic('/.svelte-devtools/', clientDir)\n\n ctx.docks.register({\n id: 'svelte-devtools',\n title: 'Svelte',\n icon: 'simple-icons:svelte',\n type: 'iframe',\n url: '/.svelte-devtools/',\n category: 'framework',\n })\n\n // Register all RPC functions from shared handlers\n const handlers = getRpcHandlers()\n for (const [name, handler] of Object.entries(handlers)) {\n ctx.rpc.register({ name, handler })\n }\n },\n },\n }\n\n // --- Phase 4 helper functions ---\n\n function getModuleGraph(): ModuleGraphData {\n if (!server) return { modules: [], cycles: [] }\n const modules: ModuleNode[] = []\n const idMap = new Map<string, ModuleNode>()\n const moduleById = new Map<string, ModuleNode>()\n\n // Try different Vite moduleGraph APIs (v8 uses environments)\n const allModules: Array<{ file?: string | null; importedModules: Set<any> }> = []\n try {\n // Vite 8: use environments\n for (const env of Object.values(server.environments || {})) {\n if (env && 'moduleGraph' in env) {\n const mg = (env as any).moduleGraph\n if (mg?.idToModuleMap) {\n for (const mod of mg.idToModuleMap.values()) allModules.push(mod)\n }\n }\n }\n } catch {\n /* ignore */\n }\n\n // Fallback: try legacy moduleGraph\n if (allModules.length === 0) {\n try {\n const mg = (server as any).moduleGraph\n if (mg?.idToModuleMap) {\n for (const mod of mg.idToModuleMap.values()) allModules.push(mod)\n }\n } catch {\n /* ignore */\n }\n }\n\n for (const mod of allModules) {\n if (!mod.file || mod.file.includes('node_modules')) continue\n const relFile = path.relative(root, mod.file)\n if (relFile.startsWith('..')) continue\n if (idMap.has(mod.file)) continue // deduplicate\n const ext = path.extname(mod.file).toLowerCase()\n const type =\n ext === '.svelte'\n ? 'svelte'\n : ext === '.ts' || ext === '.js'\n ? ext === '.ts'\n ? 'ts'\n : 'js'\n : ext === '.css'\n ? 'css'\n : 'other'\n let size: number | undefined\n try {\n size = fs.statSync(mod.file).size\n } catch {\n /* ignore */\n }\n const node: ModuleNode = {\n id: relFile,\n file: mod.file,\n type: type as ModuleNode['type'],\n importedBy: [],\n imports: [],\n size,\n }\n idMap.set(mod.file, node)\n moduleById.set(relFile, node)\n modules.push(node)\n }\n\n // Build edges using Sets for O(1) dedup\n for (const mod of allModules) {\n if (!mod.file || !idMap.has(mod.file)) continue\n const node = idMap.get(mod.file)!\n const importsSet = new Set(node.imports)\n for (const imp of mod.importedModules) {\n if (imp.file && idMap.has(imp.file)) {\n const impNode = idMap.get(imp.file)!\n const relImp = impNode.id\n if (!importsSet.has(relImp)) {\n importsSet.add(relImp)\n node.imports.push(relImp)\n }\n if (!impNode.importedBy.includes(node.id)) {\n impNode.importedBy.push(node.id)\n }\n }\n }\n }\n\n // Detect cycles (DFS) using Map for O(1) node lookup, push/pop to avoid array copies\n const cycles: string[][] = []\n const visited = new Set<string>()\n const stack = new Set<string>()\n const pathBuf: string[] = []\n function dfs(id: string) {\n if (stack.has(id)) {\n const cycleStart = pathBuf.indexOf(id)\n if (cycleStart >= 0 && pathBuf.length - cycleStart > 0) {\n const cycle = pathBuf.slice(cycleStart).concat(id)\n if (cycle.length > 2) cycles.push(cycle) // skip self-references\n }\n return\n }\n if (visited.has(id)) return\n visited.add(id)\n stack.add(id)\n pathBuf.push(id)\n const node = moduleById.get(id)\n if (node) for (const imp of node.imports) dfs(imp)\n pathBuf.pop()\n stack.delete(id)\n }\n for (const m of modules) dfs(m.id)\n\n // Mark cyclic modules\n const cyclicIds = new Set(cycles.flat())\n for (const m of modules) if (cyclicIds.has(m.id)) m.isCyclic = true\n\n return { modules, cycles }\n }\n\n async function getOGPreview(url: string): Promise<OGPreview> {\n const preview: OGPreview = { url, title: '', description: '', image: '', tags: [], issues: [] }\n try {\n validateExternalUrl(url)\n const res = await fetch(url)\n const html = await res.text()\n // Parse meta tags (attribute-order independent; matches both <meta ...> and <meta ... />)\n const metaRegex = /<meta\\s+([^>]*?)\\/?>/gi\n const propRegex = /(?:property|name)=[\"']([^\"']+)[\"']/\n const contentRegex = /content=[\"']([^\"']+)[\"']/\n let match\n while ((match = metaRegex.exec(html)) !== null) {\n const attrs = match[1]\n const propMatch = attrs.match(propRegex)\n const contentMatch = attrs.match(contentRegex)\n if (propMatch && contentMatch) {\n const prop = propMatch[1]\n const content = contentMatch[1]\n preview.tags.push({ property: prop, content })\n if (prop === 'og:title') preview.title = content\n else if (prop === 'og:description') preview.description = content\n else if (prop === 'og:image') preview.image = content\n }\n }\n // Fallback title\n if (!preview.title) {\n const titleMatch = html.match(/<title>([^<]+)<\\/title>/i)\n if (titleMatch) preview.title = titleMatch[1]\n }\n // Fallback description\n if (!preview.description) {\n const descTag = preview.tags.find(t => t.property === 'description')\n if (descTag) preview.description = descTag.content\n }\n // Issues\n if (!preview.title) preview.issues.push('Missing og:title or <title>')\n if (!preview.description) preview.issues.push('Missing og:description or meta description')\n if (!preview.image) preview.issues.push('Missing og:image')\n if (!preview.tags.some(t => t.property === 'og:url')) preview.issues.push('Missing og:url')\n if (!preview.tags.some(t => t.property === 'og:type')) preview.issues.push('Missing og:type')\n } catch (e) {\n preview.issues.push(`Failed to fetch: ${String(e)}`)\n }\n return preview\n }\n\n function getBuildAnalysis(): BuildAnalysis {\n const buildDir = path.resolve(root, '.svelte-kit/output')\n const clientDir = path.resolve(root, 'build/client') // common SvelteKit build output\n const chunks: BuildChunk[] = []\n\n // Try to find built assets\n for (const dir of [buildDir, clientDir, path.resolve(root, 'build')]) {\n try {\n const walkDir = (d: string) => {\n for (const entry of fs.readdirSync(d, { withFileTypes: true })) {\n const full = path.join(d, entry.name)\n if (entry.isDirectory()) {\n walkDir(full)\n continue\n }\n const ext = path.extname(entry.name).toLowerCase()\n if (['.js', '.css', '.html'].includes(ext)) {\n const stat = fs.statSync(full)\n chunks.push({\n name: entry.name,\n file: path.relative(root, full),\n size: stat.size,\n modules: [],\n isEntry: entry.name.includes('index') || entry.name.includes('start'),\n })\n }\n }\n }\n walkDir(dir)\n } catch {\n /* directory doesn't exist or not readable */\n }\n }\n\n chunks.sort((a, b) => b.size - a.size)\n return { chunks, totalSize: chunks.reduce((s, c) => s + c.size, 0), timestamp: Date.now() }\n }\n\n // Minimal component tracking transform plugin.\n // Only injects the file path before $.push() so the runtime wrapper knows\n // which component file is being initialized. All reactive tracking (state,\n // derived, proxy, effect) is handled by the svelte/internal/client wrapper.\n const trackingPlugin: Plugin = {\n name: 'vite-devtools-svelte:tracking',\n enforce: 'post',\n\n transform(code, id) {\n if (!componentTracking) return null\n if (!id.endsWith('.svelte')) return null\n if (id.includes('node_modules')) return null\n if (config?.command !== 'serve') return null\n if (!code.includes('$.push(')) return null\n\n const safeId = JSON.stringify(id)\n\n const importLine = `import '${RUNTIME_MODULE_ID}';\\n`\n\n const modified =\n importLine +\n code.replace(\n /(\\$\\.push\\([^)]+\\);?)/,\n `if (typeof window !== 'undefined' && window.__SVELTE_DEVTOOLS__) { window.__SVELTE_DEVTOOLS__._pendingFile = ${safeId}; }\\n$1`,\n )\n\n return { code: modified, map: null }\n },\n }\n\n // Load function profiling transform plugin\n const loadProfilePlugin: Plugin = {\n name: 'vite-devtools-svelte:load-profile',\n enforce: 'post',\n\n transform(code, id) {\n if (config?.command !== 'serve') return null\n // Only transform SvelteKit load files\n const isServerLoad = /\\+page\\.server\\.[tj]s$/.test(id) || /\\+layout\\.server\\.[tj]s$/.test(id)\n const isUniversalLoad = /\\+(page|layout)\\.[tj]s$/.test(id) && !id.includes('.server.')\n if (!isServerLoad && !isUniversalLoad) return null\n if (id.includes('node_modules')) return null\n // Must have an exported load function\n if (!code.includes('export') || !code.includes('load')) return null\n\n const loadType = isServerLoad ? 'server' : 'universal'\n // Determine route from file path\n const routesMatch = id.match(/routes(.*)\\/\\+/)\n const route = routesMatch ? routesMatch[1] || '/' : '/'\n const safeRoute = JSON.stringify(route)\n const safeFile = JSON.stringify(id)\n const safeType = JSON.stringify(loadType)\n\n // Replace the exported load function with a profiled version.\n // Supports both `export const load = ...` and `export (async) function load(...)` patterns.\n let transformed = code.replace(/export\\s+const\\s+load\\s*=\\s*/, `const __original_load = `)\n\n if (transformed === code) {\n // Try `export function load` / `export async function load` pattern\n transformed = code.replace(\n /export\\s+(async\\s+)?function\\s+load\\s*\\(/,\n `const __original_load = $1function __load_impl(`,\n )\n }\n\n if (transformed === code) return null // no match found\n\n const profiledExport = `\nexport const load = async (event) => {\n const __start = performance.now();\n const __result = await __original_load(event);\n const __duration = performance.now() - __start;\n const __dataSize = JSON.stringify(__result || {}).length;\n if (typeof globalThis.__svelte_devtools_record_load === 'function') {\n globalThis.__svelte_devtools_record_load(${safeRoute}, ${safeFile}, ${safeType}, __duration, __dataSize);\n }\n return __result;\n};\n`\n return { code: transformed + profiledExport, map: null }\n },\n }\n\n // Register load profiling hook on server\n const loadProfileServerPlugin: Plugin = {\n name: 'vite-devtools-svelte:load-profile-server',\n\n configureServer() {\n // Make the recording function available globally on the server\n ;(globalThis as Record<string, unknown>).__svelte_devtools_record_load = (\n route: string,\n file: string,\n type: string,\n duration: number,\n dataSize: number,\n ) => {\n const entry: LoadProfile = {\n route,\n file,\n type: type as 'server' | 'universal',\n duration: Math.round(duration * 100) / 100,\n dataSize,\n timestamp: Date.now(),\n }\n loadProfiles.push(entry)\n // Keep only last 200 entries\n if (loadProfiles.length > 200) {\n loadProfiles = loadProfiles.slice(-200)\n }\n getSessions().recordLoadProfile(entry)\n }\n },\n }\n\n // Compiler warning capture plugin\n const warningCapturePlugin: Plugin = {\n name: 'vite-devtools-svelte:warning-capture',\n enforce: 'post',\n\n configResolved(resolvedConfig) {\n // Intercept Svelte compiler warnings from the logger\n const originalWarn = resolvedConfig.logger.warn\n resolvedConfig.logger.warn = (msg: string, options?: { timestamp?: boolean }) => {\n // Svelte compiler warnings usually contain file paths and codes\n if (msg.includes('.svelte') && config?.command === 'serve') {\n const fileMatch = msg.match(/(?:^|\\s)((?:\\/|\\.\\/|\\w:)[^\\s:]+\\.svelte)(?::(\\d+):(\\d+))?/)\n const codeMatch = msg.match(/\\(([a-z0-9_-]+)\\)/)\n compilerWarnings.push({\n code: codeMatch?.[1] || 'unknown',\n // oxlint-disable-next-line no-control-regex -- intentional: strip ANSI escape sequences\n message: msg.replace(/\\x1b\\[[0-9;]*m/g, '').trim(),\n file: fileMatch?.[1] || '',\n line: fileMatch?.[2] ? parseInt(fileMatch[2]) : undefined,\n column: fileMatch?.[3] ? parseInt(fileMatch[3]) : undefined,\n })\n if (compilerWarnings.length > 500) compilerWarnings = compilerWarnings.slice(-500)\n }\n originalWarn(msg, options)\n }\n },\n }\n\n return [\n mainPlugin,\n trackingPlugin,\n loadProfilePlugin,\n loadProfileServerPlugin,\n warningCapturePlugin,\n sveltekitTemplateInjector(),\n ]\n}\n"],"mappings":"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"}