vite-devtools-svelte 0.1.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.
- package/dist/analyzers/assets.d.ts +3 -0
- package/dist/analyzers/components.d.ts +2 -0
- package/dist/analyzers/project.d.ts +2 -0
- package/dist/analyzers/routes.d.ts +2 -0
- package/dist/client/assets/client-jp6K3SZs.js +4 -0
- package/dist/client/assets/index-BjOa4UgY.js +6 -0
- package/dist/client/assets/index-D-ChuYqP.css +1 -0
- package/dist/client/index.html +46 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +855 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugin.d.ts +9 -0
- package/dist/runtime.d.ts +17 -0
- package/dist/types.d.ts +176 -0
- package/package.json +62 -0
|
@@ -0,0 +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/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","/// <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 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 // --- 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 })\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\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 loadProfiles.push({\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 // Keep only last 200 entries\n if (loadProfiles.length > 200) {\n loadProfiles = loadProfiles.slice(-200)\n }\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 ]\n}\n"],"mappings":"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"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
export interface SvelteDevtoolsOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Enable component tracking via code injection.
|
|
5
|
+
* @default true
|
|
6
|
+
*/
|
|
7
|
+
componentTracking?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function svelteDevtools(options?: SvelteDevtoolsOptions): Plugin[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const RUNTIME_MODULE_ID = "virtual:svelte-devtools-runtime";
|
|
2
|
+
export declare const RESOLVED_RUNTIME_ID: string;
|
|
3
|
+
export declare const WRAPPER_MODULE_ID = "\0svelte-devtools:wrapped-client";
|
|
4
|
+
/**
|
|
5
|
+
* Wrapper code for svelte/internal/client.
|
|
6
|
+
*
|
|
7
|
+
* Re-exports everything from the real module, then overrides:
|
|
8
|
+
* - push/pop: component lifecycle tracking
|
|
9
|
+
* - tag/tag_proxy: named signal/proxy tracking (Svelte dev mode)
|
|
10
|
+
* - state/derived/proxy: type markers consumed by tag/tag_proxy
|
|
11
|
+
* - user_effect/user_pre_effect: effect tracking
|
|
12
|
+
*
|
|
13
|
+
* This single module replaces all post-compilation regex transforms
|
|
14
|
+
* for reactive tracking, making the approach Svelte-compiler-output agnostic.
|
|
15
|
+
*/
|
|
16
|
+
export declare const wrapperCode = "\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";
|
|
17
|
+
export declare const runtimeCode = "\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";
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
export interface RouteInfo {
|
|
2
|
+
id: string;
|
|
3
|
+
path: string;
|
|
4
|
+
pattern: string;
|
|
5
|
+
segments: string[];
|
|
6
|
+
hasPage: boolean;
|
|
7
|
+
hasLayout: boolean;
|
|
8
|
+
hasServerPage: boolean;
|
|
9
|
+
hasServerLayout: boolean;
|
|
10
|
+
hasEndpoint: boolean;
|
|
11
|
+
hasPageLoad: boolean;
|
|
12
|
+
hasLayoutLoad: boolean;
|
|
13
|
+
params: ParamInfo[];
|
|
14
|
+
files: RouteFile[];
|
|
15
|
+
}
|
|
16
|
+
export interface ParamInfo {
|
|
17
|
+
name: string;
|
|
18
|
+
optional: boolean;
|
|
19
|
+
rest: boolean;
|
|
20
|
+
matcher?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface RouteFile {
|
|
23
|
+
type: 'page' | 'layout' | 'server-page' | 'server-layout' | 'endpoint' | 'page-load' | 'layout-load' | 'error' | 'page-load-server' | 'layout-load-server';
|
|
24
|
+
path: string;
|
|
25
|
+
}
|
|
26
|
+
export interface AssetInfo {
|
|
27
|
+
name: string;
|
|
28
|
+
path: string;
|
|
29
|
+
relativePath: string;
|
|
30
|
+
size: number;
|
|
31
|
+
type: string;
|
|
32
|
+
mtime: number;
|
|
33
|
+
}
|
|
34
|
+
export interface ProjectInfo {
|
|
35
|
+
name: string;
|
|
36
|
+
version: string;
|
|
37
|
+
svelteVersion: string;
|
|
38
|
+
sveltekitVersion: string;
|
|
39
|
+
viteVersion: string;
|
|
40
|
+
dependencies: Record<string, string>;
|
|
41
|
+
devDependencies: Record<string, string>;
|
|
42
|
+
routesDir: string;
|
|
43
|
+
staticDir: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ComponentRelation {
|
|
46
|
+
file: string;
|
|
47
|
+
name: string;
|
|
48
|
+
imports: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface ComponentInstance {
|
|
51
|
+
id: number;
|
|
52
|
+
file: string;
|
|
53
|
+
name: string;
|
|
54
|
+
parentId: number | null;
|
|
55
|
+
mounted: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface RenderProfile {
|
|
58
|
+
componentId: number;
|
|
59
|
+
file: string;
|
|
60
|
+
name: string;
|
|
61
|
+
initTime: number;
|
|
62
|
+
renderCount: number;
|
|
63
|
+
totalRenderTime: number;
|
|
64
|
+
lastRenderTime: number;
|
|
65
|
+
lastRenderAt: number;
|
|
66
|
+
}
|
|
67
|
+
export interface ReactiveNode {
|
|
68
|
+
id: string;
|
|
69
|
+
type: 'state' | 'derived' | 'effect';
|
|
70
|
+
name: string;
|
|
71
|
+
componentId: number;
|
|
72
|
+
componentFile: string;
|
|
73
|
+
value?: unknown;
|
|
74
|
+
}
|
|
75
|
+
export interface ReactiveEdge {
|
|
76
|
+
from: string;
|
|
77
|
+
to: string;
|
|
78
|
+
}
|
|
79
|
+
export interface ReactiveGraph {
|
|
80
|
+
nodes: ReactiveNode[];
|
|
81
|
+
edges: ReactiveEdge[];
|
|
82
|
+
}
|
|
83
|
+
export interface LoadProfile {
|
|
84
|
+
route: string;
|
|
85
|
+
file: string;
|
|
86
|
+
type: 'server' | 'universal';
|
|
87
|
+
duration: number;
|
|
88
|
+
dataSize: number;
|
|
89
|
+
timestamp: number;
|
|
90
|
+
}
|
|
91
|
+
export interface StateChange {
|
|
92
|
+
id: string;
|
|
93
|
+
name: string;
|
|
94
|
+
componentFile: string;
|
|
95
|
+
oldValue: unknown;
|
|
96
|
+
newValue: unknown;
|
|
97
|
+
timestamp: number;
|
|
98
|
+
}
|
|
99
|
+
export interface ApiEndpoint {
|
|
100
|
+
route: string;
|
|
101
|
+
path: string;
|
|
102
|
+
methods: string[];
|
|
103
|
+
file: string;
|
|
104
|
+
}
|
|
105
|
+
export interface ApiResponse {
|
|
106
|
+
status: number;
|
|
107
|
+
statusText: string;
|
|
108
|
+
headers: Record<string, string>;
|
|
109
|
+
body: string;
|
|
110
|
+
duration: number;
|
|
111
|
+
}
|
|
112
|
+
export interface CompilerWarning {
|
|
113
|
+
code: string;
|
|
114
|
+
message: string;
|
|
115
|
+
file: string;
|
|
116
|
+
line?: number;
|
|
117
|
+
column?: number;
|
|
118
|
+
}
|
|
119
|
+
export interface RuntimeError {
|
|
120
|
+
message: string;
|
|
121
|
+
file?: string;
|
|
122
|
+
line?: number;
|
|
123
|
+
column?: number;
|
|
124
|
+
stack?: string;
|
|
125
|
+
timestamp: number;
|
|
126
|
+
}
|
|
127
|
+
export interface InspectResult {
|
|
128
|
+
source: string;
|
|
129
|
+
compiled: string;
|
|
130
|
+
file: string;
|
|
131
|
+
/** VLQ-encoded source map `mappings` string (per the Source Map v3 spec). */
|
|
132
|
+
mappings?: string;
|
|
133
|
+
/** Source map sources array */
|
|
134
|
+
sources?: string[];
|
|
135
|
+
}
|
|
136
|
+
export interface ModuleNode {
|
|
137
|
+
id: string;
|
|
138
|
+
file: string;
|
|
139
|
+
type: 'svelte' | 'js' | 'ts' | 'css' | 'other';
|
|
140
|
+
importedBy: string[];
|
|
141
|
+
imports: string[];
|
|
142
|
+
isCyclic?: boolean;
|
|
143
|
+
size?: number;
|
|
144
|
+
}
|
|
145
|
+
export interface ModuleGraphData {
|
|
146
|
+
modules: ModuleNode[];
|
|
147
|
+
cycles: string[][];
|
|
148
|
+
}
|
|
149
|
+
export interface OGTag {
|
|
150
|
+
property: string;
|
|
151
|
+
content: string;
|
|
152
|
+
}
|
|
153
|
+
export interface OGPreview {
|
|
154
|
+
url: string;
|
|
155
|
+
title: string;
|
|
156
|
+
description: string;
|
|
157
|
+
image: string;
|
|
158
|
+
tags: OGTag[];
|
|
159
|
+
issues: string[];
|
|
160
|
+
}
|
|
161
|
+
export interface BuildChunk {
|
|
162
|
+
name: string;
|
|
163
|
+
file: string;
|
|
164
|
+
size: number;
|
|
165
|
+
modules: string[];
|
|
166
|
+
isEntry: boolean;
|
|
167
|
+
}
|
|
168
|
+
export interface BuildAnalysis {
|
|
169
|
+
chunks: BuildChunk[];
|
|
170
|
+
totalSize: number;
|
|
171
|
+
timestamp: number;
|
|
172
|
+
}
|
|
173
|
+
export interface FpsSample {
|
|
174
|
+
timestamp: number;
|
|
175
|
+
fps: number;
|
|
176
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-devtools-svelte",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Svelte DevTools plugin for Vite DevTools",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Yuichiro Yamashita",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/baseballyama/vite-devtools-svelte.git",
|
|
10
|
+
"directory": "packages/vite-devtools-svelte"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/baseballyama/vite-devtools-svelte#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/baseballyama/vite-devtools-svelte/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"vite",
|
|
18
|
+
"vite-plugin",
|
|
19
|
+
"vite-devtools",
|
|
20
|
+
"svelte",
|
|
21
|
+
"sveltekit",
|
|
22
|
+
"devtools"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=22.0.0"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"type": "module",
|
|
31
|
+
"main": "./dist/index.mjs",
|
|
32
|
+
"module": "./dist/index.mjs",
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"import": "./dist/index.mjs",
|
|
37
|
+
"types": "./dist/index.d.ts"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "vite build",
|
|
45
|
+
"dev": "vite build --watch",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@vitejs/devtools-kit": "^0.1.21"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^25.6.2",
|
|
54
|
+
"typescript": "^6.0.3",
|
|
55
|
+
"vite": "^8.0.0",
|
|
56
|
+
"vite-plugin-dts": "^4.5.4",
|
|
57
|
+
"vitest": "^3.0.0"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"vite": "^8.0.0"
|
|
61
|
+
}
|
|
62
|
+
}
|