@xiaou66/vite-plugin-vue-mcp-next 1.2.0 → 1.3.1

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,"sources":["../../src/runtime/client.ts","../../src/runtime/consoleHook.ts","../../src/shared/serialization.ts","../../src/runtime/networkHook.ts","../../src/shared/sanitize.ts","../../src/shared/url.ts","../../src/runtime/pageIdentity.ts","../../src/runtime/performanceHook.ts","../../src/shared/limits.ts","../../src/constants.ts","../../src/performance/summary.ts","../../src/runtime/screenshot.ts","../../src/runtime/vueBridge.ts","../../src/runtime/domSnapshot.ts","../../src/runtime/evaluateExpression.ts","../../src/runtime/storageBridge.ts","../../src/runtime/devtoolsBridge.ts"],"sourcesContent":["/**\n * Runtime Client 是注入到浏览器页面的启动入口。\n *\n * 该文件负责协调 Vue、Console、Network 等浏览器端 hook 的安装,并通过 Vite hot context 上报页面状态。\n */\nimport { createHotContext } from 'vite-hot-client'\nimport { installConsoleHook } from './consoleHook'\nimport { installNetworkHook } from './networkHook'\nimport { getRuntimeClientId, getRuntimePageIdentity } from './pageIdentity'\nimport { installPerformanceHook } from './performanceHook'\nexport { setScreenshotModuleRegistry, setSnapdomLoader } from './screenshot'\nimport { initializeVueDevtoolsHook, installVueBridge } from './vueBridge'\nexport { evaluateExpression } from './evaluateExpression'\nexport type { RuntimeEvaluateRequest } from './evaluateExpression'\n\n/**\n * 启动浏览器端 Runtime Bridge。\n *\n * Vue Devtools hook 必须在等待 Vite hot context 前同步初始化,否则 Vue app 挂载时会错过注册窗口。\n */\nexport async function startRuntimeClient(): Promise<void> {\n initializeVueDevtoolsHook()\n\n const hot = await createHotContext('vite-plugin-vue-mcp-next', '/')\n\n if (!hot) {\n return\n }\n\n installVueBridge(hot)\n\n const identity = getRuntimePageIdentity({\n href: window.location.href,\n title: document.title,\n runtimeClientId: getRuntimeClientId(window.sessionStorage, window),\n innerWidth: window.innerWidth,\n innerHeight: window.innerHeight,\n readyState: document.readyState\n })\n\n hot.send('vite-plugin-vue-mcp-next:page-connected', identity)\n installPerformanceHook({\n pageId: identity.pageId,\n send(report) {\n hot.send('vite-plugin-vue-mcp-next:performance-record', report)\n }\n })\n installConsoleHook({\n pageId: identity.pageId,\n send(record) {\n hot.send('vite-plugin-vue-mcp-next:console-record', record)\n }\n })\n installNetworkHook({\n pageId: identity.pageId,\n maxBodySize: 100_000,\n maskHeaders: ['authorization', 'cookie', 'set-cookie'],\n send(record) {\n hot.send('vite-plugin-vue-mcp-next:network-record', record)\n }\n })\n}\n","import { nanoid } from 'nanoid'\nimport { safeStringify } from '../shared/serialization'\nimport type { ConsoleRecord } from '../types'\n\n/**\n * Console Hook 安装参数。\n *\n * Hook 运行在浏览器页面内,需要通过 send 回调交给 Vite WebSocket,而不是直接依赖服务器模块。\n */\nexport interface ConsoleHookOptions {\n /** 当前页面 ID,用于服务端区分多页面日志来源。 */\n readonly pageId: string\n /** 发送规范化日志记录的回调,由 runtime client 绑定到 Vite WebSocket。 */\n readonly send: (record: ConsoleRecord) => void\n}\n\n/**\n * 安装页面 Console 和错误 Hook。\n *\n * 即使启用 CDP,也保留该 Hook,因为早期日志可能发生在 CDP target 匹配完成之前。\n */\nexport function installConsoleHook(options: ConsoleHookOptions): () => void {\n const originalConsole = {\n log: console.log,\n info: console.info,\n warn: console.warn,\n error: console.error,\n debug: console.debug\n }\n\n const emit = (level: ConsoleRecord['level'], args: unknown[]): void => {\n options.send({\n id: nanoid(),\n pageId: options.pageId,\n source: 'hook',\n level,\n message: args.map((arg) => safeStringify(arg)).join(' '),\n args,\n timestamp: Date.now()\n })\n }\n\n ;(['log', 'info', 'warn', 'error', 'debug'] as const).forEach((level) => {\n console[level] = (...args: unknown[]) => {\n emit(level, args)\n originalConsole[level](...args)\n }\n })\n\n const onError = (event: ErrorEvent): void => {\n options.send({\n id: nanoid(),\n pageId: options.pageId,\n source: 'hook',\n level: 'error',\n message: event.message,\n stack: event.error instanceof Error ? event.error.stack : undefined,\n timestamp: Date.now()\n })\n }\n\n window.addEventListener('error', onError)\n\n return () => {\n Object.assign(console, originalConsole)\n window.removeEventListener('error', onError)\n }\n}\n","/**\n * 将未知值转换为适合 MCP 文本输出的字符串。\n *\n * Console 参数、脚本执行结果和 Network body 都可能包含循环引用,统一序列化能避免工具调用崩溃。\n */\nexport function safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value\n }\n\n const seen = new WeakSet()\n\n const serialized = JSON.stringify(\n value,\n (_key: string, current: unknown): unknown => {\n if (typeof current !== 'object' || current === null) {\n return current\n }\n\n if (seen.has(current)) {\n return '[Circular]'\n }\n\n seen.add(current)\n return current\n }\n )\n\n return serialized\n}\n","import { nanoid } from 'nanoid'\nimport { maskHeaders, truncateText } from '../shared/sanitize'\nimport { parseRequestQuery } from '../shared/url'\nimport type { NetworkRecord } from '../types'\n\n/**\n * Hook Network 记录创建参数。\n *\n * 将记录创建抽成纯函数,便于测试脱敏、query 解析和字段标准化。\n */\nexport interface HookNetworkRecordInput {\n /** 当前页面 ID,用于服务端区分多页面请求来源。 */\n readonly pageId: string\n /** 请求 URL,用于记录接口地址和解析 query 参数。 */\n readonly url: string\n /** HTTP 方法,Hook 会从 fetch init 或 XHR open 中提取。 */\n readonly method: string\n /** 请求头快照,采集前会按 maskHeaders 脱敏。 */\n readonly requestHeaders?: Record<string, string>\n /** 请求体快照,用于调试提交参数。 */\n readonly requestBody?: unknown\n /** 需要脱敏的 header 名称。 */\n readonly maskHeaders: readonly string[]\n /** 请求开始时间,用于后续计算耗时。 */\n readonly startedAt: number\n}\n\n/**\n * Network Hook 安装参数。\n *\n * Hook 运行在浏览器页面内,通过 send 回调把记录交给 Vite WebSocket。\n */\nexport interface NetworkHookOptions {\n /** 当前页面 ID,用于服务端区分多页面请求来源。 */\n readonly pageId: string\n /** 请求体和响应体最大采集长度,避免大响应污染 MCP 上下文。 */\n readonly maxBodySize: number\n /** 需要脱敏的 header 名称。 */\n readonly maskHeaders: readonly string[]\n /** 发送规范化网络记录的回调。 */\n readonly send: (record: NetworkRecord) => void\n}\n\n/**\n * 创建 Hook 来源的 Network 记录。\n *\n * Hook 模式只覆盖 fetch/XHR,但它可以零配置提供业务接口的请求参数和响应值。\n */\nexport function createHookNetworkRecord(\n input: HookNetworkRecordInput\n): NetworkRecord {\n return {\n id: nanoid(),\n pageId: input.pageId,\n source: 'hook',\n url: input.url,\n method: input.method,\n requestHeaders: maskHeaders(input.requestHeaders, input.maskHeaders),\n requestQuery: parseRequestQuery(input.url),\n requestBody: input.requestBody,\n startedAt: input.startedAt\n }\n}\n\n/**\n * 安装 fetch 和 XHR 网络 Hook。\n *\n * Hook 不覆盖静态资源和浏览器内部请求,但能在无 CDP 配置时捕获大多数业务接口。\n */\nexport function installNetworkHook(options: NetworkHookOptions): () => void {\n const originalFetch = window.fetch.bind(window)\n const XMLHttpRequestCtor = window.XMLHttpRequest as\n | typeof XMLHttpRequest\n | undefined\n // eslint-disable-next-line @typescript-eslint/unbound-method -- XHR 原型方法必须保留动态 this,后续通过 Reflect.apply 绑定到具体实例。\n const originalOpen = XMLHttpRequestCtor?.prototype.open\n // eslint-disable-next-line @typescript-eslint/unbound-method -- XHR 原型方法必须保留动态 this,后续通过 Reflect.apply 绑定到具体实例。\n const originalSend = XMLHttpRequestCtor?.prototype.send\n\n window.fetch = createFetchHook(originalFetch, options)\n\n if (XMLHttpRequestCtor && originalOpen && originalSend) {\n installXhrHook(XMLHttpRequestCtor, originalOpen, originalSend, options)\n }\n\n return () => {\n window.fetch = originalFetch\n if (XMLHttpRequestCtor && originalOpen && originalSend) {\n XMLHttpRequestCtor.prototype.open = originalOpen\n XMLHttpRequestCtor.prototype.send = originalSend\n }\n }\n}\n\n/**\n * 创建 fetch 包装函数。\n *\n * 使用 response.clone() 读取响应体,避免调试采集破坏业务代码对 response 的消费。\n */\nfunction createFetchHook(\n originalFetch: typeof window.fetch,\n options: NetworkHookOptions\n): typeof window.fetch {\n return async (input, init) => {\n const startedAt = Date.now()\n const record = createHookNetworkRecord({\n pageId: options.pageId,\n url: getFetchUrl(input),\n method: getFetchMethod(input, init),\n requestHeaders: headersToRecord(\n init?.headers ?? (input instanceof Request ? input.headers : undefined)\n ),\n requestBody: init?.body,\n maskHeaders: options.maskHeaders,\n startedAt\n })\n\n try {\n const response = await originalFetch(input, init)\n const endedAt = Date.now()\n options.send({\n ...record,\n status: response.status,\n responseHeaders: headersToRecord(response.headers),\n responseBody: await readResponseBody(response, options.maxBodySize),\n endedAt,\n durationMs: endedAt - startedAt\n })\n return response\n } catch (error) {\n const endedAt = Date.now()\n options.send({\n ...record,\n error: error instanceof Error ? error.message : String(error),\n endedAt,\n durationMs: endedAt - startedAt\n })\n throw error\n }\n }\n}\n\n/**\n * 安装 XHR 包装。\n *\n * XHR 没有 fetch 那样的 clone 能力,因此只读取 responseText,并在失败时静默降级。\n */\nfunction installXhrHook(\n XMLHttpRequestCtor: typeof XMLHttpRequest,\n originalOpen: typeof XMLHttpRequest.prototype.open,\n originalSend: typeof XMLHttpRequest.prototype.send,\n options: NetworkHookOptions\n): void {\n const states = new WeakMap<\n XMLHttpRequest,\n { method: string; url: string; startedAt: number; body?: unknown }\n >()\n\n XMLHttpRequestCtor.prototype.open = function open(\n this: XMLHttpRequest,\n method: string,\n url: string | URL,\n async?: boolean,\n username?: string | null,\n password?: string | null\n ): void {\n const args = [method, url, async, username, password].filter(\n (item) => item !== undefined\n )\n states.set(this, { method, url: String(url), startedAt: 0 })\n Reflect.apply(originalOpen, this, args)\n }\n\n XMLHttpRequestCtor.prototype.send = function send(\n this: XMLHttpRequest,\n ...args: Parameters<typeof originalSend>\n ): void {\n const [body] = args\n const state = states.get(this)\n\n if (state) {\n state.startedAt = Date.now()\n state.body = body\n const record = createHookNetworkRecord({\n pageId: options.pageId,\n url: state.url,\n method: state.method,\n requestBody: body,\n maskHeaders: options.maskHeaders,\n startedAt: state.startedAt\n })\n this.addEventListener('loadend', () => {\n const endedAt = Date.now()\n options.send({\n ...record,\n status: this.status,\n responseHeaders: parseRawHeaders(this.getAllResponseHeaders()),\n responseBody: truncateText(\n safeReadXhrResponseText(this),\n options.maxBodySize\n ).text,\n endedAt,\n durationMs: endedAt - state.startedAt\n })\n })\n }\n\n Reflect.apply(originalSend, this, args)\n }\n}\n\n/**\n * 获取 fetch 请求 URL。\n *\n * fetch 支持字符串、URL 和 Request,多形态输入需要统一为字符串才能进入 NetworkRecord。\n */\nfunction getFetchUrl(input: RequestInfo | URL): string {\n if (input instanceof Request) {\n return input.url\n }\n\n return String(input)\n}\n\n/**\n * 获取 fetch 请求方法。\n *\n * init.method 优先级最高,其次复用 Request.method,最后回退到 GET。\n */\nfunction getFetchMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method) {\n return init.method.toUpperCase()\n }\n\n if (input instanceof Request) {\n return input.method.toUpperCase()\n }\n\n return 'GET'\n}\n\n/**\n * 将 HeadersInit 转成普通对象。\n *\n * MCP 输出需要 JSON 友好的结构,不能直接返回 Headers 实例。\n */\nfunction headersToRecord(headers?: HeadersInit): Record<string, string> {\n if (!headers) {\n return {}\n }\n\n return Object.fromEntries(new Headers(headers).entries())\n}\n\n/**\n * 读取 fetch 响应体。\n *\n * 使用 clone 防止消费业务响应;读取失败时返回 undefined,让 Hook 不影响页面逻辑。\n */\nasync function readResponseBody(\n response: Response,\n maxBodySize: number\n): Promise<string | undefined> {\n try {\n return truncateText(await response.clone().text(), maxBodySize).text\n } catch {\n return undefined\n }\n}\n\n/**\n * 解析 XHR 原始响应头。\n *\n * XHR 只提供字符串格式的响应头,拆成对象后 MCP 工具更容易过滤和展示。\n */\nfunction parseRawHeaders(rawHeaders: string): Record<string, string> {\n return Object.fromEntries(\n rawHeaders\n .trim()\n .split(/\\r?\\n/)\n .filter(Boolean)\n .map((line) => {\n const index = line.indexOf(':')\n return [\n line.slice(0, index).trim().toLowerCase(),\n line.slice(index + 1).trim()\n ]\n })\n )\n}\n\n/**\n * 安全读取 XHR responseText。\n *\n * 某些 responseType 下读取 responseText 会抛错,Hook 必须静默降级而不是影响业务请求。\n */\nfunction safeReadXhrResponseText(xhr: XMLHttpRequest): string {\n try {\n return xhr.responseText\n } catch {\n return ''\n }\n}\n","/**\n * 文本截断结果。\n *\n * MCP 输出需要明确告诉调用方内容被截断,否则 AI 可能误以为看到的是完整响应。\n */\nexport interface TruncatedText {\n /** 截断后的文本。 */\n readonly text: string\n /** 是否发生截断。 */\n readonly truncated: boolean\n /** 原始文本长度,用于判断丢失信息规模。 */\n readonly originalLength: number\n}\n\n/**\n * 截断长文本。\n *\n * DOM 文本和响应体都可能很大,统一截断策略可以避免不同工具输出行为不一致。\n */\nexport function truncateText(text: string, maxLength: number): TruncatedText {\n if (text.length <= maxLength) {\n return { text, truncated: false, originalLength: text.length }\n }\n\n return {\n text: text.slice(0, maxLength),\n truncated: true,\n originalLength: text.length\n }\n}\n\n/**\n * 对敏感 header 做脱敏。\n *\n * Network 调试需要展示 header,但认证和 Cookie 不应原样暴露给 AI 客户端。\n */\nexport function maskHeaders(\n headers: Record<string, string> = {},\n maskNames: readonly string[] = []\n): Record<string, string> {\n const normalizedMaskNames = new Set(\n maskNames.map((name) => name.toLowerCase())\n )\n\n return Object.fromEntries(\n Object.entries(headers).map(([name, value]) => [\n name,\n normalizedMaskNames.has(name.toLowerCase()) ? '[masked]' : value\n ])\n )\n}\n","/**\n * 解析请求 URL 中的 query 参数。\n *\n * Network 工具需要直接回答“请求参数是什么”,将 query 拆成结构化对象可以减少 AI 重复解析。\n */\nexport function parseRequestQuery(\n url: string\n): Record<string, string | string[]> {\n const parsed = new URL(url, 'http://vite-plugin-vue-mcp-next.local')\n const queryEntries = new Map<string, string | string[]>()\n\n for (const [key, value] of parsed.searchParams.entries()) {\n const existing = queryEntries.get(key)\n\n if (existing === undefined) {\n queryEntries.set(key, value)\n continue\n }\n\n if (Array.isArray(existing)) {\n existing.push(value)\n continue\n }\n\n queryEntries.set(key, [existing, value])\n }\n\n return Object.fromEntries(queryEntries)\n}\n\n/**\n * 获取 URL pathname。\n *\n * 页面 target 可能上报绝对 URL 或相对路径,该 helper 让展示逻辑不需要关心来源格式。\n */\nexport function safeUrlPathname(url: string): string {\n try {\n return new URL(url).pathname\n } catch {\n return url.split('?')[0] || '/'\n }\n}\n","/**\n * Runtime 页面身份生成。\n *\n * 该文件把页面级随机 pageId 和同标签页稳定 client id 分开维护,\n * 让 MCP 既能区分多标签页,又能在刷新重连时清理旧 runtime 目标。\n */\nimport { nanoid } from 'nanoid'\nimport { safeUrlPathname } from '../shared/url'\n\n/**\n * 页面运行时身份输入。\n *\n * 测试中传入 window-like 对象可以避免直接依赖浏览器全局对象。\n */\nexport interface RuntimePageIdentityInput {\n /** 当前页面完整 URL,用于关联 runtime target 和 CDP target。 */\n readonly href: string\n /** 当前页面标题,用于多页面调试时辅助识别。 */\n readonly title: string\n /** 同标签页稳定身份,用于服务端清理刷新或 HMR 造成的旧 runtime 连接。 */\n readonly runtimeClientId: string\n /** 视口宽度,用于帮助 AI 判断页面当前布局状态。 */\n readonly innerWidth: number\n /** 视口高度,用于帮助 AI 判断页面当前布局状态。 */\n readonly innerHeight: number\n /** 文档加载状态,用于解释某些 DOM 或日志为何暂时不可用。 */\n readonly readyState: DocumentReadyState\n}\n\n/**\n * runtime client id 的最小存储接口。\n *\n * 只依赖 getItem/setItem,便于在测试中使用轻量对象,也避免把身份生成逻辑绑定到浏览器全局对象。\n */\nexport interface RuntimeClientIdStorage {\n /** 读取同标签页已保存的 client id。 */\n getItem(key: string): string | null\n /** 写入同标签页后续刷新可复用的 client id。 */\n setItem(key: string, value: string): void\n}\n\n\n/**\n * runtime client id 的标签页作用域。\n *\n * 浏览器新标签页可能复制 opener 的 sessionStorage 初始值,因此需要一个不会被复制的标签页标记辅助区分。\n */\nexport interface RuntimeClientIdTabScope {\n /** window.name 会跨刷新保留,适合作为开发态调试身份的轻量标签页标记。 */\n name: string\n /** 当前 JS 上下文内的 runtime client id,优先用于抵御 HMR 或重复启动。 */\n __VITE_MCP_NEXT_RUNTIME_CLIENT_ID__?: string\n}\n\n/**\n * 页面运行时身份。\n *\n * Runtime Bridge 上报该结构后,服务端可以在没有 CDP 的情况下也维护可调试页面列表。\n */\nexport interface RuntimePageIdentity {\n /** runtime 页面唯一标识,同一路径多 tab 打开时仍可区分。 */\n readonly pageId: string\n /** 固定标记为 runtime,便于服务端区分 CDP target。 */\n readonly source: 'runtime'\n /** 当前页面完整 URL,用于展示和 target 关联。 */\n readonly url: string\n /** URL pathname,用于多入口页面的短路径展示。 */\n readonly pathname: string\n /** 页面标题,用于多页面调试时辅助识别。 */\n readonly title: string\n /** 同标签页稳定身份,用于服务端把刷新后的新连接和旧 pageId 关联起来。 */\n readonly runtimeClientId: string\n /** runtime 启动后页面默认处于可连接状态。 */\n readonly connected: true\n /** 文档加载状态,用于解释 DOM 快照时机。 */\n readonly readyState: DocumentReadyState\n /** 当前视口尺寸,用于帮助 AI 判断响应式布局状态。 */\n readonly viewport: {\n readonly width: number\n readonly height: number\n }\n}\n\nconst RUNTIME_CLIENT_ID_STORAGE_KEY = 'vite-plugin-vue-mcp-next:runtime-client-id'\nconst RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX =\n 'vite-plugin-vue-mcp-next:runtime-client-id='\nconst RUNTIME_CLIENT_ID_WINDOW_NAME_SEPARATOR = '\\n'\n\n/**\n * 创建同标签页稳定 client id。\n *\n * 该 ID 不作为 MCP 工具调用目标,只用于服务端识别同一个浏览器标签页刷新后的新连接。\n */\nexport function createRuntimeClientId(): string {\n return `runtime-client-${nanoid()}`\n}\n\n/**\n * 获取同标签页稳定 client id。\n *\n * 正常浏览器环境使用 sessionStorage 跨刷新复用;隐私模式或存储不可用时退回单次随机 ID,\n * 这样不会阻塞 runtime bridge 启动,只是无法自动合并该标签页的历史连接。\n */\n/**\n * 从 window.name 中读取 runtime client id。\n *\n * 该标记用于识别同一个真实标签页,避免新标签页复制 sessionStorage 后被误判为同一页面。\n */\nfunction readRuntimeClientIdFromTabScope(\n tabScope?: RuntimeClientIdTabScope\n): string | undefined {\n if (!tabScope) {\n return undefined\n }\n\n if (tabScope.__VITE_MCP_NEXT_RUNTIME_CLIENT_ID__) {\n return tabScope.__VITE_MCP_NEXT_RUNTIME_CLIENT_ID__\n }\n\n return tabScope.name\n .split(RUNTIME_CLIENT_ID_WINDOW_NAME_SEPARATOR)\n .find((item) => item.startsWith(RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX))\n ?.slice(RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX.length)\n}\n\n/**\n * 写入 window.name 中的 runtime client id 标记。\n *\n * 保留已有 window.name 内容,是为了降低对业务页面或测试页面自身 window.name 用法的影响。\n */\nfunction writeRuntimeClientIdToTabScope(\n tabScope: RuntimeClientIdTabScope,\n clientId: string\n): void {\n tabScope.__VITE_MCP_NEXT_RUNTIME_CLIENT_ID__ = clientId\n const preservedNameParts = tabScope.name\n .split(RUNTIME_CLIENT_ID_WINDOW_NAME_SEPARATOR)\n .filter((item) => !item.startsWith(RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX))\n .filter(Boolean)\n tabScope.name = [\n ...preservedNameParts,\n `${RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX}${clientId}`\n ].join(RUNTIME_CLIENT_ID_WINDOW_NAME_SEPARATOR)\n}\n\n/**\n * 保存 runtime client id。\n *\n * sessionStorage 支撑刷新复用,window.name 标记支撑区分复制 sessionStorage 的新标签页。\n */\nfunction persistRuntimeClientId(\n storage: RuntimeClientIdStorage,\n clientId: string,\n tabScope?: RuntimeClientIdTabScope\n): string {\n storage.setItem(RUNTIME_CLIENT_ID_STORAGE_KEY, clientId)\n\n if (tabScope) {\n writeRuntimeClientIdToTabScope(tabScope, clientId)\n }\n\n return clientId\n}\n\nexport function getRuntimeClientId(\n storage?: RuntimeClientIdStorage,\n tabScope?: RuntimeClientIdTabScope\n): string {\n const nextClientId = createRuntimeClientId()\n\n if (!storage) {\n return nextClientId\n }\n\n try {\n const tabScopedClientId = readRuntimeClientIdFromTabScope(tabScope)\n\n if (tabScopedClientId) {\n return persistRuntimeClientId(storage, tabScopedClientId, tabScope)\n }\n\n if (tabScope) {\n return persistRuntimeClientId(storage, nextClientId, tabScope)\n }\n\n const currentClientId = storage.getItem(RUNTIME_CLIENT_ID_STORAGE_KEY)\n\n if (currentClientId) {\n return currentClientId\n }\n\n return persistRuntimeClientId(storage, nextClientId)\n } catch {\n return nextClientId\n }\n}\n\n/**\n * 创建 runtime 页面 ID。\n *\n * 使用随机 ID 而不是 URL,是因为同一个页面可能在多个 tab 中同时打开。\n */\nexport function createRuntimePageId(): string {\n return `runtime-${nanoid()}`\n}\n\n/**\n * 读取页面身份信息。\n *\n * Runtime Bridge 启动后立即上报该信息,让 MCP 在没有 CDP 的情况下也能列出可调试页面。\n */\nexport function getRuntimePageIdentity(\n input: RuntimePageIdentityInput\n): RuntimePageIdentity {\n return {\n pageId: createRuntimePageId(),\n source: 'runtime',\n url: input.href,\n pathname: safeUrlPathname(input.href),\n title: input.title,\n runtimeClientId: input.runtimeClientId,\n connected: true,\n readyState: input.readyState,\n viewport: {\n width: input.innerWidth,\n height: input.innerHeight\n }\n }\n}\n","/**\n * 浏览器端性能采集 Hook。\n *\n * 该文件只负责收集运行态可见的长任务、内存趋势和错误堆栈,并把它们整理成统一的性能报告。\n */\nimport { nanoid } from 'nanoid'\nimport {\n buildMemorySummary,\n buildPerformanceSummary,\n buildStackSummary\n} from '../performance/summary'\nimport type {\n LongTaskRecord,\n MemorySample,\n PerformanceArtifact,\n PerformanceReport,\n StackFrameSummary\n} from '../types'\n\n/**\n * 性能采集器依赖。\n *\n * 通过依赖注入隔离浏览器原生 API,可以让单元测试直接驱动采集逻辑,而不用真的启动浏览器。\n */\nexport interface PerformanceCollectorDependencies {\n /** 页面 id,用于区分多标签页采样结果。 */\n readonly pageId: string\n /** 时间函数,便于测试固定时间线。 */\n readonly now: () => number\n /** 读取当前内存采样。 */\n readonly readMemory: () => MemorySample | undefined\n /** 安装 longtask 监听器,返回清理函数。 */\n readonly observeLongTask: (push: (task: LongTaskRecord) => void) => () => void\n /** 安装 long-animation-frame 监听器,返回清理函数。 */\n readonly observeAnimationFrame: (\n push: (task: LongTaskRecord) => void\n ) => () => void\n /** 安装 error 监听器,返回清理函数。 */\n readonly observeErrorStack?: (push: (stack: StackFrameSummary) => void) => () => void\n /** 安装 unhandledrejection 监听器,返回清理函数。 */\n readonly observeUnhandledRejectionStack?: (\n push: (stack: StackFrameSummary) => void\n ) => () => void\n /** 等待用 setTimeout。 */\n readonly setTimeout: typeof globalThis.setTimeout\n /** 清理等待用 setTimeout。 */\n readonly clearTimeout: typeof globalThis.clearTimeout\n}\n\n/**\n * 性能采集器。\n *\n * 一个页面只维护一个采集器,工具层通过 start/stop 或 recordOnce 控制采集窗口。\n */\nexport interface PerformanceCollector {\n /** 进行一次定时采集并返回报告。 */\n recordOnce(options: {\n durationMs: number\n includeMemory: boolean\n includeStacks: boolean\n }): Promise<PerformanceReport>\n /** 开始一段交互式采集,返回 recordingId。 */\n start(options: {\n includeMemory: boolean\n includeStacks: boolean\n }): string\n /** 结束交互式采集并返回报告。 */\n stop(recordingId: string): PerformanceReport\n /** 获取最近一次报告。 */\n latest(): PerformanceReport | undefined\n /** 释放监听器。 */\n dispose(): void\n}\n\nlet activePerformanceCollector: PerformanceCollector | undefined\n\n/**\n * 安装浏览器端性能 Hook。\n *\n * 该函数适用于页面启动阶段,会把真实浏览器 API 绑定到统一的采集器实例上。\n */\nexport function installPerformanceHook(options: {\n pageId: string\n send?: (report: PerformanceReport) => void\n sampleIntervalMs?: number\n longTaskThresholdMs?: number\n}): PerformanceCollector {\n const collector = createPerformanceCollector({\n pageId: options.pageId,\n now: () => Date.now(),\n readMemory: readBrowserMemory,\n observeLongTask: (push) => observeLongTasks(push, options.longTaskThresholdMs),\n observeAnimationFrame: observeAnimationFrameTasks,\n observeErrorStack: observeWindowErrorStack,\n observeUnhandledRejectionStack: observeUnhandledRejectionStack,\n setTimeout: window.setTimeout.bind(window),\n clearTimeout: window.clearTimeout.bind(window)\n })\n\n const decoratedCollector = options.send\n ? createDispatchingCollector(collector, options.send)\n : collector\n\n activePerformanceCollector = decoratedCollector\n\n return decoratedCollector\n}\n\n/**\n * 获取当前页面的性能采集器。\n *\n * RPC 层会在运行时调用这里,避免把采集状态散落在多个模块。\n */\nexport function getPerformanceCollector(): PerformanceCollector | undefined {\n return activePerformanceCollector\n}\n\n/**\n * 创建性能采集器。\n *\n * 采集器只做数据收集和报告聚合,不知道 MCP、CDP 或文件落盘的细节。\n */\nexport function createPerformanceCollector(\n deps: PerformanceCollectorDependencies\n): PerformanceCollector {\n const state: PerformanceCollectorState = {\n longTasks: [],\n stackFrames: [],\n memorySamples: [],\n latestReport: undefined,\n activeRecordingId: undefined,\n activeRecordingStartedAt: 0,\n activeIncludeMemory: true,\n activeIncludeStacks: true\n }\n\n const cleanups = [\n deps.observeLongTask((task) => {\n state.longTasks.push(task)\n }),\n deps.observeAnimationFrame((task) => {\n state.longTasks.push(task)\n })\n ]\n\n if (deps.observeErrorStack) {\n cleanups.push(\n deps.observeErrorStack((frame) => {\n state.stackFrames.push(frame)\n })\n )\n }\n\n if (deps.observeUnhandledRejectionStack) {\n cleanups.push(\n deps.observeUnhandledRejectionStack((frame) => {\n state.stackFrames.push(frame)\n })\n )\n }\n\n return {\n async recordOnce(options) {\n const recordingId = startSession(state, deps, {\n includeMemory: options.includeMemory,\n includeStacks: options.includeStacks\n })\n\n await waitForDuration(deps, options.durationMs)\n\n return stopSession({\n state,\n deps,\n recordingId,\n source: 'hook'\n })\n },\n start(options) {\n if (state.activeRecordingId) {\n throw new Error('A performance recording is already active')\n }\n\n return startSession(state, deps, options)\n },\n stop(recordingId) {\n return stopSession({\n state,\n deps,\n recordingId,\n source: 'hook'\n })\n },\n latest() {\n return state.latestReport\n },\n dispose() {\n activePerformanceCollector = undefined\n for (const cleanup of cleanups) {\n cleanup()\n }\n }\n }\n}\n\n/**\n * 性能采集器状态。\n */\ninterface PerformanceCollectorState {\n /** 长任务列表。 */\n longTasks: LongTaskRecord[]\n /** 堆栈列表。 */\n stackFrames: StackFrameSummary[]\n /** 内存采样列表。 */\n memorySamples: MemorySample[]\n /** 最近一次报告。 */\n latestReport?: PerformanceReport\n /** 当前活跃录制 id。 */\n activeRecordingId?: string\n /** 当前录制开始时间。 */\n activeRecordingStartedAt: number\n /** 当前录制是否采集内存。 */\n activeIncludeMemory: boolean\n /** 当前录制是否采集堆栈。 */\n activeIncludeStacks: boolean\n}\n\n/**\n * 创建录制 id。\n */\nfunction createRecordingId(): string {\n return `performance-${nanoid()}`\n}\n\n/**\n * 启动一次录制。\n */\nfunction startSession(\n state: PerformanceCollectorState,\n deps: PerformanceCollectorDependencies,\n options: {\n includeMemory: boolean\n includeStacks: boolean\n }\n): string {\n const recordingId = createRecordingId()\n state.longTasks.length = 0\n state.stackFrames.length = 0\n state.memorySamples.length = 0\n\n if (options.includeMemory) {\n const sample = deps.readMemory()\n if (sample) {\n state.memorySamples.push(sample)\n }\n }\n\n state.activeRecordingId = recordingId\n state.activeRecordingStartedAt = deps.now()\n state.activeIncludeMemory = options.includeMemory\n state.activeIncludeStacks = options.includeStacks\n\n return recordingId\n}\n\n/**\n * 给性能采集器包装一个报告分发器。\n *\n * runtime client 需要把完整报告同步推回服务端,但采集器本身不应感知 hot channel;\n * 这里用薄包装保持采集逻辑独立,同时让报告产生时自动上报。\n */\nfunction createDispatchingCollector(\n collector: PerformanceCollector,\n send: (report: PerformanceReport) => void\n): PerformanceCollector {\n return {\n async recordOnce(options) {\n const report = await collector.recordOnce(options)\n send(report)\n return report\n },\n start(options) {\n return collector.start(options)\n },\n stop(recordingId) {\n const report = collector.stop(recordingId)\n send(report)\n return report\n },\n latest() {\n return collector.latest()\n },\n dispose() {\n collector.dispose()\n }\n }\n}\n\n/**\n * 等待指定时长。\n */\nfunction waitForDuration(\n deps: PerformanceCollectorDependencies,\n durationMs: number\n): Promise<void> {\n return new Promise((resolve) => {\n const timer = deps.setTimeout(() => {\n deps.clearTimeout(timer)\n resolve()\n }, durationMs)\n })\n}\n\n/**\n * 构建最终报告。\n */\nfunction buildReport(options: {\n recordingId: string\n pageId: string\n startedAt: number\n endedAt: number\n source: 'cdp' | 'hook'\n includeMemory: boolean\n includeStacks: boolean\n longTasks: LongTaskRecord[]\n memorySamples: MemorySample[]\n stackFrames: StackFrameSummary[]\n limitations: string[]\n rawProfilePath?: string\n artifacts?: PerformanceArtifact[]\n}): PerformanceReport {\n const memory = options.includeMemory\n ? buildMemorySummary(options.memorySamples)\n : undefined\n const summary = buildPerformanceSummary({\n longTasks: options.longTasks,\n memorySamples: options.includeMemory ? options.memorySamples : []\n })\n const stacks = options.includeStacks\n ? buildStackSummary(options.stackFrames, {\n rawProfilePath: options.rawProfilePath,\n limitation:\n options.stackFrames.length > 0\n ? undefined\n : 'Runtime path only exposes error stacks when the page reports them'\n })\n : undefined\n const report: PerformanceReport = {\n recordingId: options.recordingId,\n pageId: options.pageId,\n source: options.source,\n startedAt: options.startedAt,\n endedAt: options.endedAt,\n durationMs: options.endedAt - options.startedAt,\n summary,\n longTasks: [...options.longTasks],\n memory,\n stacks,\n artifacts: options.artifacts,\n limitations: options.limitations\n }\n\n return report\n}\n\n/**\n * 结束一次录制并返回报告。\n */\nfunction stopSession(options: {\n state: PerformanceCollectorState\n deps: PerformanceCollectorDependencies\n recordingId: string\n source: 'cdp' | 'hook'\n}): PerformanceReport {\n const { state, deps, recordingId, source } = options\n\n if (!state.activeRecordingId || state.activeRecordingId !== recordingId) {\n throw new Error(`Performance recording not found: ${recordingId}`)\n }\n\n if (state.activeIncludeMemory) {\n const sample = deps.readMemory()\n if (sample) {\n state.memorySamples.push(sample)\n }\n }\n\n const report = buildReport({\n recordingId: state.activeRecordingId,\n pageId: deps.pageId,\n startedAt: state.activeRecordingStartedAt,\n endedAt: deps.now(),\n source,\n includeMemory: state.activeIncludeMemory,\n includeStacks: state.activeIncludeStacks,\n longTasks: state.longTasks,\n memorySamples: state.memorySamples,\n stackFrames: state.stackFrames,\n limitations: [\n 'Runtime path only sees browser-observable signals',\n 'Runtime path cannot produce a full CPU profile or heap snapshot'\n ]\n })\n\n state.latestReport = report\n state.activeRecordingId = undefined\n state.activeRecordingStartedAt = 0\n state.activeIncludeMemory = true\n state.activeIncludeStacks = true\n\n return report\n}\n\n/**\n * 从当前运行环境读取内存。\n */\nfunction readBrowserMemory(): MemorySample | undefined {\n const memory = (performance as Performance & {\n memory?: {\n usedJSHeapSize: number\n totalJSHeapSize: number\n jsHeapSizeLimit: number\n }\n }).memory\n\n if (!memory) {\n return undefined\n }\n\n return {\n timestamp: Date.now(),\n usedJSHeapSize: memory.usedJSHeapSize,\n totalJSHeapSize: memory.totalJSHeapSize,\n jsHeapSizeLimit: memory.jsHeapSizeLimit\n }\n}\n\n/**\n * 安装 long task 监听器。\n */\nfunction observeLongTasks(\n push: (task: LongTaskRecord) => void,\n longTaskThresholdMs = 50\n): () => void {\n if (typeof PerformanceObserver === 'undefined') {\n return () => {}\n }\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.duration < longTaskThresholdMs) {\n continue\n }\n\n push({\n startTime: entry.startTime,\n durationMs: entry.duration,\n name: entry.name,\n source: 'longtask'\n })\n }\n })\n\n observer.observe({ type: 'longtask', buffered: true })\n\n return () => {\n observer.disconnect()\n }\n}\n\n/**\n * 安装 long-animation-frame 监听器。\n */\nfunction observeAnimationFrameTasks(\n push: (task: LongTaskRecord) => void\n): () => void {\n if (typeof PerformanceObserver === 'undefined') {\n return () => {}\n }\n\n const supported = PerformanceObserver.supportedEntryTypes.includes(\n 'long-animation-frame'\n )\n\n if (!supported) {\n return () => {}\n }\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n push({\n startTime: entry.startTime,\n durationMs: entry.duration,\n name: entry.name,\n source: 'long-animation-frame'\n })\n }\n })\n\n observer.observe({ type: 'long-animation-frame', buffered: true })\n\n return () => {\n observer.disconnect()\n }\n}\n\n/**\n * 安装 window error 监听器。\n */\nfunction observeWindowErrorStack(\n push: (frame: StackFrameSummary) => void\n): () => void {\n const onError = (event: ErrorEvent): void => {\n const error = event.error as Error | undefined\n const frames = parseStackFrames(error?.stack)\n if (frames.length === 0 && event.message) {\n push({ functionName: event.message })\n return\n }\n\n frames.forEach((frame) => {\n push(frame)\n })\n }\n\n window.addEventListener('error', onError)\n\n return () => {\n window.removeEventListener('error', onError)\n }\n}\n\n/**\n * 安装 unhandledrejection 监听器。\n */\nfunction observeUnhandledRejectionStack(\n push: (frame: StackFrameSummary) => void\n): () => void {\n const onRejection = (event: PromiseRejectionEvent): void => {\n const reason = event.reason as Error | undefined\n const frames = parseStackFrames(reason?.stack)\n\n if (frames.length === 0 && reason?.message) {\n push({ functionName: reason.message })\n return\n }\n\n frames.forEach((frame) => {\n push(frame)\n })\n }\n\n window.addEventListener('unhandledrejection', onRejection)\n\n return () => {\n window.removeEventListener('unhandledrejection', onRejection)\n }\n}\n\n/**\n * 解析 stack 文本。\n */\nfunction parseStackFrames(stack?: string): StackFrameSummary[] {\n if (!stack) {\n return []\n }\n\n return stack\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => {\n const match = /at\\s+(.*?)\\s+\\((.*?):(\\d+):(\\d+)\\)$/.exec(line)\n\n if (match) {\n return {\n functionName: match[1] || '<anonymous>',\n url: match[2],\n lineNumber: Number(match[3]),\n columnNumber: Number(match[4])\n }\n }\n\n return { functionName: line }\n })\n}\n","/**\n * 运行时采集的默认限制集中定义。\n *\n * DOM、Console 和 Network 都可能持续产生大量数据;把限制放在共享模块里,\n * 可以让服务端工具、运行时 Hook 和测试使用同一套安全边界。\n */\n\n/** 默认 DOM 递归深度,保留主要结构,同时避免复杂页面把 MCP 上下文撑爆。 */\nexport const DEFAULT_DOM_MAX_DEPTH = 8\n\n/** 默认 DOM 节点上限,用于防止一次性返回整页巨量节点。 */\nexport const DEFAULT_DOM_MAX_NODES = 2000\n\n/** 默认文本截断长度,保留可定位内容但避免长文案污染调试上下文。 */\nexport const DEFAULT_DOM_MAX_TEXT_LENGTH = 300\n\n/** 默认 Console 缓存上限,适合开发态持续运行且不会无界增长。 */\nexport const DEFAULT_CONSOLE_MAX_RECORDS = 1000\n\n/** 默认 Network 缓存上限,覆盖常见调试窗口同时控制内存占用。 */\nexport const DEFAULT_NETWORK_MAX_RECORDS = 500\n\n/** 默认请求体和响应体最大采集长度,避免大文件响应进入 MCP 工具结果。 */\nexport const DEFAULT_NETWORK_MAX_BODY_SIZE = 100_000\n\n/**\n * 默认脱敏 header。\n *\n * 这些字段通常包含认证态或用户隐私,Network 工具默认隐藏它们可以降低误传风险。\n */\nexport const DEFAULT_MASK_HEADERS = [\n 'authorization',\n 'cookie',\n 'set-cookie'\n] as const\n\n/** 默认响应体截断标记,集中定义可以让 Hook 和 CDP 输出保持一致。 */\nexport const TRUNCATED_MARKER = '[truncated]'\n","import {\n DEFAULT_CONSOLE_MAX_RECORDS,\n DEFAULT_DOM_MAX_DEPTH,\n DEFAULT_DOM_MAX_NODES,\n DEFAULT_DOM_MAX_TEXT_LENGTH,\n DEFAULT_MASK_HEADERS,\n DEFAULT_NETWORK_MAX_BODY_SIZE,\n DEFAULT_NETWORK_MAX_RECORDS\n} from './shared/limits'\nimport type {\n McpClientConfigOptions,\n ResolvedVueMcpNextOptions,\n VueMcpNextOptions\n} from './types'\n\n/** 默认 MCP 挂载路径,使用双下划线前缀避免与业务路由冲突。 */\nexport const DEFAULT_MCP_PATH = '/__mcp'\n\n/** 默认截图最大响应体积,避免 base64 图片挤占 MCP 客户端上下文。 */\nexport const DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024\n\n/** 默认截图保存目录,项目级 MCP 使用项目内目录方便用户复查截图文件。 */\nexport const DEFAULT_SCREENSHOT_SAVE_DIR = '.vite-mcp/screenshot'\n\n/** 默认性能诊断保存目录,原始 profile 和 heap 文件都应保存在项目内。 */\nexport const DEFAULT_PERFORMANCE_SAVE_DIR = '.vite-mcp/performance'\n\n/** 默认性能报告缓冲上限,避免长时间会话无限累积历史诊断结果。 */\nexport const DEFAULT_PERFORMANCE_MAX_REPORTS = 100\n\n/** 默认性能诊断最大时长,避免一次采集长时间占用浏览器资源。 */\nexport const DEFAULT_PERFORMANCE_MAX_DURATION_MS = 30_000\n\n/** 默认性能诊断采样间隔,兼顾趋势判断和额外采样开销。 */\nexport const DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS = 250\n\n/** 默认长任务阈值,沿用浏览器 Long Task 的常见卡顿判断口径。 */\nexport const DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS = 50\n\n/** MCP 工具名集中管理,避免工具注册和测试中出现拼写漂移。 */\nexport const MCP_TOOL_NAMES = {\n listPages: 'list_pages',\n reloadPage: 'reload_page',\n getDomTree: 'get_dom_tree',\n queryDom: 'query_dom',\n takeScreenshot: 'take_screenshot',\n getConsoleLogs: 'get_console_logs',\n clearConsoleLogs: 'clear_console_logs',\n evaluateScript: 'evaluate_script',\n getNetworkRequests: 'get_network_requests',\n getNetworkRequestDetail: 'get_network_request_detail',\n clearNetworkRequests: 'clear_network_requests',\n listStorage: 'list_storage',\n getStorageItem: 'get_storage_item',\n setStorageItem: 'set_storage_item',\n deleteStorageItem: 'delete_storage_item',\n clearStorage: 'clear_storage',\n recordPerformance: 'record_performance',\n startPerformanceRecording: 'start_performance_recording',\n stopPerformanceRecording: 'stop_performance_recording',\n getPerformanceReport: 'get_performance_report',\n takeHeapSnapshot: 'take_heap_snapshot',\n getComponentTree: 'get_component_tree',\n getComponentState: 'get_component_state',\n editComponentState: 'edit_component_state',\n highlightComponent: 'highlight_component',\n getRouterInfo: 'get_router_info',\n getPiniaTree: 'get_pinia_tree',\n getPiniaState: 'get_pinia_state'\n} as const\n\n/** 虚拟模块 ID 集中管理,便于注入逻辑和测试复用。 */\nexport const VIRTUAL_RUNTIME_ID = 'virtual:vite-plugin-vue-mcp-next/runtime'\n\n/** Vite 内部解析虚拟模块时需要使用的空字节前缀。 */\nexport const RESOLVED_VIRTUAL_RUNTIME_ID = `\\0${VIRTUAL_RUNTIME_ID}`\n\n/** snapdom 扩展虚拟模块 ID,用静态 import 支持 Vite alias 和源码转换。 */\nexport const VIRTUAL_SCREENSHOT_CONFIG_ID =\n 'virtual:vite-plugin-vue-mcp-next/screenshot-config'\n\n/** Vite 内部解析截图配置虚拟模块时使用空字节前缀,避免与真实文件冲突。 */\nexport const RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID = `\\0${VIRTUAL_SCREENSHOT_CONFIG_ID}`\n\n/** snapdom loader 虚拟模块 ID,用于把 optional peer 解析限制在宿主 Vite 模块图里。 */\nexport const VIRTUAL_SNAPDOM_LOADER_ID =\n 'virtual:vite-plugin-vue-mcp-next/snapdom-loader'\n\n/** Vite 内部解析 snapdom loader 时使用空字节前缀,避免与真实文件冲突。 */\nexport const RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID = `\\0${VIRTUAL_SNAPDOM_LOADER_ID}`\n\n/** 默认 MCP 客户端服务名,采用 Vite 维度命名以匹配插件能力边界。 */\nexport const DEFAULT_MCP_CLIENT_SERVER_NAME = 'vite-mcp-next'\n\n/** 旧默认服务名只用于迁移已有配置,避免用户项目里同时出现新旧两份 MCP 配置。 */\nexport const LEGACY_MCP_CLIENT_SERVER_NAMES = ['vue-mcp-next'] as const\n\n/** Runtime 页面重连事件名,供 reload_page 等待页面刷新后重新接入。 */\nexport const RUNTIME_PAGE_RECONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-reconnected'\n\n/** 安全默认值,优先保证调试工具不会默认暴露危险能力。 */\nexport const DEFAULT_OPTIONS: ResolvedVueMcpNextOptions = {\n mcpPath: DEFAULT_MCP_PATH,\n host: 'localhost',\n printUrl: true,\n updateCursorMcpJson: {\n enabled: true,\n serverName: DEFAULT_MCP_CLIENT_SERVER_NAME\n },\n mcpClients: {\n cursor: true,\n codex: true,\n claudeCode: true,\n trae: true,\n serverName: DEFAULT_MCP_CLIENT_SERVER_NAME\n },\n skill: {\n autoConfig: true\n },\n runtime: {\n mode: 'auto',\n evaluate: {\n enabled: false,\n timeoutMs: 3000\n }\n },\n cdp: {},\n network: {\n mode: 'auto',\n maxRecords: DEFAULT_NETWORK_MAX_RECORDS,\n captureRequestBody: true,\n captureResponseBody: true,\n maxBodySize: DEFAULT_NETWORK_MAX_BODY_SIZE,\n maskHeaders: [...DEFAULT_MASK_HEADERS]\n },\n dom: {\n maxDepth: DEFAULT_DOM_MAX_DEPTH,\n maxNodes: DEFAULT_DOM_MAX_NODES,\n maxTextLength: DEFAULT_DOM_MAX_TEXT_LENGTH\n },\n console: {\n maxRecords: DEFAULT_CONSOLE_MAX_RECORDS\n },\n screenshot: {\n type: 'path',\n saveDir: DEFAULT_SCREENSHOT_SAVE_DIR,\n prefer: 'auto',\n maxBytes: DEFAULT_SCREENSHOT_MAX_BYTES,\n snapdom: {\n options: {},\n plugins: []\n }\n },\n performance: {\n mode: 'auto',\n maxDurationMs: DEFAULT_PERFORMANCE_MAX_DURATION_MS,\n sampleIntervalMs: DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS,\n longTaskThresholdMs: DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS,\n saveDir: DEFAULT_PERFORMANCE_SAVE_DIR,\n memory: {\n enabled: true\n },\n stacks: {\n enabled: true\n }\n }\n}\n\n/**\n * 兼容旧 Cursor 配置并合并新多客户端配置。\n *\n * `updateCursorMcpJson` 已经公开给用户,不能直接删除;这里让旧配置继续影响 Cursor,\n * 同时允许 `mcpClients` 作为新入口覆盖默认行为。\n */\nfunction mergeMcpClientOptions(\n cursorConfig: ResolvedVueMcpNextOptions['updateCursorMcpJson'],\n mcpClients?: McpClientConfigOptions\n): Required<McpClientConfigOptions> {\n return {\n ...DEFAULT_OPTIONS.mcpClients,\n cursor: cursorConfig.enabled,\n serverName: cursorConfig.serverName,\n ...mcpClients\n }\n}\n\n/**\n * 合并用户配置和安全默认值。\n *\n * 嵌套配置不能使用浅合并,否则用户只配置一个字段时会丢掉默认安全边界。\n */\nexport function mergeOptions(\n options: VueMcpNextOptions = {}\n): ResolvedVueMcpNextOptions {\n const cursorConfig =\n typeof options.updateCursorMcpJson === 'boolean'\n ? {\n enabled: options.updateCursorMcpJson,\n serverName: DEFAULT_OPTIONS.updateCursorMcpJson.serverName\n }\n : {\n ...DEFAULT_OPTIONS.updateCursorMcpJson,\n ...options.updateCursorMcpJson\n }\n const mcpClients = mergeMcpClientOptions(cursorConfig, options.mcpClients)\n\n return {\n ...DEFAULT_OPTIONS,\n ...options,\n updateCursorMcpJson: cursorConfig,\n mcpClients,\n skill: {\n ...DEFAULT_OPTIONS.skill,\n ...options.skill\n },\n runtime: {\n ...DEFAULT_OPTIONS.runtime,\n ...options.runtime,\n evaluate: {\n ...DEFAULT_OPTIONS.runtime.evaluate,\n ...options.runtime?.evaluate\n }\n },\n cdp: {\n ...DEFAULT_OPTIONS.cdp,\n ...options.cdp\n },\n network: {\n ...DEFAULT_OPTIONS.network,\n ...options.network,\n maskHeaders: options.network?.maskHeaders ?? [\n ...DEFAULT_OPTIONS.network.maskHeaders\n ]\n },\n dom: {\n ...DEFAULT_OPTIONS.dom,\n ...options.dom\n },\n console: {\n ...DEFAULT_OPTIONS.console,\n ...options.console\n },\n screenshot: {\n ...DEFAULT_OPTIONS.screenshot,\n ...options.screenshot,\n snapdom: {\n ...DEFAULT_OPTIONS.screenshot.snapdom,\n ...options.screenshot?.snapdom,\n options: {\n ...DEFAULT_OPTIONS.screenshot.snapdom.options,\n ...options.screenshot?.snapdom?.options\n },\n plugins: options.screenshot?.snapdom?.plugins ?? [\n ...DEFAULT_OPTIONS.screenshot.snapdom.plugins\n ]\n }\n },\n performance: {\n ...DEFAULT_OPTIONS.performance,\n ...options.performance,\n memory: {\n ...DEFAULT_OPTIONS.performance.memory,\n ...options.performance?.memory\n },\n stacks: {\n ...DEFAULT_OPTIONS.performance.stacks,\n ...options.performance?.stacks\n }\n }\n }\n}\n","/**\n * 性能报告摘要计算。\n *\n * 这个文件只保留纯数据归纳逻辑,不依赖浏览器 API 或 CDP client,便于 runtime 和 CDP 两条路径共享同一口径。\n */\nimport { DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS } from '../constants'\nimport type {\n LongTaskRecord,\n MemorySample,\n MemorySummary,\n PerformanceSummary,\n StackFrameSummary,\n StackSummary\n} from '../types'\n\n/**\n * 计算性能摘要。\n *\n * 该摘要面向快速判断页面是否明显卡顿,不追求把所有原始信号都塞进结果里。\n */\nexport function buildPerformanceSummary(input: {\n longTasks: LongTaskRecord[]\n memorySamples: MemorySample[]\n}): PerformanceSummary {\n const memory = buildMemorySummary(input.memorySamples)\n const blockedTimeMs = input.longTasks.reduce((total, task) => {\n return (\n total +\n Math.max(0, task.durationMs - DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS)\n )\n }, 0)\n const longTaskCount = input.longTasks.length\n const durations = input.longTasks.map((task) => task.durationMs)\n const maxTaskDurationMs = durations.length ? Math.max(...durations) : 0\n const averageTaskDurationMs = durations.length\n ? Math.round(\n durations.reduce((total, duration) => total + duration, 0) /\n durations.length\n )\n : undefined\n const suspectedJank =\n blockedTimeMs > 0 || memory.trend === 'growing' || longTaskCount > 0\n const severity = resolveSeverity({\n blockedTimeMs,\n longTaskCount,\n memoryTrend: memory.trend\n })\n\n return {\n blockedTimeMs,\n longTaskCount,\n maxTaskDurationMs,\n averageTaskDurationMs,\n suspectedJank,\n severity\n }\n}\n\n/**\n * 计算内存趋势。\n *\n * 只比较首尾和峰值,不推断对象引用关系,这样 runtime-only 路径也能给出稳定结论。\n */\nexport function buildMemorySummary(samples: MemorySample[]): MemorySummary {\n const first = samples[0]?.usedJSHeapSize\n const last = samples.at(-1)?.usedJSHeapSize\n const peak = samples.reduce((currentPeak, sample) => {\n if (typeof sample.usedJSHeapSize !== 'number') {\n return currentPeak\n }\n\n return Math.max(currentPeak, sample.usedJSHeapSize)\n }, 0)\n\n const trend = resolveMemoryTrend(first, last)\n\n return {\n samples,\n initialUsedJSHeapSize: first,\n finalUsedJSHeapSize: last,\n peakUsedJSHeapSize: peak || undefined,\n deltaUsedJSHeapSize:\n typeof first === 'number' && typeof last === 'number'\n ? last - first\n : undefined,\n trend\n }\n}\n\n/**\n * 计算堆栈摘要。\n *\n * 该函数只做排序和裁剪,不直接理解 CPU profile 或错误对象,方便 CDP 和 runtime 传入不同来源的帧数据。\n */\nexport function buildStackSummary(\n frames: StackFrameSummary[],\n options: { rawProfilePath?: string; limitation?: string } = {}\n): StackSummary {\n return {\n topFrames: [...frames].sort(sortByHotness).slice(0, 10),\n rawProfilePath: options.rawProfilePath,\n limitation: options.limitation\n }\n}\n\n/**\n * 根据卡顿指标判断严重程度。\n *\n * 这个分级只用于调试报告的阅读提示,不代表生产级告警阈值。\n */\nfunction resolveSeverity(input: {\n blockedTimeMs: number\n longTaskCount: number\n memoryTrend: MemorySummary['trend']\n}): PerformanceSummary['severity'] {\n if (input.blockedTimeMs >= 1000 || input.longTaskCount >= 10) {\n return 'critical'\n }\n\n if (input.blockedTimeMs > 0 || input.memoryTrend === 'growing') {\n return 'warning'\n }\n\n return 'ok'\n}\n\n/**\n * 根据首尾内存采样判断趋势。\n *\n * 只要存在明显上升就视为 growing,避免 runtime 路径因单次抖动而过度乐观。\n */\nfunction resolveMemoryTrend(\n first: number | undefined,\n last: number | undefined\n): MemorySummary['trend'] {\n if (typeof first !== 'number' || typeof last !== 'number') {\n return 'unknown'\n }\n\n if (last > first) {\n return 'growing'\n }\n\n return 'stable'\n}\n\n/**\n * 按热点程度给堆栈帧排序。\n *\n * 优先比较总耗时,再比较自身耗时和命中次数,保证摘要更偏向真正的热点函数。\n */\nfunction sortByHotness(\n left: StackFrameSummary,\n right: StackFrameSummary\n): number {\n return compareNumber(right.totalTimeMs, left.totalTimeMs)\n || compareNumber(right.selfTimeMs, left.selfTimeMs)\n || compareNumber(right.hitCount, left.hitCount)\n}\n\n/**\n * 比较可选数值。\n *\n * 空值统一排后,方便摘要维持稳定排序。\n */\nfunction compareNumber(left?: number, right?: number): number {\n return (left ?? -1) - (right ?? -1)\n}\n","/**\n * 浏览器端 snapdom 截图降级能力。\n *\n * 该文件只在页面 runtime 中执行,适用于没有 CDP 但仍希望让 MCP 客户端看到页面视觉结果的场景;\n * 函数型扩展通过 Vite import 路径加载,避免 Node 侧配置直接跨运行时传递函数。\n */\nimport type {\n RuntimeScreenshotResult,\n ScreenshotFormat,\n ScreenshotTarget,\n SnapdomPluginImport,\n SnapdomScreenshotOptions\n} from '../types'\n\n/**\n * Runtime 截图参数。\n *\n * loader 只用于测试替换和 Vite 动态 import 边界;正常业务调用只需要传截图目标和 snapdom 配置。\n */\nexport interface RuntimeScreenshotOptions {\n /** 截图目标范围,用于选择 documentElement 或 selector 元素。 */\n readonly target: ScreenshotTarget\n /** 元素截图选择器,只在 `target: \"element\"` 时使用。 */\n readonly selector?: string\n /** 输出格式,决定 Blob mime type 和压缩策略。 */\n readonly format: ScreenshotFormat\n /** 有损格式质量,适用于 jpeg/webp 控制响应体积。 */\n readonly quality?: number\n /** 单次调用缩放倍率覆盖值,适合临时请求高清局部截图。 */\n readonly scale?: number\n /** 已解析 snapdom 配置,函数型配置仍以 Vite import 路径表达。 */\n readonly snapdom: Required<\n Pick<SnapdomScreenshotOptions, 'options' | 'plugins'>\n > &\n Omit<SnapdomScreenshotOptions, 'options' | 'plugins'>\n /** 测试或特殊运行环境替换 snapdom 加载方式时使用。 */\n readonly loadSnapdom?: () => Promise<{ snapdom: SnapdomFunction }>\n /** 测试或特殊运行环境替换 Vite 动态 import 时使用。 */\n readonly loadModule?: (path: string) => Promise<Record<string, unknown>>\n}\n\n/**\n * snapdom 函数边界。\n *\n * 只声明当前截图流程需要的最小能力,可以让本插件不绑定 snapdom 的完整内部类型。\n */\ntype SnapdomFunction = (\n element: Element,\n options: Record<string, unknown>\n) => Promise<{ toBlob: (options?: Record<string, unknown>) => Promise<Blob> }>\n\n/**\n * snapdom 加载器。\n *\n * 该函数由 Vite 虚拟模块注册,避免发布包 runtime 直接 import optional peer 后触发 optimizeDeps 失败。\n */\ntype SnapdomLoader = () => Promise<{ snapdom: SnapdomFunction }>\n\n/**\n * 默认 snapdom 加载器。\n *\n * 缺失 optional peer 时返回结构化错误,适合 MCP 工具把原因直接反馈给大模型。\n */\nlet snapdomLoader: SnapdomLoader = () =>\n Promise.reject(createMissingSnapdomError())\n\n/**\n * snapdom 扩展模块注册表。\n *\n * 注册表由 Vite 注入的虚拟 runtime wrapper 写入,而不是在发布的 runtime client 里直接 import 虚拟模块;\n * 这样可以避开 Vite optimizeDeps 扫描 node_modules 时无法解析虚拟模块的问题。\n */\nlet screenshotModuleRegistry: Partial<Record<string, Record<string, unknown>>> =\n {}\n\n/**\n * 注册截图扩展模块。\n *\n * Vite import 路径必须在宿主项目的 Vite 模块图里解析,适用于插件、filter、fallbackURL 需要使用 alias 或源码转换的场景。\n */\nexport function setScreenshotModuleRegistry(\n registry: Record<string, Record<string, unknown>>\n): void {\n screenshotModuleRegistry = registry\n}\n\n/**\n * 注册 snapdom 加载器。\n *\n * 只有宿主 Vite 项目可以正确解析 optional peer,因此由虚拟 runtime 入口在浏览器侧注册。\n */\nexport function setSnapdomLoader(loader: SnapdomLoader): void {\n snapdomLoader = loader\n}\n\n/**\n * 执行 runtime DOM 截图。\n *\n * snapdom 截图是 CDP 不可用时的兼容路径,因此返回结果必须带 `source: \"snapdom\"` 和限制说明。\n */\nexport async function takeRuntimeScreenshot(\n options: RuntimeScreenshotOptions\n): Promise<RuntimeScreenshotResult & { source?: 'snapdom' }> {\n const target = resolveScreenshotTarget(options.target, options.selector)\n\n if (!target.ok) {\n return target\n }\n\n const loadSnapdom = options.loadSnapdom ?? loadDefaultSnapdom\n let loaded: { snapdom: SnapdomFunction }\n\n try {\n loaded = await loadSnapdom()\n } catch (error) {\n return {\n ok: false,\n source: 'snapdom',\n error: error instanceof Error ? error.message : String(error)\n }\n }\n\n const { snapdom } = loaded\n const snapdomOptions = await createSnapdomOptions(options)\n const capture = await snapdom(target.element, snapdomOptions)\n const blob = await capture.toBlob({\n type: createMimeType(options.format),\n quality: options.quality\n })\n const data = await blobToBase64(blob)\n const rect = target.element.getBoundingClientRect()\n\n return {\n ok: true,\n source: 'snapdom',\n data,\n width: rect.width,\n height: rect.height,\n mimeType: createMimeType(options.format),\n byteLength: blob.size,\n limitations: [\n 'snapdom renders DOM to an image and may differ from browser pixels',\n 'cross-origin images, iframe content, video, WebGL, and complex CSS may be incomplete'\n ]\n }\n}\n\n/**\n * 加载默认 snapdom 实现。\n *\n * 真实加载逻辑由宿主 Vite 虚拟模块注册,适合 optional peer 缺失时把错误留到 MCP 工具响应阶段。\n */\nfunction loadDefaultSnapdom(): Promise<{ snapdom: SnapdomFunction }> {\n return snapdomLoader()\n}\n\n/**\n * 解析截图目标元素。\n *\n * runtime 降级截图只能读取页面自身 DOM;在边界处返回明确错误可以让 MCP 工具解释失败原因。\n */\nfunction resolveScreenshotTarget(\n target: ScreenshotTarget,\n selector?: string\n):\n | { ok: true; element: Element }\n | { ok: false; error: string } {\n if (target === 'element' && !selector) {\n return { ok: false, error: 'selector is required when target is element' }\n }\n\n if (target === 'element') {\n if (!selector) {\n return { ok: false, error: 'selector is required when target is element' }\n }\n\n const elementSelector = selector\n const element = document.querySelector(elementSelector)\n\n return element\n ? { ok: true, element }\n : { ok: false, error: `element not found: ${elementSelector}` }\n }\n\n return { ok: true, element: document.documentElement }\n}\n\n/**\n * 组装 snapdom options。\n *\n * 项目级配置和单次调用配置需要在浏览器端合并,因为插件、filter、fallbackURL 都依赖 Vite import。\n */\nasync function createSnapdomOptions(\n options: RuntimeScreenshotOptions\n): Promise<Record<string, unknown>> {\n const snapdomOptions: Record<string, unknown> = {\n ...options.snapdom.options,\n quality: options.quality ?? options.snapdom.options.quality,\n scale: options.scale ?? options.snapdom.options.scale,\n plugins: await loadSnapdomPlugins(options)\n }\n const loadModule = createModuleLoader(options)\n\n if (options.snapdom.filter) {\n snapdomOptions.filter = await loadDefaultExport(\n loadModule,\n options.snapdom.filter\n )\n }\n\n if (options.snapdom.fallbackURL) {\n snapdomOptions.fallbackURL = await loadDefaultExport(\n loadModule,\n options.snapdom.fallbackURL\n )\n }\n\n return removeUndefinedEntries(snapdomOptions)\n}\n\n/**\n * 加载 snapdom 插件。\n *\n * 插件只能通过 Vite import 路径进入浏览器 runtime,适用于用户插件依赖源码别名或 Vite transform 的场景。\n */\nasync function loadSnapdomPlugins(\n options: RuntimeScreenshotOptions\n): Promise<unknown[]> {\n const loadModule = createModuleLoader(options)\n\n return Promise.all(\n options.snapdom.plugins.map((plugin) => loadPluginImport(plugin, loadModule))\n )\n}\n\n/**\n * 创建模块加载器。\n *\n * 独立函数可以让测试注入 fake loader,同时真实运行时保留 Vite 对动态 import 的处理。\n */\nfunction createModuleLoader(\n options: RuntimeScreenshotOptions\n): (path: string) => Promise<Record<string, unknown>> {\n return options.loadModule ?? loadConfiguredModule\n}\n\n/**\n * 从虚拟模块读取用户配置模块。\n *\n * 这里仅读取已注册表,不直接 import 虚拟模块;发布包中的 runtime client 会被 Vite 依赖优化扫描,\n * 保留虚拟 import 会让用户项目在启动阶段失败。\n */\nfunction loadConfiguredModule(\n path: string\n): Promise<Record<string, unknown>> {\n const mod = screenshotModuleRegistry[path]\n\n if (!mod) {\n throw new Error(`screenshot module is not registered: ${path}`)\n }\n\n return Promise.resolve(mod)\n}\n\n/**\n * 加载单个插件声明。\n *\n * 插件模块可能直接导出插件对象,也可能导出插件工厂;这里按是否提供 options 决定是否调用工厂。\n */\nasync function loadPluginImport(\n plugin: SnapdomPluginImport,\n loadModule: (path: string) => Promise<Record<string, unknown>>\n): Promise<unknown> {\n const normalized =\n typeof plugin === 'string'\n ? { path: plugin, exportName: 'default' }\n : { exportName: 'default', ...plugin }\n const mod = await loadModule(normalized.path)\n const exported = mod[normalized.exportName]\n\n if (isPluginFactory(exported) && 'options' in normalized) {\n return exported(normalized.options)\n }\n\n return exported\n}\n\n/**\n * 判断导出值是否是插件工厂。\n *\n * 动态 import 的模块导出是 unknown,先收窄再调用可以避免把任意值当函数执行。\n */\nfunction isPluginFactory(value: unknown): value is (options: unknown) => unknown {\n return typeof value === 'function'\n}\n\n/**\n * 加载默认导出函数。\n *\n * filter 和 fallbackURL 是 snapdom 原生函数型扩展,路径化加载能保留函数能力但不跨运行时序列化函数。\n */\nasync function loadDefaultExport(\n loadModule: (path: string) => Promise<Record<string, unknown>>,\n path: string\n): Promise<unknown> {\n return (await loadModule(path)).default\n}\n\n/**\n * 生成图片 mime type。\n *\n * MCP 响应需要明确 mime type,方便客户端按格式解码 base64 图片。\n */\nfunction createMimeType(format: ScreenshotFormat): string {\n return `image/${format}`\n}\n\n/**\n * 将 Blob 转成 base64。\n *\n * runtime 运行在浏览器里不能依赖 Node Buffer,因此使用 ArrayBuffer 和 btoa 完成编码。\n */\nasync function blobToBase64(blob: Blob): Promise<string> {\n const bytes = new Uint8Array(await blob.arrayBuffer())\n let binary = ''\n\n for (const byte of bytes) {\n binary += String.fromCharCode(byte)\n }\n\n return btoa(binary)\n}\n\n/**\n * 删除 undefined 配置。\n *\n * snapdom options 里保留 undefined 没有语义,清理后更容易在测试和调试时确认真实传参。\n */\nfunction removeUndefinedEntries(\n value: Record<string, unknown>\n): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(value).filter(([, item]) => item !== undefined)\n )\n}\n\n/**\n * 创建缺失 snapdom 的错误。\n *\n * 错误文案必须包含安装命令,方便 MCP 客户端和大模型直接指导用户修复环境。\n */\nfunction createMissingSnapdomError(): Error {\n return new Error(\n '缺少可选依赖 @zumer/snapdom。DOM 截图降级需要该依赖,请执行:pnpm add -D @zumer/snapdom'\n )\n}\n","/**\n * Vue Runtime Bridge 负责把 Vue Devtools runtime API 暴露给 MCP 服务端。\n *\n * 该文件只处理 Vue 语义能力,适用于组件树、组件状态、Router 和 Pinia 等 CDP 无法直接表达的应用层信息。\n */\nimport {\n devtools,\n devtoolsRouterInfo,\n devtoolsState,\n getInspector,\n stringify,\n toggleHighPerfMode\n} from '@vue/devtools-kit'\nimport { createRPCClient } from 'vite-dev-rpc'\nimport type { ViteHotContext } from 'vite-hot-client'\nimport type { VueRuntimeRpc } from '../types'\nimport { getPerformanceCollector } from './performanceHook'\nimport { createRuntimeDevtoolsRpc } from './devtoolsBridge'\n\nconst PINIA_INSPECTOR_ID = 'pinia'\nconst COMPONENTS_INSPECTOR_ID = 'components'\nconst COMPONENT_HIGHLIGHT_DURATION = 5000\n\nlet highlightComponentTimeout: ReturnType<typeof setTimeout> | undefined\n\n/**\n * 同步初始化 Vue Devtools hook。\n *\n * Vue 会在应用 mount 时读取全局 hook 并注册 app,因此该函数必须在任何异步等待前执行。\n */\nexport function initializeVueDevtoolsHook(): void {\n devtools.init()\n}\n\n/**\n * 安装 Vue Runtime RPC。\n *\n * RPC 依赖 Vite hot context 传输消息,因此只能在 hot context 创建成功后安装。\n */\nexport function installVueBridge(hot: ViteHotContext): void {\n const rpcRef: { current?: VueRuntimeRpc } = {}\n const rpc = createRPCClient<VueRuntimeRpc, VueRuntimeRpc>(\n 'vite-plugin-vue-mcp-next',\n hot,\n createClientVueRuntimeRpc(() => {\n if (!rpcRef.current) {\n throw new Error('Vue runtime RPC is not initialized')\n }\n return rpcRef.current\n }),\n { timeout: -1 }\n )\n rpcRef.current = rpc\n}\n\n/**\n * 创建浏览器端 Vue RPC 实现。\n *\n * 函数单独拆分可以让每个 Vue 能力的错误边界集中处理,避免 MCP 请求因为某个组件缺失而崩溃。\n */\nfunction createClientVueRuntimeRpc(getRpc: () => VueRuntimeRpc): VueRuntimeRpc {\n return {\n ...createRuntimeDevtoolsRpc(getRpc),\n async getInspectorTree(query) {\n const inspectorTree = await devtools.api.getInspectorTree({\n inspectorId: COMPONENTS_INSPECTOR_ID,\n filter: query.componentName ?? ''\n })\n getRpc().onInspectorTreeUpdated(query.event, inspectorTree[0])\n },\n onInspectorTreeUpdated: () => undefined,\n async getInspectorState(query) {\n const targetNode = await findComponentNode(query.componentName)\n if (!targetNode) {\n getRpc().onInspectorStateUpdated(\n query.event,\n createMissingComponentError(query.componentName)\n )\n return\n }\n\n const inspectorState = await devtools.api.getInspectorState({\n inspectorId: COMPONENTS_INSPECTOR_ID,\n nodeId: targetNode.id\n })\n getRpc().onInspectorStateUpdated(query.event, stringify(inspectorState))\n },\n onInspectorStateUpdated: () => undefined,\n async editComponentState(query) {\n const targetNode = await findComponentNode(query.componentName)\n if (!targetNode) {\n return\n }\n\n devtools.ctx.api.editInspectorState({\n app: null,\n inspectorId: COMPONENTS_INSPECTOR_ID,\n nodeId: targetNode.id,\n path: query.path,\n state: {\n remove: false,\n value: parseStateValue(query.value, query.valueType)\n },\n type: query.valueType,\n set: setStateValue\n })\n },\n async highlightComponent(query) {\n const targetNode = await findComponentNode(query.componentName)\n if (!targetNode) {\n return\n }\n\n if (highlightComponentTimeout) {\n clearTimeout(highlightComponentTimeout)\n }\n\n callVueDevtoolsHook('componentHighlight', { uid: targetNode.id })\n highlightComponentTimeout = setTimeout(() => {\n callVueDevtoolsHook('componentUnhighlight')\n }, COMPONENT_HIGHLIGHT_DURATION)\n },\n getRouterInfo(query) {\n getRpc().onRouterInfoUpdated(\n query.event,\n JSON.stringify(devtoolsRouterInfo, null, 2)\n )\n },\n onRouterInfoUpdated: () => undefined,\n async getPiniaTree(query) {\n const inspectorTree = await withPiniaHighPerfDisabled(() =>\n devtools.api.getInspectorTree({\n inspectorId: PINIA_INSPECTOR_ID,\n filter: ''\n })\n )\n getRpc().onPiniaTreeUpdated(query.event, inspectorTree)\n },\n onPiniaTreeUpdated: () => undefined,\n async getPiniaState(query) {\n const result = await withPiniaHighPerfDisabled(async () => {\n const payload = {\n inspectorId: PINIA_INSPECTOR_ID,\n nodeId: query.storeName\n }\n const inspector = getInspector(payload.inspectorId)\n\n if (inspector) {\n inspector.selectedNodeId = payload.nodeId\n }\n\n return devtools.ctx.api.getInspectorState(payload)\n })\n getRpc().onPiniaInfoUpdated(query.event, stringify(result))\n },\n onPiniaInfoUpdated: () => undefined,\n async recordPerformance(query) {\n const collector = getPerformanceCollector()\n\n if (!collector) {\n getRpc().onPerformanceRecorded(\n query.event,\n createPerformanceUnavailableError()\n )\n return\n }\n\n try {\n const report = await collector.recordOnce({\n durationMs: query.durationMs,\n includeMemory: query.includeMemory,\n includeStacks: query.includeStacks\n })\n getRpc().onPerformanceRecorded(query.event, report)\n } catch (error) {\n getRpc().onPerformanceRecorded(\n query.event,\n createPerformanceError(error)\n )\n }\n },\n onPerformanceRecorded: () => undefined,\n startPerformanceRecording(query) {\n const collector = getPerformanceCollector()\n\n if (!collector) {\n getRpc().onPerformanceRecordingStarted(\n query.event,\n createPerformanceUnavailableError()\n )\n return\n }\n\n try {\n const recordingId = collector.start({\n includeMemory: query.includeMemory,\n includeStacks: query.includeStacks\n })\n getRpc().onPerformanceRecordingStarted(query.event, {\n ok: true,\n recordingId,\n startedAt: Date.now(),\n source: 'hook'\n })\n } catch (error) {\n getRpc().onPerformanceRecordingStarted(\n query.event,\n createPerformanceError(error)\n )\n }\n },\n onPerformanceRecordingStarted: () => undefined,\n stopPerformanceRecording(query) {\n const collector = getPerformanceCollector()\n\n if (!collector) {\n getRpc().onPerformanceRecordingStopped(\n query.event,\n createPerformanceUnavailableError()\n )\n return\n }\n\n try {\n const report = collector.stop(query.recordingId)\n getRpc().onPerformanceRecordingStopped(query.event, report)\n } catch (error) {\n getRpc().onPerformanceRecordingStopped(\n query.event,\n createPerformanceError(error)\n )\n }\n },\n onPerformanceRecordingStopped: () => undefined\n }\n}\n\n/**\n * Vue DevTools editInspectorState 需要的 set 回调。\n *\n * 运行时 bridge 只负责把 MCP 请求转交给 DevTools API,实际状态写入由 DevTools 内部完成;\n * 这里提供保守赋值实现,保证新版类型要求满足且不引入额外依赖。\n */\nfunction setStateValue(\n object: unknown,\n path?: string | string[],\n value?: unknown\n): void {\n if (!object || typeof object !== 'object' || !path) {\n return\n }\n\n const keys = Array.isArray(path) ? path : [path]\n const lastKey = keys.at(-1)\n\n if (!lastKey) {\n return\n }\n\n ;(object as Record<string, unknown>)[lastKey] = value\n}\n\n/**\n * 按 MCP 输入类型解析组件状态值。\n *\n * DevTools Kit 当前只接收最终 value,不再接收旧版本的 type 字段,\n * 因此这里在 bridge 内部完成基础类型转换。\n */\nfunction parseStateValue(value: string, valueType: string): unknown {\n if (valueType === 'number') {\n return Number(value)\n }\n\n if (valueType === 'boolean') {\n return value === 'true'\n }\n\n if (valueType === 'object' || valueType === 'array') {\n try {\n return JSON.parse(value) as unknown\n } catch {\n return value\n }\n }\n\n return value\n}\n\n/**\n * 调用 Vue DevTools 内部 hook。\n *\n * 当前 @vue/devtools-kit 的公开类型没有覆盖组件高亮 hook,但运行时仍提供该能力;\n * 单独收敛类型逃逸可以避免把不稳定内部事件扩散到业务逻辑。\n */\nfunction callVueDevtoolsHook(name: string, payload?: unknown): void {\n const hooks = devtools.ctx.hooks as {\n callHook: (event: string, payload?: unknown) => void\n }\n hooks.callHook(name, payload)\n}\n\n/**\n * 生成性能 RPC 不可用的统一错误回包。\n *\n * performance collector 只在 runtime client 完成安装后存在;如果 Vue bridge 先被调用,\n * 与其让请求悬空,不如明确告诉服务端稍后重试。\n */\nfunction createPerformanceUnavailableError(): {\n readonly ok: false\n readonly error: string\n} {\n return {\n ok: false,\n error: 'Performance collector is not initialized'\n }\n}\n\n/**\n * 把性能 RPC 异常收敛成结构化错误。\n *\n * 运行态采集不应该把异常直接抛回 RPC 调用链,否则会让整个 bridge 请求失败。\n */\nfunction createPerformanceError(error: unknown): {\n readonly ok: false\n readonly error: string\n} {\n return {\n ok: false,\n error: error instanceof Error ? error.message : String(error)\n }\n}\n\n/**\n * 查找组件节点。\n *\n * 组件名来自 MCP 输入,运行时必须处理找不到组件的情况,而不是直接访问 undefined.id。\n */\nasync function findComponentNode(\n componentName: string\n): Promise<{ id: string; name?: string; children?: unknown[] } | undefined> {\n const inspectorTree = await devtools.api.getInspectorTree({\n inspectorId: COMPONENTS_INSPECTOR_ID,\n filter: ''\n })\n const nodes = flattenTree(inspectorTree[0])\n\n return nodes.find((node) => node.name === componentName)\n}\n\n/**\n * 展平 Vue inspector tree。\n *\n * Vue DevTools 返回树状结构,按组件名查找状态和高亮目标时需要递归展开。\n */\nfunction flattenTree(\n root: unknown\n): Array<{ id: string; name?: string; children?: unknown[] }> {\n const result: Array<{ id: string; name?: string; children?: unknown[] }> = []\n\n const traverse = (node: unknown): void => {\n if (!isInspectorNode(node)) {\n return\n }\n\n result.push(node)\n node.children?.forEach((child) => {\n traverse(child)\n })\n }\n\n traverse(root)\n return result\n}\n\n/**\n * 校验 Vue inspector 节点的最小结构。\n *\n * DevTools 数据结构可能随版本变化,使用窄类型保护可以降低运行时异常风险。\n */\nfunction isInspectorNode(\n node: unknown\n): node is { id: string; name?: string; children?: unknown[] } {\n return Boolean(\n node &&\n typeof node === 'object' &&\n typeof (node as { id?: unknown }).id === 'string'\n )\n}\n\n/**\n * 临时关闭 Pinia high perf mode 后执行读取。\n *\n * Pinia inspector 在高性能模式下可能不返回完整状态,读取后恢复原状态可以避免影响用户调试体验。\n */\nasync function withPiniaHighPerfDisabled<T>(\n callback: () => Promise<T>\n): Promise<T> {\n const highPerfModeEnabled = devtoolsState.highPerfModeEnabled\n\n if (highPerfModeEnabled) {\n toggleHighPerfMode(false)\n }\n\n try {\n return await callback()\n } finally {\n if (highPerfModeEnabled) {\n toggleHighPerfMode(true)\n }\n }\n}\n\n/**\n * 创建组件缺失错误。\n *\n * 返回结构化错误比抛异常更适合 MCP 场景,AI 可以直接把原因反馈给用户。\n */\nfunction createMissingComponentError(componentName: string): {\n ok: false\n error: string\n} {\n return {\n ok: false,\n error: `component not found: ${componentName}`\n }\n}\n","import { truncateText } from '../shared/sanitize'\nimport type { DomOptions } from '../types'\n\n/**\n * DOM 节点快照。\n *\n * MCP 不应该返回真实 DOM 节点对象,而应该返回可序列化结构,便于 AI 理解和传输。\n */\nexport interface DomNodeSnapshot {\n /** 节点标签名,文本节点使用 `#text`。 */\n readonly tag: string\n /** 节点属性,敏感字段会被脱敏。 */\n readonly attrs?: Record<string, string>\n /** 节点文本,按配置截断。 */\n readonly text?: string\n /** 子节点,受最大深度和最大节点数限制。 */\n readonly children?: DomNodeSnapshot[]\n}\n\n/**\n * selector 查询结果。\n *\n * 查询工具只返回定位所需的摘要信息,避免把完整节点对象暴露给 MCP 客户端。\n */\nexport interface DomElementQueryResult {\n /** 元素标签名,用于快速判断命中的节点类型。 */\n readonly tag: string\n /** 元素聚合文本,用于 AI 判断该节点是否是目标控件。 */\n readonly text: string\n /** 元素属性快照,敏感字段会被脱敏。 */\n readonly attrs: Record<string, string>\n /** 元素布局矩形,便于后续判断可见区域和点击位置。 */\n readonly rect: Record<string, number>\n}\n\n/**\n * 创建裁剪后的 DOM 快照。\n *\n * DOM 输出必须裁剪,因为 MCP 上下文有限,大页面直接返回会导致 AI 无法消费。\n */\nexport function createDomSnapshot(\n root: Element,\n options: Required<DomOptions>\n): DomNodeSnapshot {\n let count = 0\n\n /**\n * 递归访问 DOM 节点。\n *\n * 将递归放在闭包内可以共享节点计数,确保 maxNodes 是整棵树的全局限制。\n */\n function visit(node: Node, depth: number): DomNodeSnapshot | null {\n if (count >= options.maxNodes || depth > options.maxDepth) {\n return null\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n return createTextSnapshot(node, options, () => {\n count += 1\n })\n }\n\n if (!(node instanceof Element)) {\n return null\n }\n\n const tag = node.tagName.toLowerCase()\n\n if (['script', 'style', 'noscript'].includes(tag)) {\n return null\n }\n\n count += 1\n\n return createElementSnapshot(node, tag, (child) => visit(child, depth + 1))\n }\n\n return visit(root, 0) ?? { tag: root.tagName.toLowerCase() }\n}\n\n/**\n * 查询 DOM 元素摘要。\n *\n * selector 查询用于让 AI 快速定位关键元素,不需要返回整棵 DOM。\n */\nexport function queryDomElements(\n selector: string,\n limit: number\n): DomElementQueryResult[] {\n return Array.from(document.querySelectorAll(selector))\n .slice(0, limit)\n .map((element) => ({\n tag: element.tagName.toLowerCase(),\n text: element.textContent.trim(),\n attrs: collectAttrs(element),\n rect: serializeRect(element.getBoundingClientRect())\n }))\n}\n\n/**\n * 创建文本节点快照。\n *\n * 空白文本在调试时通常是布局噪声,过滤它们可以让 AI 更专注于真实内容。\n */\nfunction createTextSnapshot(\n node: Node,\n options: Required<DomOptions>,\n markVisited: () => void\n): DomNodeSnapshot | null {\n const text = node.textContent?.trim()\n\n if (!text) {\n return null\n }\n\n markVisited()\n\n return { tag: '#text', text: truncateText(text, options.maxTextLength).text }\n}\n\n/**\n * 创建元素节点快照。\n *\n * 属性和子节点拆开处理,是为了后续可以单独扩展属性脱敏或节点过滤策略。\n */\nfunction createElementSnapshot(\n node: Element,\n tag: string,\n visitChild: (child: Node) => DomNodeSnapshot | null\n): DomNodeSnapshot {\n const attrs = collectAttrs(node)\n const children = Array.from(node.childNodes)\n .map((child) => visitChild(child))\n .filter((child): child is DomNodeSnapshot => Boolean(child))\n\n return {\n tag,\n ...(Object.keys(attrs).length ? { attrs } : {}),\n ...(children.length ? { children } : {})\n }\n}\n\n/**\n * 收集元素属性并隐藏敏感值。\n *\n * 密码输入框的 value 不能泄露给 MCP 客户端,即使它只在本地开发环境使用。\n */\nfunction collectAttrs(element: Element): Record<string, string> {\n const attrs: Record<string, string> = {}\n\n for (const attr of Array.from(element.attributes)) {\n attrs[attr.name] = attr.value\n }\n\n if (element instanceof HTMLInputElement && element.type === 'password') {\n attrs.value = '[masked]'\n }\n\n return attrs\n}\n\n/**\n * 序列化 DOMRect。\n *\n * 浏览器返回的 DOMRect 不是普通 JSON 对象,显式挑选字段可以让 MCP 输出稳定且可测试。\n */\nfunction serializeRect(rect: DOMRect): Record<string, number> {\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left\n }\n}\n","/**\n * 运行时脚本执行请求。\n *\n * Hook fallback 仅支持表达式风格执行,复杂语句执行优先交给 CDP adapter。\n */\nexport interface RuntimeEvaluateRequest {\n /** 需要执行的表达式。 */\n readonly expression: string\n /** 是否等待 Promise 结果,默认由调用方决定。 */\n readonly awaitPromise?: boolean\n /** 执行超时时间,避免页面长任务阻塞调试链路。 */\n readonly timeoutMs: number\n}\n\n/**\n * 执行表达式风格脚本。\n *\n * 使用 Function 构造器而不是直接 eval,可以明确限定为表达式返回值;\n * 语句级调试留给 CDP Runtime.evaluate,以减少 Hook fallback 的行为边界。\n */\nexport async function evaluateExpression(\n request: RuntimeEvaluateRequest\n): Promise<unknown> {\n const value = runExpression(request.expression)\n const result =\n request.awaitPromise === false ? value : await Promise.resolve(value)\n\n return Promise.race([\n Promise.resolve(result),\n createTimeout(request.timeoutMs)\n ])\n}\n\n/**\n * 执行表达式并返回结果。\n *\n * 这里必须动态执行用户传入表达式,但 MCP 工具默认关闭该能力,只有用户显式配置\n * `runtime.evaluate.enabled` 后才会暴露入口;因此把例外集中在该函数,便于后续安全审查。\n */\nfunction runExpression(expression: string): unknown {\n // eslint-disable-next-line @typescript-eslint/no-implied-eval, @typescript-eslint/no-unsafe-call -- evaluate_script 的职责就是执行显式授权后的调试表达式。\n return new Function(`return (${expression})`)() as unknown\n}\n\n/**\n * 创建执行超时 Promise。\n *\n * 控制台执行必须有硬边界,否则 MCP 调用可能被页面内长任务永久挂起。\n */\nfunction createTimeout(timeoutMs: number): Promise<never> {\n return new Promise((_, reject) => {\n window.setTimeout(() => {\n reject(\n new Error(`evaluate_script timed out after ${String(timeoutMs)}ms`)\n )\n }, timeoutMs)\n })\n}\n","import type {\n RuntimeStorageRequest,\n RuntimeStorageResult,\n StorageScope\n} from '../types'\n\n/**\n * Runtime 存储桥接负责访问页面同源存储。\n *\n * 该文件只封装浏览器公开 Web API;Cookie 仅覆盖 document.cookie 可见的同源非 HttpOnly 值,\n * 浏览器级 Cookie 和 HttpOnly 查询仍必须交给 CDP。\n */\n\n/** Runtime 存储桥接运行环境,测试可注入内存实现,浏览器端注入真实 window。 */\nexport interface RuntimeStorageEnvironment {\n /** 当前页面 origin,用于拒绝跨源误操作。 */\n readonly origin: string\n /** 当前页面同源 localStorage。 */\n readonly localStorage: Storage\n /** 当前页面同源 sessionStorage。 */\n readonly sessionStorage: Storage\n /** 当前页面同源 IndexedDB 工厂。 */\n readonly indexedDB?: Pick<IDBFactory, 'databases' | 'open'> | MemoryIndexedDb\n /** 当前页面 document.cookie 访问器,测试可注入内存实现。 */\n readonly cookie?: RuntimeCookieAccess\n}\n\n/** Runtime 存储桥接服务,暴露给 Vite RPC 的浏览器侧实现复用。 */\nexport interface RuntimeStorageBridge {\n /** 根据固定动作访问同源存储,所有错误都会被收敛成结构化结果。 */\n manageStorage(request: RuntimeStorageRequest): Promise<RuntimeStorageResult>\n}\n\n/** Runtime Cookie 访问器,保留 document.cookie 的 getter/setter 语义以便测试替换。 */\nexport interface RuntimeCookieAccess {\n /** 读取当前页面可见 Cookie 字符串。 */\n get(): string\n /** 写入一条 document.cookie 指令。 */\n set(value: string): void\n}\n\n/** 测试用内存 IndexedDB 形态,避免单元测试依赖真实浏览器事务实现。 */\nexport interface MemoryIndexedDb {\n readonly stores: Map<string, Map<string, unknown>>\n databases(): Promise<Array<{ readonly name: string | null; readonly version: number }>>\n}\n\n/**\n * 创建 Runtime 存储桥接。\n *\n * 参数化环境让单元测试无需真实浏览器,也能验证同源限制和 Web Storage 读写删边界。\n */\nexport function createRuntimeStorageBridge(\n env: RuntimeStorageEnvironment\n): RuntimeStorageBridge {\n return {\n async manageStorage(request) {\n try {\n return await manageRuntimeStorage(env, request)\n } catch (error) {\n return createRuntimeStorageError(\n request,\n error instanceof Error ? error.message : String(error)\n )\n }\n }\n }\n}\n\nasync function manageRuntimeStorage(\n env: RuntimeStorageEnvironment,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (request.origin !== env.origin) {\n return createRuntimeStorageError(\n request,\n 'Runtime storage access is limited to the current page origin'\n )\n }\n\n if (request.scope === 'cookie') {\n return manageRuntimeCookie(env, request)\n }\n\n if (request.scope === 'indexedDB') {\n return manageRuntimeIndexedDb(env, request)\n }\n\n return manageRuntimeWebStorage(getWebStorage(env, request.scope), request)\n}\n\nfunction manageRuntimeCookie(\n env: RuntimeStorageEnvironment,\n request: RuntimeStorageRequest\n): RuntimeStorageResult {\n if (!env.cookie) {\n return createRuntimeStorageError(\n request,\n 'Runtime cookie access is unavailable',\n ['document.cookie is not available in this runtime environment']\n )\n }\n\n if (request.action === 'list') {\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n cookies: readRuntimeCookies(env.cookie)\n })\n }\n\n if (request.action === 'get') {\n assertCookieName(request)\n\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n cookies: readRuntimeCookies(env.cookie).filter(\n (cookie) => cookie.name === request.cookie.name\n )\n })\n }\n\n if (request.action === 'set') {\n assertCookieName(request)\n env.cookie.set(createRuntimeCookieWrite(request))\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'delete') {\n assertCookieName(request)\n env.cookie.set(createRuntimeCookieDelete(request))\n\n return createRuntimeStorageSuccess(request, {\n deletedCount: 1,\n skippedHttpOnlyCount: 0,\n limitations: ['HttpOnly cookies are invisible to runtime cookie access']\n })\n }\n\n const cookies = readRuntimeCookies(env.cookie)\n\n for (const cookie of cookies) {\n env.cookie.set(\n createRuntimeCookieDelete({\n ...request,\n cookie: {\n name: cookie.name,\n path: request.cookie?.path\n }\n })\n )\n }\n\n return createRuntimeStorageSuccess(request, {\n deletedCount: cookies.length,\n skippedHttpOnlyCount: 0,\n limitations: ['HttpOnly cookies are invisible to runtime cookie access']\n })\n}\n\nfunction getWebStorage(\n env: RuntimeStorageEnvironment,\n scope: StorageScope\n): Storage {\n return scope === 'sessionStorage' ? env.sessionStorage : env.localStorage\n}\n\nfunction manageRuntimeWebStorage(\n storage: Storage,\n request: RuntimeStorageRequest\n): RuntimeStorageResult {\n if (request.action === 'list') {\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n scope: request.scope,\n entries: readStorageEntries(storage)\n })\n }\n\n if (request.action === 'get') {\n assertStorageKey(request)\n\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n scope: request.scope,\n key: request.key,\n value: storage.getItem(request.key)\n })\n }\n\n if (request.action === 'set') {\n assertStorageKey(request)\n storage.setItem(request.key, request.value ?? '')\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n storage.removeItem(request.key)\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n storage.clear()\n\n return createRuntimeStorageSuccess(request, { ok: true })\n}\n\nasync function manageRuntimeIndexedDb(\n env: RuntimeStorageEnvironment,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (!env.indexedDB?.databases) {\n return createRuntimeStorageError(request, 'IndexedDB metadata API is unavailable')\n }\n\n if (request.action === 'list') {\n const databases = await env.indexedDB.databases()\n\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n scope: request.scope,\n databases: databases.map((database) => ({\n name: database.name,\n version: database.version\n }))\n })\n }\n\n assertIndexedDbTarget(request)\n\n if ('stores' in env.indexedDB) {\n return manageMemoryIndexedDb(env.indexedDB, request)\n }\n\n return manageBrowserIndexedDb(env.indexedDB, request)\n}\n\nfunction manageMemoryIndexedDb(\n indexedDB: MemoryIndexedDb,\n request: RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n }\n): RuntimeStorageResult {\n const storeId = `${request.databaseName}:${request.objectStoreName}`\n const store = indexedDB.stores.get(storeId) ?? new Map<string, unknown>()\n indexedDB.stores.set(storeId, store)\n\n if (request.action === 'get') {\n assertStorageKey(request)\n\n return createRuntimeStorageSuccess(request, {\n key: request.key,\n value: store.get(request.key) ?? null\n })\n }\n\n if (request.action === 'set') {\n assertStorageKey(request)\n store.set(request.key, parseIndexedDbValue(request.value))\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n store.delete(request.key)\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n store.clear()\n\n return createRuntimeStorageSuccess(request, { ok: true })\n}\n\nasync function manageBrowserIndexedDb(\n indexedDB: Pick<IDBFactory, 'open'>,\n request: RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n }\n): Promise<RuntimeStorageResult> {\n const database = await openIndexedDbForRequest(indexedDB, request)\n\n try {\n return await executeIndexedDbTransaction(database, request)\n } finally {\n database.close()\n }\n}\n\nfunction openIndexedDb(\n indexedDB: Pick<IDBFactory, 'open'>,\n databaseName: string\n): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(databaseName)\n request.onerror = () => {\n reject(request.error ?? new Error('IndexedDB open failed'))\n }\n request.onsuccess = () => {\n resolve(request.result)\n }\n })\n}\n\n/**\n * 按操作意图打开 IndexedDB。\n *\n * 浏览器原生 IndexedDB 只能在版本升级阶段创建 object store;set 操作代表明确写入意图,\n * 因此允许自动升版本建 store,避免 MCP 使用方必须先写一段页面脚本初始化数据库。\n */\nasync function openIndexedDbForRequest(\n indexedDB: Pick<IDBFactory, 'open'>,\n request: RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n }\n): Promise<IDBDatabase> {\n const database = await openIndexedDb(indexedDB, request.databaseName)\n\n if (\n request.action !== 'set' ||\n database.objectStoreNames.contains(request.objectStoreName)\n ) {\n return database\n }\n\n const version = database.version + 1\n database.close()\n\n return openIndexedDbWithStore(indexedDB, {\n databaseName: request.databaseName,\n objectStoreName: request.objectStoreName,\n version\n })\n}\n\n/**\n * 升级 IndexedDB 并创建缺失的 object store。\n *\n * 该函数只服务 set 的自动初始化场景;读、删、清仍要求目标 store 已存在,以便暴露错误而不是\n * 静默创建空库造成误判。\n */\nfunction openIndexedDbWithStore(\n indexedDB: Pick<IDBFactory, 'open'>,\n options: {\n readonly databaseName: string\n readonly objectStoreName: string\n readonly version: number\n }\n): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(options.databaseName, options.version)\n request.onupgradeneeded = () => {\n const database = request.result\n\n if (!database.objectStoreNames.contains(options.objectStoreName)) {\n database.createObjectStore(options.objectStoreName)\n }\n }\n request.onerror = () => {\n reject(request.error ?? new Error('IndexedDB upgrade failed'))\n }\n request.onsuccess = () => {\n resolve(request.result)\n }\n })\n}\n\nfunction executeIndexedDbTransaction(\n database: IDBDatabase,\n request: RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n }\n): Promise<RuntimeStorageResult> {\n return new Promise((resolve, reject) => {\n const mode = request.action === 'get' ? 'readonly' : 'readwrite'\n const transaction = database.transaction(request.objectStoreName, mode)\n const store = transaction.objectStore(request.objectStoreName)\n\n transaction.onerror = () => {\n reject(transaction.error ?? new Error('IndexedDB transaction failed'))\n }\n\n if (request.action === 'get') {\n assertStorageKey(request)\n const getRequest = store.get(request.key)\n getRequest.onerror = () => {\n reject(getRequest.error ?? new Error('IndexedDB get failed'))\n }\n getRequest.onsuccess = () => {\n const value: unknown = getRequest.result ?? null\n resolve(\n createRuntimeStorageSuccess(request, {\n key: request.key,\n value\n })\n )\n }\n return\n }\n\n if (request.action === 'set') {\n assertStorageKey(request)\n store.put(parseIndexedDbValue(request.value), request.key)\n transaction.oncomplete = () => {\n resolve(createRuntimeStorageSuccess(request, { ok: true }))\n }\n return\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n store.delete(request.key)\n transaction.oncomplete = () => {\n resolve(createRuntimeStorageSuccess(request, { ok: true }))\n }\n return\n }\n\n store.clear()\n transaction.oncomplete = () => {\n resolve(createRuntimeStorageSuccess(request, { ok: true }))\n }\n })\n}\n\nfunction readStorageEntries(storage: Storage): Array<{\n readonly key: string\n readonly value: string\n}> {\n const entries: Array<{ key: string; value: string }> = []\n\n for (let index = 0; index < storage.length; index += 1) {\n const key = storage.key(index)\n\n if (!key) {\n continue\n }\n\n const value = storage.getItem(key)\n\n if (value === null) {\n continue\n }\n\n entries.push({ key, value })\n }\n\n return entries\n}\n\nfunction readRuntimeCookies(cookieAccess: RuntimeCookieAccess): Array<{\n readonly name: string\n readonly value: string\n}> {\n return cookieAccess\n .get()\n .split(';')\n .map((item) => item.trim())\n .filter(Boolean)\n .map((item) => {\n const separatorIndex = item.indexOf('=')\n\n if (separatorIndex === -1) {\n return { name: decodeCookiePart(item), value: '' }\n }\n\n return {\n name: decodeCookiePart(item.slice(0, separatorIndex)),\n value: decodeCookiePart(item.slice(separatorIndex + 1))\n }\n })\n}\n\nfunction createRuntimeCookieWrite(request: RuntimeStorageRequest & {\n readonly cookie: NonNullable<RuntimeStorageRequest['cookie']>\n}): string {\n const value = request.cookie.value ?? request.value ?? ''\n const parts = [\n `${encodeURIComponent(request.cookie.name)}=${encodeURIComponent(value)}`\n ]\n\n appendRuntimeCookieAttributes(parts, request.cookie)\n\n return parts.join('; ')\n}\n\nfunction createRuntimeCookieDelete(request: RuntimeStorageRequest & {\n readonly cookie: NonNullable<RuntimeStorageRequest['cookie']>\n}): string {\n const parts = [\n `${encodeURIComponent(request.cookie.name)}=`,\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'Max-Age=0'\n ]\n\n appendRuntimeCookieAttributes(parts, {\n path: request.cookie.path,\n domain: request.cookie.domain\n })\n\n return parts.join('; ')\n}\n\nfunction appendRuntimeCookieAttributes(\n parts: string[],\n cookie: Partial<NonNullable<RuntimeStorageRequest['cookie']>>\n): void {\n if (cookie.path) {\n parts.push(`Path=${cookie.path}`)\n }\n\n if (cookie.domain) {\n parts.push(`Domain=${cookie.domain}`)\n }\n\n if (cookie.expires !== undefined) {\n parts.push(`Expires=${new Date(cookie.expires * 1000).toUTCString()}`)\n }\n\n if (cookie.sameSite) {\n parts.push(`SameSite=${normalizeRuntimeSameSite(cookie.sameSite)}`)\n }\n\n if (cookie.secure) {\n parts.push('Secure')\n }\n}\n\nfunction normalizeRuntimeSameSite(\n sameSite: 'strict' | 'lax' | 'none'\n): 'Strict' | 'Lax' | 'None' {\n if (sameSite === 'strict') {\n return 'Strict'\n }\n\n if (sameSite === 'lax') {\n return 'Lax'\n }\n\n return 'None'\n}\n\nfunction decodeCookiePart(value: string): string {\n try {\n return decodeURIComponent(value)\n } catch {\n return value\n }\n}\n\nfunction assertStorageKey(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & { readonly key: string } {\n if (!request.key) {\n throw new Error('Storage key is required for this operation')\n }\n}\n\nfunction assertCookieName(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & {\n readonly cookie: NonNullable<RuntimeStorageRequest['cookie']>\n} {\n if (!request.cookie?.name) {\n throw new Error('Cookie name is required for this operation')\n }\n}\n\nfunction assertIndexedDbTarget(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n} {\n if (!request.databaseName || !request.objectStoreName) {\n throw new Error('IndexedDB databaseName and objectStoreName are required')\n }\n}\n\nfunction parseIndexedDbValue(value?: string): unknown {\n if (value === undefined) {\n return null\n }\n\n try {\n return JSON.parse(value) as unknown\n } catch {\n return value\n }\n}\n\nfunction createRuntimeStorageSuccess(\n request: RuntimeStorageRequest,\n data: unknown\n): RuntimeStorageResult {\n return {\n ok: true,\n source: 'hook',\n action: request.action,\n scope: request.scope,\n data\n }\n}\n\nfunction createRuntimeStorageError(\n request: RuntimeStorageRequest,\n error: string,\n limitations?: string[]\n): RuntimeStorageResult {\n return {\n ok: false,\n source: 'hook',\n action: request.action,\n scope: request.scope,\n error,\n limitations\n }\n}\n","import type { VueRuntimeRpc } from '../types'\nimport { createDomSnapshot, queryDomElements } from './domSnapshot'\nimport { evaluateExpression } from './evaluateExpression'\nimport { takeRuntimeScreenshot } from './screenshot'\nimport { createRuntimeStorageBridge } from './storageBridge'\n\n/**\n * 创建通用 Runtime DevTools RPC。\n *\n * 这些能力是 CDP 不可用时的 Hook fallback,和 Vue 专属能力放在同一条 Vite RPC 通道里,\n * 可以避免再维护第二套浏览器到服务端的请求协议。\n */\nexport function createRuntimeDevtoolsRpc(\n getRpc: () => VueRuntimeRpc\n): Pick<\n VueRuntimeRpc,\n | 'getDomTree'\n | 'onDomTreeUpdated'\n | 'queryDom'\n | 'onDomQueryUpdated'\n | 'reloadPage'\n | 'onPageReloaded'\n | 'evaluateScript'\n | 'onEvaluateScriptUpdated'\n | 'takeScreenshot'\n | 'onScreenshotTaken'\n | 'manageStorage'\n | 'onStorageUpdated'\n> {\n return {\n getDomTree(options) {\n getRpc().onDomTreeUpdated(\n options.event,\n createDomSnapshot(document.documentElement, {\n maxDepth: options.maxDepth,\n maxNodes: options.maxNodes,\n maxTextLength: options.maxTextLength\n })\n )\n },\n onDomTreeUpdated: () => undefined,\n queryDom(options) {\n getRpc().onDomQueryUpdated(\n options.event,\n queryDomElements(options.selector, options.limit)\n )\n },\n onDomQueryUpdated: () => undefined,\n reloadPage(options) {\n getRpc().onPageReloaded(options.event, { ok: true, source: 'hook' })\n setTimeout(() => {\n window.location.reload()\n }, 0)\n },\n onPageReloaded: () => undefined,\n async evaluateScript(options) {\n try {\n getRpc().onEvaluateScriptUpdated(options.event, {\n ok: true,\n value: await evaluateExpression(options)\n })\n } catch (error) {\n getRpc().onEvaluateScriptUpdated(options.event, {\n ok: false,\n error: error instanceof Error ? error.message : String(error)\n })\n }\n },\n onEvaluateScriptUpdated: () => undefined,\n async takeScreenshot(options) {\n try {\n getRpc().onScreenshotTaken(\n options.event,\n await takeRuntimeScreenshot(options)\n )\n } catch (error) {\n getRpc().onScreenshotTaken(options.event, {\n ok: false,\n error: error instanceof Error ? error.message : String(error)\n })\n }\n },\n onScreenshotTaken: () => undefined,\n async manageStorage(options) {\n const bridge = createRuntimeStorageBridge({\n origin: window.location.origin,\n localStorage: window.localStorage,\n sessionStorage: window.sessionStorage,\n indexedDB: window.indexedDB,\n cookie: {\n get: () => window.document.cookie,\n set: (value) => {\n window.document.cookie = value\n }\n }\n })\n getRpc().onStorageUpdated(\n options.event,\n await bridge.manageStorage(options)\n )\n },\n onStorageUpdated: () => undefined\n }\n}\n"],"mappings":"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","names":["nanoid","nanoid","nanoid","nanoid","nanoid","nanoid"]}
1
+ {"version":3,"sources":["../../src/runtime/client.ts","../../src/shared/limits.ts","../../src/constants.ts","../../src/runtime/consoleHook.ts","../../src/shared/serialization.ts","../../src/runtime/elementRegistry.ts","../../src/runtime/elementPicker.ts","../../src/shared/elementId.ts","../../src/shared/sanitize.ts","../../src/runtime/domSnapshot.ts","../../src/runtime/vueComponentLocator.ts","../../src/runtime/elementContext.ts","../../src/runtime/networkHook.ts","../../src/shared/url.ts","../../src/runtime/pageIdentity.ts","../../src/runtime/performanceHook.ts","../../src/performance/summary.ts","../../src/runtime/screenshot.ts","../../src/runtime/vueBridge.ts","../../src/runtime/evaluateExpression.ts","../../src/runtime/storageBridge.ts","../../src/runtime/devtoolsBridge.ts"],"sourcesContent":["/**\n * Runtime Client 是注入到浏览器页面的启动入口。\n *\n * 该文件负责协调 Vue、Console、Network 等浏览器端 hook 的安装,并通过 Vite hot context 上报页面状态。\n */\nimport { createHotContext } from 'vite-hot-client'\nimport {\n DEFAULT_OPTIONS,\n DEFAULT_RUNTIME_PAGE_HEARTBEAT_INTERVAL_MS,\n RUNTIME_PAGE_CONNECTED_EVENT,\n RUNTIME_PAGE_DISCONNECTED_EVENT,\n RUNTIME_PAGE_HEARTBEAT_EVENT\n} from '../constants'\nimport type { RuntimeClientOptions } from '../types'\nimport { installConsoleHook } from './consoleHook'\nimport { installElementPicker } from './elementPicker'\nimport {\n createElementContextResolver,\n setElementContextResolver\n} from './elementContext'\nimport { runtimeElementRegistry } from './elementRegistry'\nimport { installNetworkHook } from './networkHook'\nimport { getRuntimeClientId, getRuntimePageIdentity } from './pageIdentity'\nimport { installPerformanceHook } from './performanceHook'\nexport { setScreenshotModuleRegistry, setSnapdomLoader } from './screenshot'\nimport { initializeVueDevtoolsHook, installVueBridge } from './vueBridge'\nexport { evaluateExpression } from './evaluateExpression'\nexport type { RuntimeEvaluateRequest } from './evaluateExpression'\n\n/**\n * 启动浏览器端 Runtime Bridge。\n *\n * Vue Devtools hook 必须在等待 Vite hot context 前同步初始化,否则 Vue app 挂载时会错过注册窗口。\n */\nexport async function startRuntimeClient(\n runtimeOptions: RuntimeClientOptions = {\n elementPicker: DEFAULT_OPTIONS.elementPicker\n }\n): Promise<void> {\n initializeVueDevtoolsHook()\n\n const hot = await createHotContext('vite-plugin-vue-mcp-next', '/')\n\n if (!hot) {\n return\n }\n\n installVueBridge(hot)\n installElementPicker(runtimeOptions.elementPicker)\n\n const identity = getRuntimePageIdentity({\n href: window.location.href,\n title: document.title,\n runtimeClientId: getRuntimeClientId(window.sessionStorage, window),\n innerWidth: window.innerWidth,\n innerHeight: window.innerHeight,\n readyState: document.readyState\n })\n\n setElementContextResolver(\n createElementContextResolver({\n root: runtimeOptions.projectRoot ?? '/',\n registry: runtimeElementRegistry,\n querySelector(selector) {\n return document.querySelector(selector)\n }\n })\n )\n\n hot.send(RUNTIME_PAGE_CONNECTED_EVENT, identity)\n installRuntimePageLifecycle({\n pageId: identity.pageId,\n send: hot.send.bind(hot)\n })\n installPerformanceHook({\n pageId: identity.pageId,\n send(report) {\n hot.send('vite-plugin-vue-mcp-next:performance-record', report)\n }\n })\n installConsoleHook({\n pageId: identity.pageId,\n send(record) {\n hot.send('vite-plugin-vue-mcp-next:console-record', record)\n }\n })\n installNetworkHook({\n pageId: identity.pageId,\n maxBodySize: 100_000,\n maskHeaders: ['authorization', 'cookie', 'set-cookie'],\n send(record) {\n hot.send('vite-plugin-vue-mcp-next:network-record', record)\n }\n })\n}\n\n/**\n * 安装 runtime 页面生命周期上报。\n *\n * 该逻辑只负责上报连接、心跳和离开,不参与页面目标决策,避免把服务端语义带回浏览器侧。\n */\nfunction installRuntimePageLifecycle(options: {\n readonly pageId: string\n readonly send: (event: string, payload: unknown) => void\n}): void {\n let disconnected = false\n const heartbeatTimer = setInterval(() => {\n options.send(RUNTIME_PAGE_HEARTBEAT_EVENT, {\n pageId: options.pageId,\n timestamp: Date.now()\n })\n }, DEFAULT_RUNTIME_PAGE_HEARTBEAT_INTERVAL_MS)\n\n const disconnect = (): void => {\n if (disconnected) {\n return\n }\n\n disconnected = true\n clearInterval(heartbeatTimer)\n options.send(RUNTIME_PAGE_DISCONNECTED_EVENT, {\n pageId: options.pageId\n })\n }\n\n window.addEventListener('pagehide', disconnect, { once: true })\n window.addEventListener('beforeunload', disconnect, { once: true })\n}\n","/**\n * 运行时采集的默认限制集中定义。\n *\n * DOM、Console 和 Network 都可能持续产生大量数据;把限制放在共享模块里,\n * 可以让服务端工具、运行时 Hook 和测试使用同一套安全边界。\n */\n\n/** 默认 DOM 递归深度,保留主要结构,同时避免复杂页面把 MCP 上下文撑爆。 */\nexport const DEFAULT_DOM_MAX_DEPTH = 8\n\n/** 默认 DOM 节点上限,用于防止一次性返回整页巨量节点。 */\nexport const DEFAULT_DOM_MAX_NODES = 2000\n\n/** 默认文本截断长度,保留可定位内容但避免长文案污染调试上下文。 */\nexport const DEFAULT_DOM_MAX_TEXT_LENGTH = 300\n\n/** 默认 Console 缓存上限,适合开发态持续运行且不会无界增长。 */\nexport const DEFAULT_CONSOLE_MAX_RECORDS = 1000\n\n/** 默认 Network 缓存上限,覆盖常见调试窗口同时控制内存占用。 */\nexport const DEFAULT_NETWORK_MAX_RECORDS = 500\n\n/** 默认请求体和响应体最大采集长度,避免大文件响应进入 MCP 工具结果。 */\nexport const DEFAULT_NETWORK_MAX_BODY_SIZE = 100_000\n\n/**\n * 默认脱敏 header。\n *\n * 这些字段通常包含认证态或用户隐私,Network 工具默认隐藏它们可以降低误传风险。\n */\nexport const DEFAULT_MASK_HEADERS = [\n 'authorization',\n 'cookie',\n 'set-cookie'\n] as const\n\n/** 默认响应体截断标记,集中定义可以让 Hook 和 CDP 输出保持一致。 */\nexport const TRUNCATED_MARKER = '[truncated]'\n","import {\n DEFAULT_CONSOLE_MAX_RECORDS,\n DEFAULT_DOM_MAX_DEPTH,\n DEFAULT_DOM_MAX_NODES,\n DEFAULT_DOM_MAX_TEXT_LENGTH,\n DEFAULT_MASK_HEADERS,\n DEFAULT_NETWORK_MAX_BODY_SIZE,\n DEFAULT_NETWORK_MAX_RECORDS\n} from './shared/limits'\nimport type {\n McpClientConfigOptions,\n ResolvedVueMcpNextOptions,\n VueMcpNextOptions\n} from './types'\n\n/** 默认 MCP 挂载路径,使用双下划线前缀避免与业务路由冲突。 */\nexport const DEFAULT_MCP_PATH = '/__mcp'\n\n/** 默认截图最大响应体积,避免 base64 图片挤占 MCP 客户端上下文。 */\nexport const DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024\n\n/** 默认截图保存目录,项目级 MCP 使用项目内目录方便用户复查截图文件。 */\nexport const DEFAULT_SCREENSHOT_SAVE_DIR = '.vite-mcp/screenshot'\n\n/** 默认性能诊断保存目录,原始 profile 和 heap 文件都应保存在项目内。 */\nexport const DEFAULT_PERFORMANCE_SAVE_DIR = '.vite-mcp/performance'\n\n/** 默认性能报告缓冲上限,避免长时间会话无限累积历史诊断结果。 */\nexport const DEFAULT_PERFORMANCE_MAX_REPORTS = 100\n\n/** 默认性能诊断最大时长,避免一次采集长时间占用浏览器资源。 */\nexport const DEFAULT_PERFORMANCE_MAX_DURATION_MS = 30_000\n\n/** 默认性能诊断采样间隔,兼顾趋势判断和额外采样开销。 */\nexport const DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS = 250\n\n/** 默认长任务阈值,沿用浏览器 Long Task 的常见卡顿判断口径。 */\nexport const DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS = 50\n\n/** MCP 工具名集中管理,避免工具注册和测试中出现拼写漂移。 */\nexport const MCP_TOOL_NAMES = {\n listPages: 'list_pages',\n reloadPage: 'reload_page',\n getDomTree: 'get_dom_tree',\n queryDom: 'query_dom',\n takeScreenshot: 'take_screenshot',\n getConsoleLogs: 'get_console_logs',\n clearConsoleLogs: 'clear_console_logs',\n evaluateScript: 'evaluate_script',\n getNetworkRequests: 'get_network_requests',\n getNetworkRequestDetail: 'get_network_request_detail',\n clearNetworkRequests: 'clear_network_requests',\n listStorage: 'list_storage',\n getStorageItem: 'get_storage_item',\n setStorageItem: 'set_storage_item',\n deleteStorageItem: 'delete_storage_item',\n clearStorage: 'clear_storage',\n recordPerformance: 'record_performance',\n startPerformanceRecording: 'start_performance_recording',\n stopPerformanceRecording: 'stop_performance_recording',\n getPerformanceReport: 'get_performance_report',\n takeHeapSnapshot: 'take_heap_snapshot',\n getComponentTree: 'get_component_tree',\n getComponentState: 'get_component_state',\n editComponentState: 'edit_component_state',\n highlightComponent: 'highlight_component',\n getRouterInfo: 'get_router_info',\n getPiniaTree: 'get_pinia_tree',\n getPiniaState: 'get_pinia_state',\n getElementContext: 'get_element_context'\n} as const\n\n/** 虚拟模块 ID 集中管理,便于注入逻辑和测试复用。 */\nexport const VIRTUAL_RUNTIME_ID = 'virtual:vite-plugin-vue-mcp-next/runtime'\n\n/** Vite 内部解析虚拟模块时需要使用的空字节前缀。 */\nexport const RESOLVED_VIRTUAL_RUNTIME_ID = `\\0${VIRTUAL_RUNTIME_ID}`\n\n/** snapdom 扩展虚拟模块 ID,用静态 import 支持 Vite alias 和源码转换。 */\nexport const VIRTUAL_SCREENSHOT_CONFIG_ID =\n 'virtual:vite-plugin-vue-mcp-next/screenshot-config'\n\n/** Vite 内部解析截图配置虚拟模块时使用空字节前缀,避免与真实文件冲突。 */\nexport const RESOLVED_VIRTUAL_SCREENSHOT_CONFIG_ID = `\\0${VIRTUAL_SCREENSHOT_CONFIG_ID}`\n\n/** snapdom loader 虚拟模块 ID,用于把 optional peer 解析限制在宿主 Vite 模块图里。 */\nexport const VIRTUAL_SNAPDOM_LOADER_ID =\n 'virtual:vite-plugin-vue-mcp-next/snapdom-loader'\n\n/** Vite 内部解析 snapdom loader 时使用空字节前缀,避免与真实文件冲突。 */\nexport const RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID = `\\0${VIRTUAL_SNAPDOM_LOADER_ID}`\n\n/** 默认 MCP 客户端服务名,采用 Vite 维度命名以匹配插件能力边界。 */\nexport const DEFAULT_MCP_CLIENT_SERVER_NAME = 'vite-mcp-next'\n\n/** 旧默认服务名只用于迁移已有配置,避免用户项目里同时出现新旧两份 MCP 配置。 */\nexport const LEGACY_MCP_CLIENT_SERVER_NAMES = ['vue-mcp-next'] as const\n\n/** Runtime 页面重连事件名,供 reload_page 等待页面刷新后重新接入。 */\nexport const RUNTIME_PAGE_RECONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-reconnected'\n\n/** Runtime 页面连接事件名,供 runtime client 启动时上报页面进入。 */\nexport const RUNTIME_PAGE_CONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-connected'\n\n/** Runtime 页面断开事件名,供页面卸载时主动通知服务端清理目标。 */\nexport const RUNTIME_PAGE_DISCONNECTED_EVENT =\n 'vite-plugin-vue-mcp-next:page-disconnected'\n\n/** Runtime 页面心跳事件名,供服务端兜底判断页面是否失活。 */\nexport const RUNTIME_PAGE_HEARTBEAT_EVENT =\n 'vite-plugin-vue-mcp-next:heartbeat'\n\n/** Runtime 页面心跳间隔,保持较低流量并覆盖正常关闭场景。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_INTERVAL_MS = 15_000\n\n/** Runtime 页面失活阈值,留出心跳抖动和短暂阻塞的缓冲。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS = 45_000\n\n/** Runtime 页面兜底扫描间隔,和失活阈值保持一致以减少无意义轮询。 */\nexport const DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS = 45_000\n\n/** 元素选择器轻提示默认时长,足够用户看清复制结果且不长期遮挡页面。 */\nexport const DEFAULT_ELEMENT_PICKER_TOAST_DURATION_MS = 2_200\n\n/** 安全默认值,优先保证调试工具不会默认暴露危险能力。 */\nexport const DEFAULT_OPTIONS: ResolvedVueMcpNextOptions = {\n mcpPath: DEFAULT_MCP_PATH,\n host: 'localhost',\n printUrl: true,\n updateCursorMcpJson: {\n enabled: true,\n serverName: DEFAULT_MCP_CLIENT_SERVER_NAME\n },\n mcpClients: {\n cursor: true,\n codex: true,\n claudeCode: true,\n trae: true,\n serverName: DEFAULT_MCP_CLIENT_SERVER_NAME\n },\n skill: {\n autoConfig: true\n },\n elementPicker: {\n enabled: true,\n shortcut: {\n altKey: true,\n shiftKey: true,\n metaKey: false,\n ctrlKey: false\n },\n toastDurationMs: DEFAULT_ELEMENT_PICKER_TOAST_DURATION_MS\n },\n runtime: {\n mode: 'auto',\n evaluate: {\n enabled: false,\n timeoutMs: 3000\n }\n },\n cdp: {},\n network: {\n mode: 'auto',\n maxRecords: DEFAULT_NETWORK_MAX_RECORDS,\n captureRequestBody: true,\n captureResponseBody: true,\n maxBodySize: DEFAULT_NETWORK_MAX_BODY_SIZE,\n maskHeaders: [...DEFAULT_MASK_HEADERS]\n },\n dom: {\n maxDepth: DEFAULT_DOM_MAX_DEPTH,\n maxNodes: DEFAULT_DOM_MAX_NODES,\n maxTextLength: DEFAULT_DOM_MAX_TEXT_LENGTH\n },\n console: {\n maxRecords: DEFAULT_CONSOLE_MAX_RECORDS\n },\n screenshot: {\n type: 'path',\n saveDir: DEFAULT_SCREENSHOT_SAVE_DIR,\n prefer: 'auto',\n maxBytes: DEFAULT_SCREENSHOT_MAX_BYTES,\n snapdom: {\n options: {},\n plugins: []\n }\n },\n performance: {\n mode: 'auto',\n maxDurationMs: DEFAULT_PERFORMANCE_MAX_DURATION_MS,\n sampleIntervalMs: DEFAULT_PERFORMANCE_SAMPLE_INTERVAL_MS,\n longTaskThresholdMs: DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS,\n saveDir: DEFAULT_PERFORMANCE_SAVE_DIR,\n memory: {\n enabled: true\n },\n stacks: {\n enabled: true\n }\n }\n}\n\n/**\n * 兼容旧 Cursor 配置并合并新多客户端配置。\n *\n * `updateCursorMcpJson` 已经公开给用户,不能直接删除;这里让旧配置继续影响 Cursor,\n * 同时允许 `mcpClients` 作为新入口覆盖默认行为。\n */\nfunction mergeMcpClientOptions(\n cursorConfig: ResolvedVueMcpNextOptions['updateCursorMcpJson'],\n mcpClients?: McpClientConfigOptions\n): Required<McpClientConfigOptions> {\n return {\n ...DEFAULT_OPTIONS.mcpClients,\n cursor: cursorConfig.enabled,\n serverName: cursorConfig.serverName,\n ...mcpClients\n }\n}\n\n/**\n * 合并用户配置和安全默认值。\n *\n * 嵌套配置不能使用浅合并,否则用户只配置一个字段时会丢掉默认安全边界。\n */\nexport function mergeOptions(\n options: VueMcpNextOptions = {}\n): ResolvedVueMcpNextOptions {\n const cursorConfig =\n typeof options.updateCursorMcpJson === 'boolean'\n ? {\n enabled: options.updateCursorMcpJson,\n serverName: DEFAULT_OPTIONS.updateCursorMcpJson.serverName\n }\n : {\n ...DEFAULT_OPTIONS.updateCursorMcpJson,\n ...options.updateCursorMcpJson\n }\n const mcpClients = mergeMcpClientOptions(cursorConfig, options.mcpClients)\n\n return {\n ...DEFAULT_OPTIONS,\n ...options,\n updateCursorMcpJson: cursorConfig,\n mcpClients,\n skill: {\n ...DEFAULT_OPTIONS.skill,\n ...options.skill\n },\n elementPicker: {\n ...DEFAULT_OPTIONS.elementPicker,\n ...options.elementPicker,\n shortcut: {\n ...DEFAULT_OPTIONS.elementPicker.shortcut,\n ...options.elementPicker?.shortcut\n }\n },\n runtime: {\n ...DEFAULT_OPTIONS.runtime,\n ...options.runtime,\n evaluate: {\n ...DEFAULT_OPTIONS.runtime.evaluate,\n ...options.runtime?.evaluate\n }\n },\n cdp: {\n ...DEFAULT_OPTIONS.cdp,\n ...options.cdp\n },\n network: {\n ...DEFAULT_OPTIONS.network,\n ...options.network,\n maskHeaders: options.network?.maskHeaders ?? [\n ...DEFAULT_OPTIONS.network.maskHeaders\n ]\n },\n dom: {\n ...DEFAULT_OPTIONS.dom,\n ...options.dom\n },\n console: {\n ...DEFAULT_OPTIONS.console,\n ...options.console\n },\n screenshot: {\n ...DEFAULT_OPTIONS.screenshot,\n ...options.screenshot,\n snapdom: {\n ...DEFAULT_OPTIONS.screenshot.snapdom,\n ...options.screenshot?.snapdom,\n options: {\n ...DEFAULT_OPTIONS.screenshot.snapdom.options,\n ...options.screenshot?.snapdom?.options\n },\n plugins: options.screenshot?.snapdom?.plugins ?? [\n ...DEFAULT_OPTIONS.screenshot.snapdom.plugins\n ]\n }\n },\n performance: {\n ...DEFAULT_OPTIONS.performance,\n ...options.performance,\n memory: {\n ...DEFAULT_OPTIONS.performance.memory,\n ...options.performance?.memory\n },\n stacks: {\n ...DEFAULT_OPTIONS.performance.stacks,\n ...options.performance?.stacks\n }\n }\n }\n}\n","import { nanoid } from 'nanoid'\nimport { safeStringify } from '../shared/serialization'\nimport type { ConsoleRecord } from '../types'\n\n/**\n * Console Hook 安装参数。\n *\n * Hook 运行在浏览器页面内,需要通过 send 回调交给 Vite WebSocket,而不是直接依赖服务器模块。\n */\nexport interface ConsoleHookOptions {\n /** 当前页面 ID,用于服务端区分多页面日志来源。 */\n readonly pageId: string\n /** 发送规范化日志记录的回调,由 runtime client 绑定到 Vite WebSocket。 */\n readonly send: (record: ConsoleRecord) => void\n}\n\n/**\n * 安装页面 Console 和错误 Hook。\n *\n * 即使启用 CDP,也保留该 Hook,因为早期日志可能发生在 CDP target 匹配完成之前。\n */\nexport function installConsoleHook(options: ConsoleHookOptions): () => void {\n const originalConsole = {\n log: console.log,\n info: console.info,\n warn: console.warn,\n error: console.error,\n debug: console.debug\n }\n\n const emit = (level: ConsoleRecord['level'], args: unknown[]): void => {\n const serializedArgs = serializeConsoleArgs(args)\n\n options.send({\n id: nanoid(),\n pageId: options.pageId,\n source: 'hook',\n level,\n message: serializedArgs.join(' '),\n args: serializedArgs,\n timestamp: Date.now()\n })\n }\n\n ;(['log', 'info', 'warn', 'error', 'debug'] as const).forEach((level) => {\n console[level] = (...args: unknown[]) => {\n emit(level, args)\n originalConsole[level](...args)\n }\n })\n\n const onError = (event: ErrorEvent): void => {\n options.send({\n id: nanoid(),\n pageId: options.pageId,\n source: 'hook',\n level: 'error',\n message: event.message,\n stack: event.error instanceof Error ? event.error.stack : undefined,\n timestamp: Date.now()\n })\n }\n\n window.addEventListener('error', onError)\n\n return () => {\n Object.assign(console, originalConsole)\n window.removeEventListener('error', onError)\n }\n}\n\n/**\n * 将 Console 参数转换成 HMR 可传输的安全快照。\n *\n * Vue 组件、VNode 和 Proxy 对象经常带有循环引用,保留原始引用会让 Vite WebSocket\n * 在序列化 payload 时失败;这里在浏览器侧提前裁剪,保证日志采集不会反过来打断页面热更新。\n */\nfunction serializeConsoleArgs(args: unknown[]): string[] {\n return args.map((arg) => safeStringify(arg))\n}\n","/**\n * 将未知值转换为适合 MCP 文本输出的字符串。\n *\n * Console 参数、脚本执行结果和 Network body 都可能包含循环引用,统一序列化能避免工具调用崩溃。\n */\nexport function safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value\n }\n\n const seen = new WeakSet()\n\n const serialized = JSON.stringify(\n value,\n (_key: string, current: unknown): unknown => {\n if (typeof current !== 'object' || current === null) {\n return current\n }\n\n if (seen.has(current)) {\n return '[Circular]'\n }\n\n seen.add(current)\n return current\n }\n )\n\n return serialized\n}\n","/**\n * 页面级元素 registry。\n *\n * 该 registry 只保存当前页面生命周期内的 DOM 引用,用于 runtime fallback ID;\n * 它不跨刷新、不持久化,避免 AI 使用已经失效的 DOM 节点继续修改页面。\n */\n\nimport { nanoid } from 'nanoid'\n\nconst RUNTIME_ELEMENT_ID_PREFIX = 'runtime:vmcp_'\nconst RUNTIME_ELEMENT_ID_SIZE = 8\n\n/**\n * runtime 元素记录。\n *\n * `createdAt` 用于后续排查生命周期问题,不表示该 ID 可跨刷新复用。\n */\nexport interface RuntimeElementRecord {\n readonly elementId: string\n readonly element: Element\n readonly createdAt: number\n}\n\n/**\n * runtime 元素 registry。\n *\n * register 会为无源码 ID 的元素创建短 ID;clear 在页面生命周期结束或测试中释放引用。\n */\nexport interface RuntimeElementRegistry {\n register(element: Element): string\n get(elementId: string): RuntimeElementRecord | undefined\n clear(): void\n}\n\n/**\n * 浏览器页面默认 registry。\n *\n * picker 和 runtime context resolver 必须共享同一个 registry,动态 DOM 的 runtime ID 才能被 MCP 查询回来。\n */\nexport const runtimeElementRegistry = createRuntimeElementRegistry()\n\n/**\n * 创建运行时短 ID。\n *\n * 运行时 ID 只在当前页面生命周期内有效,前缀必须清楚表达它不能跨刷新复用。\n */\nexport function createRuntimeElementId(): string {\n return `${RUNTIME_ELEMENT_ID_PREFIX}${nanoid(RUNTIME_ELEMENT_ID_SIZE)}`\n}\n\n/**\n * 创建页面级元素 registry。\n *\n * registry 不持久化到服务端,避免页面刷新后 AI 误用旧 DOM 节点。\n */\nexport function createRuntimeElementRegistry(): RuntimeElementRegistry {\n const records = new Map<string, RuntimeElementRecord>()\n\n return {\n register(element) {\n const elementId = createRuntimeElementId()\n records.set(elementId, {\n elementId,\n element,\n createdAt: Date.now()\n })\n return elementId\n },\n get(elementId) {\n return records.get(elementId)\n },\n clear() {\n records.clear()\n }\n }\n}\n","/**\n * 页面元素选择器。\n *\n * 该模块负责本地开发态的按键选择、hover 高亮、点击复制和轻提示;\n * 它不直接调用 MCP,确保用户确认后再把 elementId 发送给 AI。\n */\n\nimport type { ElementPickerShortcut } from '../types'\nimport { runtimeElementRegistry } from './elementRegistry'\nimport type { RuntimeElementRegistry } from './elementRegistry'\n\nconst MCP_ID_ATTR = 'data-v-mcp-id'\nconst INTERNAL_ATTR = 'data-v-mcp-internal'\nconst SUCCESS_MESSAGE = '元素位置已复制,请发送给 AI'\nconst COPY_FAILED_PREFIX = '复制失败,请手动复制元素 ID'\nconst OVERLAY_Z_INDEX = '2147483647'\nconst TOAST_Z_INDEX = '2147483647'\n\n/**\n * 安装页面元素选择器。\n *\n * 选择器只在本地开发态响应快捷键,默认不改变页面交互;\n * 进入选择态后才拦截 hover 和 click,避免影响业务页面日常使用。\n */\nexport function installElementPicker(options: {\n readonly enabled: boolean\n readonly shortcut: Required<ElementPickerShortcut>\n readonly toastDurationMs: number\n}): void {\n if (!options.enabled) {\n return\n }\n\n const registry = runtimeElementRegistry\n const overlay = createOverlay()\n let active = false\n let currentElement: Element | undefined\n\n window.addEventListener('keydown', (event) => {\n active = matchesShortcut(event, options.shortcut)\n })\n window.addEventListener('keyup', () => {\n active = false\n currentElement = undefined\n updateOverlay(overlay)\n })\n window.addEventListener('mousemove', (event) => {\n if (!active) {\n return\n }\n\n currentElement = document.elementFromPoint(event.clientX, event.clientY)\n ?? undefined\n updateOverlay(overlay, currentElement)\n })\n window.addEventListener(\n 'click',\n (event) => {\n if (!active || !isElementLike(event.target)) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n\n void copyAndNotify(event.target, registry, options.toastDurationMs)\n },\n true\n )\n}\n\n/**\n * 判断当前按键事件是否进入选择模式。\n *\n * 使用布尔等值比较而不是只判断 truthy,避免用户按下额外修饰键时误触。\n */\nfunction matchesShortcut(\n event: Pick<KeyboardEvent, 'altKey' | 'shiftKey' | 'metaKey' | 'ctrlKey'>,\n shortcut: Required<ElementPickerShortcut>\n): boolean {\n return (\n event.altKey === shortcut.altKey &&\n event.shiftKey === shortcut.shiftKey &&\n event.metaKey === shortcut.metaKey &&\n event.ctrlKey === shortcut.ctrlKey\n )\n}\n\n/**\n * 解析元素 ID。\n *\n * 编译期 ID 优先,因为它能直接定位源码;无 ID 的动态 DOM 才登记为 runtime fallback。\n */\nfunction resolveElementId(\n element: Element,\n registry: RuntimeElementRegistry\n): string {\n return element.getAttribute(MCP_ID_ATTR) ?? registry.register(element)\n}\n\n/**\n * 复制并提示元素 ID。\n *\n * click 监听器需要保持同步返回,异步复制流程单独封装以满足浏览器事件和 lint 约束。\n */\nasync function copyAndNotify(\n element: Element,\n registry: RuntimeElementRegistry,\n toastDurationMs: number\n): Promise<void> {\n const elementId = resolveElementId(element, registry)\n const copied = await copyElementId(elementId)\n\n showToast(\n copied ? SUCCESS_MESSAGE : `${COPY_FAILED_PREFIX}: ${elementId}`,\n toastDurationMs\n )\n}\n\n/**\n * 复制元素 ID。\n *\n * Clipboard API 可能被浏览器权限或非安全上下文拒绝,失败时由轻提示暴露手动复制值。\n */\nasync function copyElementId(elementId: string): Promise<boolean> {\n try {\n await navigator.clipboard.writeText(elementId)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * 创建 hover 高亮层。\n *\n * 高亮层标记为内部元素,后续 DOM snapshot 会跳过它,避免 AI 误改调试 UI。\n */\nfunction createOverlay(): HTMLElement {\n const overlay = document.createElement('div')\n markInternalElement(overlay)\n Object.assign(overlay.style, {\n position: 'fixed',\n pointerEvents: 'none',\n border: '2px solid #1d4ed8',\n background: 'rgba(29, 78, 216, 0.08)',\n zIndex: OVERLAY_Z_INDEX,\n display: 'none'\n })\n document.body.appendChild(overlay)\n return overlay\n}\n\n/**\n * 更新 hover 高亮层。\n *\n * 没有目标元素时隐藏 overlay;只读取布局矩形,不修改业务元素样式。\n */\nfunction updateOverlay(overlay: HTMLElement, element?: Element): void {\n if (!element || getElementAttr(element, INTERNAL_ATTR) === 'true') {\n overlay.style.display = 'none'\n return\n }\n\n const rect = element.getBoundingClientRect()\n Object.assign(overlay.style, {\n display: 'block',\n left: `${String(rect.x)}px`,\n top: `${String(rect.y)}px`,\n width: `${String(rect.width)}px`,\n height: `${String(rect.height)}px`\n })\n}\n\n/**\n * 展示复制结果轻提示。\n *\n * 提示元素同样标记为内部元素,避免 DOM 查询和截图上下文把它当业务内容。\n */\nfunction showToast(message: string, durationMs: number): void {\n const toast = document.createElement('div')\n markInternalElement(toast)\n toast.textContent = message\n Object.assign(toast.style, {\n position: 'fixed',\n left: '50%',\n bottom: '32px',\n transform: 'translateX(-50%)',\n zIndex: TOAST_Z_INDEX,\n padding: '8px 12px',\n borderRadius: '6px',\n background: 'rgba(17, 24, 39, 0.92)',\n color: '#fff',\n fontSize: '13px',\n pointerEvents: 'none'\n })\n document.body.appendChild(toast)\n globalThis.setTimeout(() => {\n toast.remove()\n }, durationMs)\n}\n\n/**\n * 收窄事件目标。\n *\n * 测试环境可能没有完整 DOM 构造函数,因此这里用能力检测保证 Node/Vitest 可测。\n */\nfunction isElementLike(value: EventTarget | null): value is Element {\n return Boolean(\n value &&\n typeof value === 'object' &&\n 'getAttribute' in value &&\n 'getBoundingClientRect' in value\n )\n}\n\n/**\n * 标记调试 UI 元素。\n *\n * 真实浏览器使用属性,测试假 DOM 可能只有 dataset;两者都写入可以让快照过滤逻辑保持一致。\n */\nfunction markInternalElement(element: HTMLElement): void {\n if (typeof element.setAttribute === 'function') {\n element.setAttribute(INTERNAL_ATTR, 'true')\n }\n\n element.dataset.vMcpInternal = 'true'\n}\n\n/**\n * 读取元素属性。\n *\n * 对测试假 DOM 做保护,避免选择器交互测试必须模拟完整 HTMLElement。\n */\nfunction getElementAttr(element: Element, name: string): string | null {\n if (typeof element.getAttribute === 'function') {\n return element.getAttribute(name)\n }\n\n return null\n}\n","/**\n * 元素 ID 共享解析契约。\n *\n * 该文件只处理字符串格式分类,不访问 DOM、runtime 或文件系统;\n * 这样 MCP 在浏览器页面不在线时,仍能基于用户提供的 ID 返回明确边界。\n */\n\nconst PROJECT_SOURCE_ID_PATTERN = /^(.+\\.(?:vue|tsx|jsx|ts|js)):(\\d+):(\\d+)$/\nconst RUNTIME_ID_PATTERN = /^runtime:([A-Za-z0-9_-]+)$/\nconst PACKAGE_ID_PREFIX = 'pkg:'\n\n/**\n * 元素 ID 解析结果。\n *\n * `project-source` 表示可定位到项目源码;`package` 只表达第三方包入口;\n * `runtime` 依赖当前页面生命周期;`invalid` 用于给 AI 返回可解释错误。\n */\nexport type ParsedElementId =\n | {\n readonly kind: 'project-source'\n readonly elementId: string\n readonly file: string\n readonly line: number\n readonly column: number\n }\n | {\n readonly kind: 'package'\n readonly elementId: string\n readonly packageName: string\n readonly entryFile: string\n }\n | {\n readonly kind: 'runtime'\n readonly elementId: string\n readonly runtimeId: string\n }\n | {\n readonly kind: 'invalid'\n readonly elementId: string\n readonly reason: string\n }\n\n/**\n * 解析用户复制给 AI 的元素标识。\n *\n * 该函数只负责格式分类,不判断文件是否存在,也不推断 DOM 是否仍在页面上;\n * 这些上下文需要由 runtime 或 MCP 上层工具补齐。\n */\nexport function parseElementId(elementId: string): ParsedElementId {\n const sourceMatch = PROJECT_SOURCE_ID_PATTERN.exec(elementId)\n\n if (sourceMatch) {\n return {\n kind: 'project-source',\n elementId,\n file: sourceMatch[1],\n line: Number(sourceMatch[2]),\n column: Number(sourceMatch[3])\n }\n }\n\n if (elementId.startsWith(PACKAGE_ID_PREFIX)) {\n return parsePackageElementId(elementId)\n }\n\n const runtimeMatch = RUNTIME_ID_PATTERN.exec(elementId)\n\n if (runtimeMatch) {\n return {\n kind: 'runtime',\n elementId,\n runtimeId: runtimeMatch[1]\n }\n }\n\n return {\n kind: 'invalid',\n elementId,\n reason: 'unsupported elementId format'\n }\n}\n\n/**\n * 解析第三方包元素标识。\n *\n * scope 包需要把前两段作为包名,避免把 `@scope/ui/Button` 错切成 `@scope`;\n * 包级 ID 不返回 `node_modules` 物理路径,避免引导 AI 修改依赖源码。\n */\nfunction parsePackageElementId(elementId: string): ParsedElementId {\n const value = elementId.slice(PACKAGE_ID_PREFIX.length)\n const parts = value.split('/').filter(Boolean)\n\n if (parts.length < 2) {\n return {\n kind: 'invalid',\n elementId,\n reason: 'package elementId must include packageName and entryFile'\n }\n }\n\n const scoped = parts[0]?.startsWith('@')\n const packageName = scoped ? parts.slice(0, 2).join('/') : parts[0]\n const entryFile = parts.slice(scoped ? 2 : 1).join('/')\n\n if (!entryFile) {\n return {\n kind: 'invalid',\n elementId,\n reason: 'package elementId must include entryFile'\n }\n }\n\n return {\n kind: 'package',\n elementId,\n packageName,\n entryFile\n }\n}\n","/**\n * 文本截断结果。\n *\n * MCP 输出需要明确告诉调用方内容被截断,否则 AI 可能误以为看到的是完整响应。\n */\nexport interface TruncatedText {\n /** 截断后的文本。 */\n readonly text: string\n /** 是否发生截断。 */\n readonly truncated: boolean\n /** 原始文本长度,用于判断丢失信息规模。 */\n readonly originalLength: number\n}\n\n/**\n * 截断长文本。\n *\n * DOM 文本和响应体都可能很大,统一截断策略可以避免不同工具输出行为不一致。\n */\nexport function truncateText(text: string, maxLength: number): TruncatedText {\n if (text.length <= maxLength) {\n return { text, truncated: false, originalLength: text.length }\n }\n\n return {\n text: text.slice(0, maxLength),\n truncated: true,\n originalLength: text.length\n }\n}\n\n/**\n * 对敏感 header 做脱敏。\n *\n * Network 调试需要展示 header,但认证和 Cookie 不应原样暴露给 AI 客户端。\n */\nexport function maskHeaders(\n headers: Record<string, string> = {},\n maskNames: readonly string[] = []\n): Record<string, string> {\n const normalizedMaskNames = new Set(\n maskNames.map((name) => name.toLowerCase())\n )\n\n return Object.fromEntries(\n Object.entries(headers).map(([name, value]) => [\n name,\n normalizedMaskNames.has(name.toLowerCase()) ? '[masked]' : value\n ])\n )\n}\n","import { truncateText } from '../shared/sanitize'\nimport type { DomOptions } from '../types'\n\n/**\n * DOM 节点快照。\n *\n * MCP 不应该返回真实 DOM 节点对象,而应该返回可序列化结构,便于 AI 理解和传输。\n */\nexport interface DomNodeSnapshot {\n /** 节点标签名,文本节点使用 `#text`。 */\n readonly tag: string\n /** 节点属性,敏感字段会被脱敏。 */\n readonly attrs?: Record<string, string>\n /** 节点文本,按配置截断。 */\n readonly text?: string\n /** 子节点,受最大深度和最大节点数限制。 */\n readonly children?: DomNodeSnapshot[]\n}\n\n/**\n * selector 查询结果。\n *\n * 查询工具只返回定位所需的摘要信息,避免把完整节点对象暴露给 MCP 客户端。\n */\nexport interface DomElementQueryResult {\n /** 元素标签名,用于快速判断命中的节点类型。 */\n readonly tag: string\n /** 元素聚合文本,用于 AI 判断该节点是否是目标控件。 */\n readonly text: string\n /** 元素属性快照,敏感字段会被脱敏。 */\n readonly attrs: Record<string, string>\n /** 元素布局矩形,便于后续判断可见区域和点击位置。 */\n readonly rect: Record<string, number>\n}\n\n/**\n * 单个 DOM 元素摘要。\n *\n * 元素上下文工具只需要目标元素本身的可读信息,不应返回整棵 DOM。\n */\nexport type DomElementSummary = DomElementQueryResult\n\n/**\n * 创建裁剪后的 DOM 快照。\n *\n * DOM 输出必须裁剪,因为 MCP 上下文有限,大页面直接返回会导致 AI 无法消费。\n */\nexport function createDomSnapshot(\n root: Element,\n options: Required<DomOptions>\n): DomNodeSnapshot {\n let count = 0\n\n /**\n * 递归访问 DOM 节点。\n *\n * 将递归放在闭包内可以共享节点计数,确保 maxNodes 是整棵树的全局限制。\n */\n function visit(node: Node, depth: number): DomNodeSnapshot | null {\n if (count >= options.maxNodes || depth > options.maxDepth) {\n return null\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n return createTextSnapshot(node, options, () => {\n count += 1\n })\n }\n\n if (!(node instanceof Element)) {\n return null\n }\n\n const tag = node.tagName.toLowerCase()\n\n if (['script', 'style', 'noscript'].includes(tag) || isInternalMcpElement(node)) {\n return null\n }\n\n count += 1\n\n return createElementSnapshot(node, tag, (child) => visit(child, depth + 1))\n }\n\n return visit(root, 0) ?? { tag: root.tagName.toLowerCase() }\n}\n\n/**\n * 查询 DOM 元素摘要。\n *\n * selector 查询用于让 AI 快速定位关键元素,不需要返回整棵 DOM。\n */\nexport function queryDomElements(\n selector: string,\n limit: number\n): DomElementQueryResult[] {\n return Array.from(document.querySelectorAll(selector))\n .filter((element) => !isInternalMcpElement(element))\n .slice(0, limit)\n .map((element) => createDomElementSummary(element))\n}\n\n/**\n * 创建单个 DOM 元素摘要。\n *\n * 该结构用于 `get_element_context` 返回目标元素上下文,避免 AI 只拿到源码位置却看不到页面语义。\n */\nexport function createDomElementSummary(element: Element): DomElementSummary {\n return {\n tag: element.tagName.toLowerCase(),\n text: element.textContent.trim(),\n attrs: collectAttrs(element),\n rect: serializeRect(element.getBoundingClientRect())\n }\n}\n\n/**\n * 创建文本节点快照。\n *\n * 空白文本在调试时通常是布局噪声,过滤它们可以让 AI 更专注于真实内容。\n */\nfunction createTextSnapshot(\n node: Node,\n options: Required<DomOptions>,\n markVisited: () => void\n): DomNodeSnapshot | null {\n const text = node.textContent?.trim()\n\n if (!text) {\n return null\n }\n\n markVisited()\n\n return { tag: '#text', text: truncateText(text, options.maxTextLength).text }\n}\n\n/**\n * 创建元素节点快照。\n *\n * 属性和子节点拆开处理,是为了后续可以单独扩展属性脱敏或节点过滤策略。\n */\nfunction createElementSnapshot(\n node: Element,\n tag: string,\n visitChild: (child: Node) => DomNodeSnapshot | null\n): DomNodeSnapshot {\n const attrs = collectAttrs(node)\n const children = Array.from(node.childNodes)\n .map((child) => visitChild(child))\n .filter((child): child is DomNodeSnapshot => Boolean(child))\n\n return {\n tag,\n ...(node.textContent.trim() ? { text: node.textContent.trim() } : {}),\n ...(Object.keys(attrs).length ? { attrs } : {}),\n ...(children.length ? { children } : {})\n }\n}\n\n/**\n * 收集元素属性并隐藏敏感值。\n *\n * 密码输入框的 value 不能泄露给 MCP 客户端,即使它只在本地开发环境使用。\n */\nexport function collectAttrs(element: Element): Record<string, string> {\n const attrs: Record<string, string> = {}\n\n for (const attr of Array.from(element.attributes)) {\n attrs[attr.name] = attr.value\n }\n\n if (\n typeof HTMLInputElement !== 'undefined' &&\n element instanceof HTMLInputElement &&\n element.type === 'password'\n ) {\n attrs.value = '[masked]'\n }\n\n return attrs\n}\n\n/**\n * 序列化 DOMRect。\n *\n * 浏览器返回的 DOMRect 不是普通 JSON 对象,显式挑选字段可以让 MCP 输出稳定且可测试。\n */\nexport function serializeRect(rect: DOMRect): Record<string, number> {\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left\n }\n}\n\n/**\n * 识别 MCP 内部调试元素。\n *\n * overlay/toast 是插件自身 UI,返回给 AI 会污染业务 DOM 判断,因此所有 DOM 输出统一过滤。\n */\nfunction isInternalMcpElement(element: Element): boolean {\n return element.getAttribute('data-v-mcp-internal') === 'true'\n}\n","/**\n * Vue DOM 到组件归属定位。\n *\n * Vue 没有公开稳定的 DOM 到组件实例 API;这里仅在开发态读取受保护的 runtime 元数据,\n * 任意字段缺失都返回空结果,避免影响 DOM 上下文查询主链路。\n */\n\n/**\n * 定位到的 Vue 组件归属。\n *\n * 项目源码组件返回 `source`,第三方组件只返回包名和入口文件,避免引导 AI 修改 `node_modules`。\n */\nexport interface LocatedVueComponent {\n readonly name?: string\n readonly source?: {\n readonly file: string\n }\n readonly packageLocation?: {\n readonly packageName: string\n readonly entryFile: string\n }\n}\n\ninterface VueRuntimeComponent {\n readonly type?: {\n readonly name?: string\n readonly __name?: string\n readonly displayName?: string\n readonly __file?: string\n }\n}\n\n/**\n * 从 DOM 元素向上查找 Vue 组件归属。\n *\n * 查询失败不是错误,因为普通 DOM、Teleport 或第三方渲染节点都可能没有 Vue 私有字段。\n */\nexport function locateVueComponentForElement(\n element: Element,\n root: string\n): LocatedVueComponent | undefined {\n const component = findNearestComponent(element)\n\n if (!component) {\n return undefined\n }\n\n const file = getComponentFile(component)\n const name = getComponentName(component)\n\n if (!file) {\n return { name }\n }\n\n const packageLocation = parseNodeModulesFile(file)\n\n if (packageLocation) {\n return {\n name,\n source: undefined,\n packageLocation\n }\n }\n\n return {\n name,\n source: {\n file: createProjectRelativePath(root, file)\n },\n packageLocation: undefined\n }\n}\n\n/**\n * 沿父元素查找最近的 Vue 私有组件引用。\n *\n * Vue 组件根节点和内部子节点都有可能挂载该字段,向上查找可以提高命中率。\n */\nfunction findNearestComponent(element: Element): VueRuntimeComponent | undefined {\n let current: Element | null = element\n\n while (current) {\n const component = (current as { __vueParentComponent?: unknown })\n .__vueParentComponent\n\n if (isVueRuntimeComponent(component)) {\n return component\n }\n\n current = current.parentElement\n }\n\n return undefined\n}\n\n/**\n * 获取组件展示名。\n *\n * 不同构建链路会写入不同字段,因此按稳定性和可读性依次尝试。\n */\nfunction getComponentName(component: VueRuntimeComponent): string | undefined {\n return (\n component.type?.name ??\n component.type?.__name ??\n component.type?.displayName\n )\n}\n\n/**\n * 获取组件源文件。\n *\n * `__file` 仅在开发态可用,缺失时不能阻断上下文返回。\n */\nfunction getComponentFile(component: VueRuntimeComponent): string | undefined {\n return component.type?.__file\n}\n\n/**\n * 解析 node_modules 中的组件文件。\n *\n * scope 包需要保留两段包名,剩余路径作为入口文件返回。\n */\nfunction parseNodeModulesFile(\n file: string\n): LocatedVueComponent['packageLocation'] | undefined {\n const normalized = normalizePath(file)\n const marker = '/node_modules/'\n const index = normalized.lastIndexOf(marker)\n\n if (index < 0) {\n return undefined\n }\n\n const parts = normalized.slice(index + marker.length).split('/').filter(Boolean)\n const scoped = parts[0]?.startsWith('@')\n const packageName = scoped ? parts.slice(0, 2).join('/') : parts[0]\n const entryFile = parts.slice(scoped ? 2 : 1).join('/')\n\n if (!packageName || !entryFile) {\n return undefined\n }\n\n return {\n packageName,\n entryFile\n }\n}\n\n/**\n * 统一路径分隔符。\n *\n * 返回给 AI 的路径需要跨平台稳定,避免 Windows 反斜杠影响 elementId 解析。\n */\nfunction normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\n/**\n * 生成项目相对路径。\n *\n * 该文件会进入浏览器 runtime bundle,不能依赖 `node:path`;\n * 这里只处理绝对路径前缀裁剪,无法归属到项目 root 时保留去掉首斜杠的可读路径。\n */\nfunction createProjectRelativePath(root: string, file: string): string {\n const normalizedRoot = normalizePath(root).replace(/\\/$/, '')\n const normalizedFile = normalizePath(file)\n const prefix = `${normalizedRoot}/`\n\n if (normalizedFile.startsWith(prefix)) {\n return normalizedFile.slice(prefix.length)\n }\n\n return normalizedFile.replace(/^\\//, '')\n}\n\n/**\n * 收窄 Vue 私有组件对象。\n *\n * 只验证本模块真正读取的字段,减少对 Vue runtime 内部结构的绑定。\n */\nfunction isVueRuntimeComponent(value: unknown): value is VueRuntimeComponent {\n return Boolean(value && typeof value === 'object' && 'type' in value)\n}\n","/**\n * runtime 元素上下文解析。\n *\n * 该模块把 elementId 转换成 AI 可消费的源码、组件和 DOM 摘要;\n * 它优先返回项目源码位置,第三方包和 runtime 兜底都显式给出不可编辑边界。\n */\n\nimport { parseElementId } from '../shared/elementId'\nimport type { ParsedElementId } from '../shared/elementId'\nimport type { ElementContextResult } from '../types'\nimport { createDomElementSummary } from './domSnapshot'\nimport { runtimeElementRegistry } from './elementRegistry'\nimport type { RuntimeElementRegistry } from './elementRegistry'\nimport { locateVueComponentForElement } from './vueComponentLocator'\n\n/**\n * 元素上下文解析器配置。\n *\n * querySelector 由调用方注入,便于测试和 runtime RPC 共享同一套解析逻辑。\n */\nexport interface ElementContextResolverOptions {\n readonly root: string\n readonly registry: RuntimeElementRegistry\n readonly querySelector: (selector: string) => Element | null\n}\n\ntype ElementContextResolver = ReturnType<typeof createElementContextResolver>\n\nlet activeResolver: ElementContextResolver | undefined\n\n/**\n * 创建 runtime 元素上下文解析器。\n *\n * 解析器优先返回可修改源码位置;只有拿不到项目源码时,才降级为第三方包或 runtime 限制说明。\n */\nexport function createElementContextResolver(\n options: ElementContextResolverOptions\n) {\n return {\n getElementContext(elementId: string): ElementContextResult {\n const parsed = parseElementId(elementId)\n\n if (parsed.kind === 'project-source') {\n const element = options.querySelector(\n `[data-v-mcp-id=\"${escapeSelector(elementId)}\"]`\n )\n\n return createProjectSourceContext(parsed, element, options.root)\n }\n\n if (parsed.kind === 'package') {\n return createPackageContext(parsed)\n }\n\n if (parsed.kind === 'runtime') {\n const record = options.registry.get(elementId)\n\n if (!record) {\n return createMissingRuntimeElementError(elementId)\n }\n\n return createRuntimeContext(elementId, record.element, options.root)\n }\n\n return {\n ok: false,\n error: parsed.reason,\n elementId,\n limitations: ['please provide a copied elementId from the element picker']\n }\n }\n }\n}\n\n/**\n * 设置当前页面使用的元素上下文解析器。\n *\n * runtime 启动后可注入共享 registry;测试也可以通过该入口隔离 DOM 查询来源。\n */\nexport function setElementContextResolver(\n resolver: ElementContextResolver\n): void {\n activeResolver = resolver\n}\n\n/**\n * 获取当前页面元素上下文解析器。\n *\n * 未显式设置时创建浏览器默认解析器,保证 runtime RPC 在普通页面中可直接工作。\n */\nexport function getElementContextResolver(): ElementContextResolver {\n activeResolver ??= createElementContextResolver({\n root: '/',\n registry: runtimeElementRegistry,\n querySelector(selector) {\n return document.querySelector(selector)\n }\n })\n\n return activeResolver\n}\n\n/**\n * 创建项目源码上下文。\n *\n * 即使当前 DOM 查不到,编译期 ID 仍然可编辑;DOM 和组件信息只是增强上下文。\n */\nfunction createProjectSourceContext(\n parsed: Extract<ParsedElementId, { kind: 'project-source' }>,\n element: Element | null,\n root: string\n): ElementContextResult {\n return {\n ok: true,\n elementId: parsed.elementId,\n editable: true,\n codeLocation: {\n file: parsed.file,\n line: parsed.line,\n column: parsed.column\n },\n ...(element ? { component: locateVueComponentForElement(element, root) } : {}),\n ...(element ? { dom: createDomElementSummary(element) } : {}),\n limitations: element ? [] : ['runtime DOM element was not found']\n }\n}\n\n/**\n * 创建第三方包上下文。\n *\n * 包级结果明确不可编辑,AI 应回到项目源码中调整用法,而不是修改依赖包文件。\n */\nfunction createPackageContext(\n parsed: Extract<ParsedElementId, { kind: 'package' }>\n): ElementContextResult {\n return {\n ok: true,\n elementId: parsed.elementId,\n editable: false,\n packageLocation: {\n packageName: parsed.packageName,\n entryFile: parsed.entryFile\n },\n limitations: ['third-party package source is not editable from this project']\n }\n}\n\n/**\n * 创建 runtime fallback 上下文。\n *\n * 动态 DOM 只有在能反查到项目组件源码时才标记可编辑,否则仅返回 DOM 摘要和限制说明。\n */\nfunction createRuntimeContext(\n elementId: string,\n element: Element,\n root: string\n): ElementContextResult {\n const component = locateVueComponentForElement(element, root)\n const sourceFile = component?.source?.file\n\n return {\n ok: true,\n elementId,\n editable: Boolean(sourceFile),\n ...(sourceFile\n ? { codeLocation: { file: sourceFile, line: 1, column: 1 } }\n : {}),\n component,\n dom: createDomElementSummary(element),\n limitations: sourceFile\n ? ['runtime id maps to nearest component file, exact template node is unavailable']\n : ['runtime id is only valid during the current page lifecycle']\n }\n}\n\n/**\n * 创建 runtime ID 失效错误。\n *\n * 失效通常来自页面刷新或 DOM 被移除,必须提示用户重新选择元素。\n */\nfunction createMissingRuntimeElementError(elementId: string): ElementContextResult {\n return {\n ok: false,\n error: 'element not found',\n elementId,\n limitations: [\n 'element was removed or page refreshed',\n 'please ask the user to pick the element again'\n ]\n }\n}\n\n/**\n * 转义属性选择器值。\n *\n * 浏览器支持 `CSS.escape` 时优先使用;测试或旧环境中使用保守转义,避免 ID 中的引号破坏选择器。\n */\nfunction escapeSelector(value: string): string {\n const css = (globalThis as {\n readonly CSS?: { readonly escape?: (input: string) => string }\n }).CSS\n\n if (css?.escape) {\n return css.escape(value)\n }\n\n return value.replace(/[\"\\\\]/g, '\\\\$&')\n}\n","import { nanoid } from 'nanoid'\nimport { maskHeaders, truncateText } from '../shared/sanitize'\nimport { parseRequestQuery } from '../shared/url'\nimport type { NetworkRecord } from '../types'\n\n/**\n * Hook Network 记录创建参数。\n *\n * 将记录创建抽成纯函数,便于测试脱敏、query 解析和字段标准化。\n */\nexport interface HookNetworkRecordInput {\n /** 当前页面 ID,用于服务端区分多页面请求来源。 */\n readonly pageId: string\n /** 请求 URL,用于记录接口地址和解析 query 参数。 */\n readonly url: string\n /** HTTP 方法,Hook 会从 fetch init 或 XHR open 中提取。 */\n readonly method: string\n /** 请求头快照,采集前会按 maskHeaders 脱敏。 */\n readonly requestHeaders?: Record<string, string>\n /** 请求体快照,用于调试提交参数。 */\n readonly requestBody?: unknown\n /** 需要脱敏的 header 名称。 */\n readonly maskHeaders: readonly string[]\n /** 请求开始时间,用于后续计算耗时。 */\n readonly startedAt: number\n}\n\n/**\n * Network Hook 安装参数。\n *\n * Hook 运行在浏览器页面内,通过 send 回调把记录交给 Vite WebSocket。\n */\nexport interface NetworkHookOptions {\n /** 当前页面 ID,用于服务端区分多页面请求来源。 */\n readonly pageId: string\n /** 请求体和响应体最大采集长度,避免大响应污染 MCP 上下文。 */\n readonly maxBodySize: number\n /** 需要脱敏的 header 名称。 */\n readonly maskHeaders: readonly string[]\n /** 发送规范化网络记录的回调。 */\n readonly send: (record: NetworkRecord) => void\n}\n\n/**\n * 创建 Hook 来源的 Network 记录。\n *\n * Hook 模式只覆盖 fetch/XHR,但它可以零配置提供业务接口的请求参数和响应值。\n */\nexport function createHookNetworkRecord(\n input: HookNetworkRecordInput\n): NetworkRecord {\n return {\n id: nanoid(),\n pageId: input.pageId,\n source: 'hook',\n url: input.url,\n method: input.method,\n requestHeaders: maskHeaders(input.requestHeaders, input.maskHeaders),\n requestQuery: parseRequestQuery(input.url),\n requestBody: input.requestBody,\n startedAt: input.startedAt\n }\n}\n\n/**\n * 安装 fetch 和 XHR 网络 Hook。\n *\n * Hook 不覆盖静态资源和浏览器内部请求,但能在无 CDP 配置时捕获大多数业务接口。\n */\nexport function installNetworkHook(options: NetworkHookOptions): () => void {\n const originalFetch = window.fetch.bind(window)\n const XMLHttpRequestCtor = window.XMLHttpRequest as\n | typeof XMLHttpRequest\n | undefined\n // eslint-disable-next-line @typescript-eslint/unbound-method -- XHR 原型方法必须保留动态 this,后续通过 Reflect.apply 绑定到具体实例。\n const originalOpen = XMLHttpRequestCtor?.prototype.open\n // eslint-disable-next-line @typescript-eslint/unbound-method -- XHR 原型方法必须保留动态 this,后续通过 Reflect.apply 绑定到具体实例。\n const originalSend = XMLHttpRequestCtor?.prototype.send\n\n window.fetch = createFetchHook(originalFetch, options)\n\n if (XMLHttpRequestCtor && originalOpen && originalSend) {\n installXhrHook(XMLHttpRequestCtor, originalOpen, originalSend, options)\n }\n\n return () => {\n window.fetch = originalFetch\n if (XMLHttpRequestCtor && originalOpen && originalSend) {\n XMLHttpRequestCtor.prototype.open = originalOpen\n XMLHttpRequestCtor.prototype.send = originalSend\n }\n }\n}\n\n/**\n * 创建 fetch 包装函数。\n *\n * 使用 response.clone() 读取响应体,避免调试采集破坏业务代码对 response 的消费。\n */\nfunction createFetchHook(\n originalFetch: typeof window.fetch,\n options: NetworkHookOptions\n): typeof window.fetch {\n return async (input, init) => {\n const startedAt = Date.now()\n const record = createHookNetworkRecord({\n pageId: options.pageId,\n url: getFetchUrl(input),\n method: getFetchMethod(input, init),\n requestHeaders: headersToRecord(\n init?.headers ?? (input instanceof Request ? input.headers : undefined)\n ),\n requestBody: init?.body,\n maskHeaders: options.maskHeaders,\n startedAt\n })\n\n try {\n const response = await originalFetch(input, init)\n const endedAt = Date.now()\n options.send({\n ...record,\n status: response.status,\n responseHeaders: headersToRecord(response.headers),\n responseBody: await readResponseBody(response, options.maxBodySize),\n endedAt,\n durationMs: endedAt - startedAt\n })\n return response\n } catch (error) {\n const endedAt = Date.now()\n options.send({\n ...record,\n error: error instanceof Error ? error.message : String(error),\n endedAt,\n durationMs: endedAt - startedAt\n })\n throw error\n }\n }\n}\n\n/**\n * 安装 XHR 包装。\n *\n * XHR 没有 fetch 那样的 clone 能力,因此只读取 responseText,并在失败时静默降级。\n */\nfunction installXhrHook(\n XMLHttpRequestCtor: typeof XMLHttpRequest,\n originalOpen: typeof XMLHttpRequest.prototype.open,\n originalSend: typeof XMLHttpRequest.prototype.send,\n options: NetworkHookOptions\n): void {\n const states = new WeakMap<\n XMLHttpRequest,\n { method: string; url: string; startedAt: number; body?: unknown }\n >()\n\n XMLHttpRequestCtor.prototype.open = function open(\n this: XMLHttpRequest,\n method: string,\n url: string | URL,\n async?: boolean,\n username?: string | null,\n password?: string | null\n ): void {\n const args = [method, url, async, username, password].filter(\n (item) => item !== undefined\n )\n states.set(this, { method, url: String(url), startedAt: 0 })\n Reflect.apply(originalOpen, this, args)\n }\n\n XMLHttpRequestCtor.prototype.send = function send(\n this: XMLHttpRequest,\n ...args: Parameters<typeof originalSend>\n ): void {\n const [body] = args\n const state = states.get(this)\n\n if (state) {\n state.startedAt = Date.now()\n state.body = body\n const record = createHookNetworkRecord({\n pageId: options.pageId,\n url: state.url,\n method: state.method,\n requestBody: body,\n maskHeaders: options.maskHeaders,\n startedAt: state.startedAt\n })\n this.addEventListener('loadend', () => {\n const endedAt = Date.now()\n options.send({\n ...record,\n status: this.status,\n responseHeaders: parseRawHeaders(this.getAllResponseHeaders()),\n responseBody: truncateText(\n safeReadXhrResponseText(this),\n options.maxBodySize\n ).text,\n endedAt,\n durationMs: endedAt - state.startedAt\n })\n })\n }\n\n Reflect.apply(originalSend, this, args)\n }\n}\n\n/**\n * 获取 fetch 请求 URL。\n *\n * fetch 支持字符串、URL 和 Request,多形态输入需要统一为字符串才能进入 NetworkRecord。\n */\nfunction getFetchUrl(input: RequestInfo | URL): string {\n if (input instanceof Request) {\n return input.url\n }\n\n return String(input)\n}\n\n/**\n * 获取 fetch 请求方法。\n *\n * init.method 优先级最高,其次复用 Request.method,最后回退到 GET。\n */\nfunction getFetchMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method) {\n return init.method.toUpperCase()\n }\n\n if (input instanceof Request) {\n return input.method.toUpperCase()\n }\n\n return 'GET'\n}\n\n/**\n * 将 HeadersInit 转成普通对象。\n *\n * MCP 输出需要 JSON 友好的结构,不能直接返回 Headers 实例。\n */\nfunction headersToRecord(headers?: HeadersInit): Record<string, string> {\n if (!headers) {\n return {}\n }\n\n return Object.fromEntries(new Headers(headers).entries())\n}\n\n/**\n * 读取 fetch 响应体。\n *\n * 使用 clone 防止消费业务响应;读取失败时返回 undefined,让 Hook 不影响页面逻辑。\n */\nasync function readResponseBody(\n response: Response,\n maxBodySize: number\n): Promise<string | undefined> {\n try {\n return truncateText(await response.clone().text(), maxBodySize).text\n } catch {\n return undefined\n }\n}\n\n/**\n * 解析 XHR 原始响应头。\n *\n * XHR 只提供字符串格式的响应头,拆成对象后 MCP 工具更容易过滤和展示。\n */\nfunction parseRawHeaders(rawHeaders: string): Record<string, string> {\n return Object.fromEntries(\n rawHeaders\n .trim()\n .split(/\\r?\\n/)\n .filter(Boolean)\n .map((line) => {\n const index = line.indexOf(':')\n return [\n line.slice(0, index).trim().toLowerCase(),\n line.slice(index + 1).trim()\n ]\n })\n )\n}\n\n/**\n * 安全读取 XHR responseText。\n *\n * 某些 responseType 下读取 responseText 会抛错,Hook 必须静默降级而不是影响业务请求。\n */\nfunction safeReadXhrResponseText(xhr: XMLHttpRequest): string {\n try {\n return xhr.responseText\n } catch {\n return ''\n }\n}\n","/**\n * 解析请求 URL 中的 query 参数。\n *\n * Network 工具需要直接回答“请求参数是什么”,将 query 拆成结构化对象可以减少 AI 重复解析。\n */\nexport function parseRequestQuery(\n url: string\n): Record<string, string | string[]> {\n const parsed = new URL(url, 'http://vite-plugin-vue-mcp-next.local')\n const queryEntries = new Map<string, string | string[]>()\n\n for (const [key, value] of parsed.searchParams.entries()) {\n const existing = queryEntries.get(key)\n\n if (existing === undefined) {\n queryEntries.set(key, value)\n continue\n }\n\n if (Array.isArray(existing)) {\n existing.push(value)\n continue\n }\n\n queryEntries.set(key, [existing, value])\n }\n\n return Object.fromEntries(queryEntries)\n}\n\n/**\n * 获取 URL pathname。\n *\n * 页面 target 可能上报绝对 URL 或相对路径,该 helper 让展示逻辑不需要关心来源格式。\n */\nexport function safeUrlPathname(url: string): string {\n try {\n return new URL(url).pathname\n } catch {\n return url.split('?')[0] || '/'\n }\n}\n","/**\n * Runtime 页面身份生成。\n *\n * 该文件把页面级随机 pageId 和同标签页稳定 client id 分开维护,\n * 让 MCP 既能区分多标签页,又能在刷新重连时清理旧 runtime 目标。\n */\nimport { nanoid } from 'nanoid'\nimport { safeUrlPathname } from '../shared/url'\n\n/**\n * 页面运行时身份输入。\n *\n * 测试中传入 window-like 对象可以避免直接依赖浏览器全局对象。\n */\nexport interface RuntimePageIdentityInput {\n /** 当前页面完整 URL,用于关联 runtime target 和 CDP target。 */\n readonly href: string\n /** 当前页面标题,用于多页面调试时辅助识别。 */\n readonly title: string\n /** 同标签页稳定身份,用于服务端清理刷新或 HMR 造成的旧 runtime 连接。 */\n readonly runtimeClientId: string\n /** 视口宽度,用于帮助 AI 判断页面当前布局状态。 */\n readonly innerWidth: number\n /** 视口高度,用于帮助 AI 判断页面当前布局状态。 */\n readonly innerHeight: number\n /** 文档加载状态,用于解释某些 DOM 或日志为何暂时不可用。 */\n readonly readyState: DocumentReadyState\n}\n\n/**\n * runtime client id 的最小存储接口。\n *\n * 只依赖 getItem/setItem,便于在测试中使用轻量对象,也避免把身份生成逻辑绑定到浏览器全局对象。\n */\nexport interface RuntimeClientIdStorage {\n /** 读取同标签页已保存的 client id。 */\n getItem(key: string): string | null\n /** 写入同标签页后续刷新可复用的 client id。 */\n setItem(key: string, value: string): void\n}\n\n\n/**\n * runtime client id 的标签页作用域。\n *\n * 浏览器新标签页可能复制 opener 的 sessionStorage 初始值,因此需要一个不会被复制的标签页标记辅助区分。\n */\nexport interface RuntimeClientIdTabScope {\n /** window.name 会跨刷新保留,适合作为开发态调试身份的轻量标签页标记。 */\n name: string\n /** 当前 JS 上下文内的 runtime client id,优先用于抵御 HMR 或重复启动。 */\n __VITE_MCP_NEXT_RUNTIME_CLIENT_ID__?: string\n}\n\n/**\n * 页面运行时身份。\n *\n * Runtime Bridge 上报该结构后,服务端可以在没有 CDP 的情况下也维护可调试页面列表。\n */\nexport interface RuntimePageIdentity {\n /** runtime 页面唯一标识,同一路径多 tab 打开时仍可区分。 */\n readonly pageId: string\n /** 固定标记为 runtime,便于服务端区分 CDP target。 */\n readonly source: 'runtime'\n /** 当前页面完整 URL,用于展示和 target 关联。 */\n readonly url: string\n /** URL pathname,用于多入口页面的短路径展示。 */\n readonly pathname: string\n /** 页面标题,用于多页面调试时辅助识别。 */\n readonly title: string\n /** 同标签页稳定身份,用于服务端把刷新后的新连接和旧 pageId 关联起来。 */\n readonly runtimeClientId: string\n /** runtime 启动后页面默认处于可连接状态。 */\n readonly connected: true\n /** 文档加载状态,用于解释 DOM 快照时机。 */\n readonly readyState: DocumentReadyState\n /** 当前视口尺寸,用于帮助 AI 判断响应式布局状态。 */\n readonly viewport: {\n readonly width: number\n readonly height: number\n }\n}\n\nconst RUNTIME_CLIENT_ID_STORAGE_KEY = 'vite-plugin-vue-mcp-next:runtime-client-id'\nconst RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX =\n 'vite-plugin-vue-mcp-next:runtime-client-id='\nconst RUNTIME_CLIENT_ID_WINDOW_NAME_SEPARATOR = '\\n'\n\n/**\n * 创建同标签页稳定 client id。\n *\n * 该 ID 不作为 MCP 工具调用目标,只用于服务端识别同一个浏览器标签页刷新后的新连接。\n */\nexport function createRuntimeClientId(): string {\n return `runtime-client-${nanoid()}`\n}\n\n/**\n * 获取同标签页稳定 client id。\n *\n * 正常浏览器环境使用 sessionStorage 跨刷新复用;隐私模式或存储不可用时退回单次随机 ID,\n * 这样不会阻塞 runtime bridge 启动,只是无法自动合并该标签页的历史连接。\n */\n/**\n * 从 window.name 中读取 runtime client id。\n *\n * 该标记用于识别同一个真实标签页,避免新标签页复制 sessionStorage 后被误判为同一页面。\n */\nfunction readRuntimeClientIdFromTabScope(\n tabScope?: RuntimeClientIdTabScope\n): string | undefined {\n if (!tabScope) {\n return undefined\n }\n\n if (tabScope.__VITE_MCP_NEXT_RUNTIME_CLIENT_ID__) {\n return tabScope.__VITE_MCP_NEXT_RUNTIME_CLIENT_ID__\n }\n\n return tabScope.name\n .split(RUNTIME_CLIENT_ID_WINDOW_NAME_SEPARATOR)\n .find((item) => item.startsWith(RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX))\n ?.slice(RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX.length)\n}\n\n/**\n * 写入 window.name 中的 runtime client id 标记。\n *\n * 保留已有 window.name 内容,是为了降低对业务页面或测试页面自身 window.name 用法的影响。\n */\nfunction writeRuntimeClientIdToTabScope(\n tabScope: RuntimeClientIdTabScope,\n clientId: string\n): void {\n tabScope.__VITE_MCP_NEXT_RUNTIME_CLIENT_ID__ = clientId\n const preservedNameParts = tabScope.name\n .split(RUNTIME_CLIENT_ID_WINDOW_NAME_SEPARATOR)\n .filter((item) => !item.startsWith(RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX))\n .filter(Boolean)\n tabScope.name = [\n ...preservedNameParts,\n `${RUNTIME_CLIENT_ID_WINDOW_NAME_PREFIX}${clientId}`\n ].join(RUNTIME_CLIENT_ID_WINDOW_NAME_SEPARATOR)\n}\n\n/**\n * 保存 runtime client id。\n *\n * sessionStorage 支撑刷新复用,window.name 标记支撑区分复制 sessionStorage 的新标签页。\n */\nfunction persistRuntimeClientId(\n storage: RuntimeClientIdStorage,\n clientId: string,\n tabScope?: RuntimeClientIdTabScope\n): string {\n storage.setItem(RUNTIME_CLIENT_ID_STORAGE_KEY, clientId)\n\n if (tabScope) {\n writeRuntimeClientIdToTabScope(tabScope, clientId)\n }\n\n return clientId\n}\n\nexport function getRuntimeClientId(\n storage?: RuntimeClientIdStorage,\n tabScope?: RuntimeClientIdTabScope\n): string {\n const nextClientId = createRuntimeClientId()\n\n if (!storage) {\n return nextClientId\n }\n\n try {\n const tabScopedClientId = readRuntimeClientIdFromTabScope(tabScope)\n\n if (tabScopedClientId) {\n return persistRuntimeClientId(storage, tabScopedClientId, tabScope)\n }\n\n if (tabScope) {\n return persistRuntimeClientId(storage, nextClientId, tabScope)\n }\n\n const currentClientId = storage.getItem(RUNTIME_CLIENT_ID_STORAGE_KEY)\n\n if (currentClientId) {\n return currentClientId\n }\n\n return persistRuntimeClientId(storage, nextClientId)\n } catch {\n return nextClientId\n }\n}\n\n/**\n * 创建 runtime 页面 ID。\n *\n * 使用随机 ID 而不是 URL,是因为同一个页面可能在多个 tab 中同时打开。\n */\nexport function createRuntimePageId(): string {\n return `runtime-${nanoid()}`\n}\n\n/**\n * 读取页面身份信息。\n *\n * Runtime Bridge 启动后立即上报该信息,让 MCP 在没有 CDP 的情况下也能列出可调试页面。\n */\nexport function getRuntimePageIdentity(\n input: RuntimePageIdentityInput\n): RuntimePageIdentity {\n return {\n pageId: createRuntimePageId(),\n source: 'runtime',\n url: input.href,\n pathname: safeUrlPathname(input.href),\n title: input.title,\n runtimeClientId: input.runtimeClientId,\n connected: true,\n readyState: input.readyState,\n viewport: {\n width: input.innerWidth,\n height: input.innerHeight\n }\n }\n}\n","/**\n * 浏览器端性能采集 Hook。\n *\n * 该文件只负责收集运行态可见的长任务、内存趋势和错误堆栈,并把它们整理成统一的性能报告。\n */\nimport { nanoid } from 'nanoid'\nimport {\n buildMemorySummary,\n buildPerformanceSummary,\n buildStackSummary\n} from '../performance/summary'\nimport type {\n LongTaskRecord,\n MemorySample,\n PerformanceArtifact,\n PerformanceReport,\n StackFrameSummary\n} from '../types'\n\n/**\n * 性能采集器依赖。\n *\n * 通过依赖注入隔离浏览器原生 API,可以让单元测试直接驱动采集逻辑,而不用真的启动浏览器。\n */\nexport interface PerformanceCollectorDependencies {\n /** 页面 id,用于区分多标签页采样结果。 */\n readonly pageId: string\n /** 时间函数,便于测试固定时间线。 */\n readonly now: () => number\n /** 读取当前内存采样。 */\n readonly readMemory: () => MemorySample | undefined\n /** 安装 longtask 监听器,返回清理函数。 */\n readonly observeLongTask: (push: (task: LongTaskRecord) => void) => () => void\n /** 安装 long-animation-frame 监听器,返回清理函数。 */\n readonly observeAnimationFrame: (\n push: (task: LongTaskRecord) => void\n ) => () => void\n /** 安装 error 监听器,返回清理函数。 */\n readonly observeErrorStack?: (push: (stack: StackFrameSummary) => void) => () => void\n /** 安装 unhandledrejection 监听器,返回清理函数。 */\n readonly observeUnhandledRejectionStack?: (\n push: (stack: StackFrameSummary) => void\n ) => () => void\n /** 等待用 setTimeout。 */\n readonly setTimeout: typeof globalThis.setTimeout\n /** 清理等待用 setTimeout。 */\n readonly clearTimeout: typeof globalThis.clearTimeout\n}\n\n/**\n * 性能采集器。\n *\n * 一个页面只维护一个采集器,工具层通过 start/stop 或 recordOnce 控制采集窗口。\n */\nexport interface PerformanceCollector {\n /** 进行一次定时采集并返回报告。 */\n recordOnce(options: {\n durationMs: number\n includeMemory: boolean\n includeStacks: boolean\n }): Promise<PerformanceReport>\n /** 开始一段交互式采集,返回 recordingId。 */\n start(options: {\n includeMemory: boolean\n includeStacks: boolean\n }): string\n /** 结束交互式采集并返回报告。 */\n stop(recordingId: string): PerformanceReport\n /** 获取最近一次报告。 */\n latest(): PerformanceReport | undefined\n /** 释放监听器。 */\n dispose(): void\n}\n\nlet activePerformanceCollector: PerformanceCollector | undefined\n\n/**\n * 安装浏览器端性能 Hook。\n *\n * 该函数适用于页面启动阶段,会把真实浏览器 API 绑定到统一的采集器实例上。\n */\nexport function installPerformanceHook(options: {\n pageId: string\n send?: (report: PerformanceReport) => void\n sampleIntervalMs?: number\n longTaskThresholdMs?: number\n}): PerformanceCollector {\n const collector = createPerformanceCollector({\n pageId: options.pageId,\n now: () => Date.now(),\n readMemory: readBrowserMemory,\n observeLongTask: (push) => observeLongTasks(push, options.longTaskThresholdMs),\n observeAnimationFrame: observeAnimationFrameTasks,\n observeErrorStack: observeWindowErrorStack,\n observeUnhandledRejectionStack: observeUnhandledRejectionStack,\n setTimeout: window.setTimeout.bind(window),\n clearTimeout: window.clearTimeout.bind(window)\n })\n\n const decoratedCollector = options.send\n ? createDispatchingCollector(collector, options.send)\n : collector\n\n activePerformanceCollector = decoratedCollector\n\n return decoratedCollector\n}\n\n/**\n * 获取当前页面的性能采集器。\n *\n * RPC 层会在运行时调用这里,避免把采集状态散落在多个模块。\n */\nexport function getPerformanceCollector(): PerformanceCollector | undefined {\n return activePerformanceCollector\n}\n\n/**\n * 创建性能采集器。\n *\n * 采集器只做数据收集和报告聚合,不知道 MCP、CDP 或文件落盘的细节。\n */\nexport function createPerformanceCollector(\n deps: PerformanceCollectorDependencies\n): PerformanceCollector {\n const state: PerformanceCollectorState = {\n longTasks: [],\n stackFrames: [],\n memorySamples: [],\n latestReport: undefined,\n activeRecordingId: undefined,\n activeRecordingStartedAt: 0,\n activeIncludeMemory: true,\n activeIncludeStacks: true\n }\n\n const cleanups = [\n deps.observeLongTask((task) => {\n state.longTasks.push(task)\n }),\n deps.observeAnimationFrame((task) => {\n state.longTasks.push(task)\n })\n ]\n\n if (deps.observeErrorStack) {\n cleanups.push(\n deps.observeErrorStack((frame) => {\n state.stackFrames.push(frame)\n })\n )\n }\n\n if (deps.observeUnhandledRejectionStack) {\n cleanups.push(\n deps.observeUnhandledRejectionStack((frame) => {\n state.stackFrames.push(frame)\n })\n )\n }\n\n return {\n async recordOnce(options) {\n const recordingId = startSession(state, deps, {\n includeMemory: options.includeMemory,\n includeStacks: options.includeStacks\n })\n\n await waitForDuration(deps, options.durationMs)\n\n return stopSession({\n state,\n deps,\n recordingId,\n source: 'hook'\n })\n },\n start(options) {\n if (state.activeRecordingId) {\n throw new Error('A performance recording is already active')\n }\n\n return startSession(state, deps, options)\n },\n stop(recordingId) {\n return stopSession({\n state,\n deps,\n recordingId,\n source: 'hook'\n })\n },\n latest() {\n return state.latestReport\n },\n dispose() {\n activePerformanceCollector = undefined\n for (const cleanup of cleanups) {\n cleanup()\n }\n }\n }\n}\n\n/**\n * 性能采集器状态。\n */\ninterface PerformanceCollectorState {\n /** 长任务列表。 */\n longTasks: LongTaskRecord[]\n /** 堆栈列表。 */\n stackFrames: StackFrameSummary[]\n /** 内存采样列表。 */\n memorySamples: MemorySample[]\n /** 最近一次报告。 */\n latestReport?: PerformanceReport\n /** 当前活跃录制 id。 */\n activeRecordingId?: string\n /** 当前录制开始时间。 */\n activeRecordingStartedAt: number\n /** 当前录制是否采集内存。 */\n activeIncludeMemory: boolean\n /** 当前录制是否采集堆栈。 */\n activeIncludeStacks: boolean\n}\n\n/**\n * 创建录制 id。\n */\nfunction createRecordingId(): string {\n return `performance-${nanoid()}`\n}\n\n/**\n * 启动一次录制。\n */\nfunction startSession(\n state: PerformanceCollectorState,\n deps: PerformanceCollectorDependencies,\n options: {\n includeMemory: boolean\n includeStacks: boolean\n }\n): string {\n const recordingId = createRecordingId()\n state.longTasks.length = 0\n state.stackFrames.length = 0\n state.memorySamples.length = 0\n\n if (options.includeMemory) {\n const sample = deps.readMemory()\n if (sample) {\n state.memorySamples.push(sample)\n }\n }\n\n state.activeRecordingId = recordingId\n state.activeRecordingStartedAt = deps.now()\n state.activeIncludeMemory = options.includeMemory\n state.activeIncludeStacks = options.includeStacks\n\n return recordingId\n}\n\n/**\n * 给性能采集器包装一个报告分发器。\n *\n * runtime client 需要把完整报告同步推回服务端,但采集器本身不应感知 hot channel;\n * 这里用薄包装保持采集逻辑独立,同时让报告产生时自动上报。\n */\nfunction createDispatchingCollector(\n collector: PerformanceCollector,\n send: (report: PerformanceReport) => void\n): PerformanceCollector {\n return {\n async recordOnce(options) {\n const report = await collector.recordOnce(options)\n send(report)\n return report\n },\n start(options) {\n return collector.start(options)\n },\n stop(recordingId) {\n const report = collector.stop(recordingId)\n send(report)\n return report\n },\n latest() {\n return collector.latest()\n },\n dispose() {\n collector.dispose()\n }\n }\n}\n\n/**\n * 等待指定时长。\n */\nfunction waitForDuration(\n deps: PerformanceCollectorDependencies,\n durationMs: number\n): Promise<void> {\n return new Promise((resolve) => {\n const timer = deps.setTimeout(() => {\n deps.clearTimeout(timer)\n resolve()\n }, durationMs)\n })\n}\n\n/**\n * 构建最终报告。\n */\nfunction buildReport(options: {\n recordingId: string\n pageId: string\n startedAt: number\n endedAt: number\n source: 'cdp' | 'hook'\n includeMemory: boolean\n includeStacks: boolean\n longTasks: LongTaskRecord[]\n memorySamples: MemorySample[]\n stackFrames: StackFrameSummary[]\n limitations: string[]\n rawProfilePath?: string\n artifacts?: PerformanceArtifact[]\n}): PerformanceReport {\n const memory = options.includeMemory\n ? buildMemorySummary(options.memorySamples)\n : undefined\n const summary = buildPerformanceSummary({\n longTasks: options.longTasks,\n memorySamples: options.includeMemory ? options.memorySamples : []\n })\n const stacks = options.includeStacks\n ? buildStackSummary(options.stackFrames, {\n rawProfilePath: options.rawProfilePath,\n limitation:\n options.stackFrames.length > 0\n ? undefined\n : 'Runtime path only exposes error stacks when the page reports them'\n })\n : undefined\n const report: PerformanceReport = {\n recordingId: options.recordingId,\n pageId: options.pageId,\n source: options.source,\n startedAt: options.startedAt,\n endedAt: options.endedAt,\n durationMs: options.endedAt - options.startedAt,\n summary,\n longTasks: [...options.longTasks],\n memory,\n stacks,\n artifacts: options.artifacts,\n limitations: options.limitations\n }\n\n return report\n}\n\n/**\n * 结束一次录制并返回报告。\n */\nfunction stopSession(options: {\n state: PerformanceCollectorState\n deps: PerformanceCollectorDependencies\n recordingId: string\n source: 'cdp' | 'hook'\n}): PerformanceReport {\n const { state, deps, recordingId, source } = options\n\n if (!state.activeRecordingId || state.activeRecordingId !== recordingId) {\n throw new Error(`Performance recording not found: ${recordingId}`)\n }\n\n if (state.activeIncludeMemory) {\n const sample = deps.readMemory()\n if (sample) {\n state.memorySamples.push(sample)\n }\n }\n\n const report = buildReport({\n recordingId: state.activeRecordingId,\n pageId: deps.pageId,\n startedAt: state.activeRecordingStartedAt,\n endedAt: deps.now(),\n source,\n includeMemory: state.activeIncludeMemory,\n includeStacks: state.activeIncludeStacks,\n longTasks: state.longTasks,\n memorySamples: state.memorySamples,\n stackFrames: state.stackFrames,\n limitations: [\n 'Runtime path only sees browser-observable signals',\n 'Runtime path cannot produce a full CPU profile or heap snapshot'\n ]\n })\n\n state.latestReport = report\n state.activeRecordingId = undefined\n state.activeRecordingStartedAt = 0\n state.activeIncludeMemory = true\n state.activeIncludeStacks = true\n\n return report\n}\n\n/**\n * 从当前运行环境读取内存。\n */\nfunction readBrowserMemory(): MemorySample | undefined {\n const memory = (performance as Performance & {\n memory?: {\n usedJSHeapSize: number\n totalJSHeapSize: number\n jsHeapSizeLimit: number\n }\n }).memory\n\n if (!memory) {\n return undefined\n }\n\n return {\n timestamp: Date.now(),\n usedJSHeapSize: memory.usedJSHeapSize,\n totalJSHeapSize: memory.totalJSHeapSize,\n jsHeapSizeLimit: memory.jsHeapSizeLimit\n }\n}\n\n/**\n * 安装 long task 监听器。\n */\nfunction observeLongTasks(\n push: (task: LongTaskRecord) => void,\n longTaskThresholdMs = 50\n): () => void {\n if (typeof PerformanceObserver === 'undefined') {\n return () => {}\n }\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.duration < longTaskThresholdMs) {\n continue\n }\n\n push({\n startTime: entry.startTime,\n durationMs: entry.duration,\n name: entry.name,\n source: 'longtask'\n })\n }\n })\n\n observer.observe({ type: 'longtask', buffered: true })\n\n return () => {\n observer.disconnect()\n }\n}\n\n/**\n * 安装 long-animation-frame 监听器。\n */\nfunction observeAnimationFrameTasks(\n push: (task: LongTaskRecord) => void\n): () => void {\n if (typeof PerformanceObserver === 'undefined') {\n return () => {}\n }\n\n const supported = PerformanceObserver.supportedEntryTypes.includes(\n 'long-animation-frame'\n )\n\n if (!supported) {\n return () => {}\n }\n\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n push({\n startTime: entry.startTime,\n durationMs: entry.duration,\n name: entry.name,\n source: 'long-animation-frame'\n })\n }\n })\n\n observer.observe({ type: 'long-animation-frame', buffered: true })\n\n return () => {\n observer.disconnect()\n }\n}\n\n/**\n * 安装 window error 监听器。\n */\nfunction observeWindowErrorStack(\n push: (frame: StackFrameSummary) => void\n): () => void {\n const onError = (event: ErrorEvent): void => {\n const error = event.error as Error | undefined\n const frames = parseStackFrames(error?.stack)\n if (frames.length === 0 && event.message) {\n push({ functionName: event.message })\n return\n }\n\n frames.forEach((frame) => {\n push(frame)\n })\n }\n\n window.addEventListener('error', onError)\n\n return () => {\n window.removeEventListener('error', onError)\n }\n}\n\n/**\n * 安装 unhandledrejection 监听器。\n */\nfunction observeUnhandledRejectionStack(\n push: (frame: StackFrameSummary) => void\n): () => void {\n const onRejection = (event: PromiseRejectionEvent): void => {\n const reason = event.reason as Error | undefined\n const frames = parseStackFrames(reason?.stack)\n\n if (frames.length === 0 && reason?.message) {\n push({ functionName: reason.message })\n return\n }\n\n frames.forEach((frame) => {\n push(frame)\n })\n }\n\n window.addEventListener('unhandledrejection', onRejection)\n\n return () => {\n window.removeEventListener('unhandledrejection', onRejection)\n }\n}\n\n/**\n * 解析 stack 文本。\n */\nfunction parseStackFrames(stack?: string): StackFrameSummary[] {\n if (!stack) {\n return []\n }\n\n return stack\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => {\n const match = /at\\s+(.*?)\\s+\\((.*?):(\\d+):(\\d+)\\)$/.exec(line)\n\n if (match) {\n return {\n functionName: match[1] || '<anonymous>',\n url: match[2],\n lineNumber: Number(match[3]),\n columnNumber: Number(match[4])\n }\n }\n\n return { functionName: line }\n })\n}\n","/**\n * 性能报告摘要计算。\n *\n * 这个文件只保留纯数据归纳逻辑,不依赖浏览器 API 或 CDP client,便于 runtime 和 CDP 两条路径共享同一口径。\n */\nimport { DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS } from '../constants'\nimport type {\n LongTaskRecord,\n MemorySample,\n MemorySummary,\n PerformanceSummary,\n StackFrameSummary,\n StackSummary\n} from '../types'\n\n/**\n * 计算性能摘要。\n *\n * 该摘要面向快速判断页面是否明显卡顿,不追求把所有原始信号都塞进结果里。\n */\nexport function buildPerformanceSummary(input: {\n longTasks: LongTaskRecord[]\n memorySamples: MemorySample[]\n}): PerformanceSummary {\n const memory = buildMemorySummary(input.memorySamples)\n const blockedTimeMs = input.longTasks.reduce((total, task) => {\n return (\n total +\n Math.max(0, task.durationMs - DEFAULT_PERFORMANCE_LONG_TASK_THRESHOLD_MS)\n )\n }, 0)\n const longTaskCount = input.longTasks.length\n const durations = input.longTasks.map((task) => task.durationMs)\n const maxTaskDurationMs = durations.length ? Math.max(...durations) : 0\n const averageTaskDurationMs = durations.length\n ? Math.round(\n durations.reduce((total, duration) => total + duration, 0) /\n durations.length\n )\n : undefined\n const suspectedJank =\n blockedTimeMs > 0 || memory.trend === 'growing' || longTaskCount > 0\n const severity = resolveSeverity({\n blockedTimeMs,\n longTaskCount,\n memoryTrend: memory.trend\n })\n\n return {\n blockedTimeMs,\n longTaskCount,\n maxTaskDurationMs,\n averageTaskDurationMs,\n suspectedJank,\n severity\n }\n}\n\n/**\n * 计算内存趋势。\n *\n * 只比较首尾和峰值,不推断对象引用关系,这样 runtime-only 路径也能给出稳定结论。\n */\nexport function buildMemorySummary(samples: MemorySample[]): MemorySummary {\n const first = samples[0]?.usedJSHeapSize\n const last = samples.at(-1)?.usedJSHeapSize\n const peak = samples.reduce((currentPeak, sample) => {\n if (typeof sample.usedJSHeapSize !== 'number') {\n return currentPeak\n }\n\n return Math.max(currentPeak, sample.usedJSHeapSize)\n }, 0)\n\n const trend = resolveMemoryTrend(first, last)\n\n return {\n samples,\n initialUsedJSHeapSize: first,\n finalUsedJSHeapSize: last,\n peakUsedJSHeapSize: peak || undefined,\n deltaUsedJSHeapSize:\n typeof first === 'number' && typeof last === 'number'\n ? last - first\n : undefined,\n trend\n }\n}\n\n/**\n * 计算堆栈摘要。\n *\n * 该函数只做排序和裁剪,不直接理解 CPU profile 或错误对象,方便 CDP 和 runtime 传入不同来源的帧数据。\n */\nexport function buildStackSummary(\n frames: StackFrameSummary[],\n options: { rawProfilePath?: string; limitation?: string } = {}\n): StackSummary {\n return {\n topFrames: [...frames].sort(sortByHotness).slice(0, 10),\n rawProfilePath: options.rawProfilePath,\n limitation: options.limitation\n }\n}\n\n/**\n * 根据卡顿指标判断严重程度。\n *\n * 这个分级只用于调试报告的阅读提示,不代表生产级告警阈值。\n */\nfunction resolveSeverity(input: {\n blockedTimeMs: number\n longTaskCount: number\n memoryTrend: MemorySummary['trend']\n}): PerformanceSummary['severity'] {\n if (input.blockedTimeMs >= 1000 || input.longTaskCount >= 10) {\n return 'critical'\n }\n\n if (input.blockedTimeMs > 0 || input.memoryTrend === 'growing') {\n return 'warning'\n }\n\n return 'ok'\n}\n\n/**\n * 根据首尾内存采样判断趋势。\n *\n * 只要存在明显上升就视为 growing,避免 runtime 路径因单次抖动而过度乐观。\n */\nfunction resolveMemoryTrend(\n first: number | undefined,\n last: number | undefined\n): MemorySummary['trend'] {\n if (typeof first !== 'number' || typeof last !== 'number') {\n return 'unknown'\n }\n\n if (last > first) {\n return 'growing'\n }\n\n return 'stable'\n}\n\n/**\n * 按热点程度给堆栈帧排序。\n *\n * 优先比较总耗时,再比较自身耗时和命中次数,保证摘要更偏向真正的热点函数。\n */\nfunction sortByHotness(\n left: StackFrameSummary,\n right: StackFrameSummary\n): number {\n return compareNumber(right.totalTimeMs, left.totalTimeMs)\n || compareNumber(right.selfTimeMs, left.selfTimeMs)\n || compareNumber(right.hitCount, left.hitCount)\n}\n\n/**\n * 比较可选数值。\n *\n * 空值统一排后,方便摘要维持稳定排序。\n */\nfunction compareNumber(left?: number, right?: number): number {\n return (left ?? -1) - (right ?? -1)\n}\n","/**\n * 浏览器端 snapdom 截图降级能力。\n *\n * 该文件只在页面 runtime 中执行,适用于没有 CDP 但仍希望让 MCP 客户端看到页面视觉结果的场景;\n * 函数型扩展通过 Vite import 路径加载,避免 Node 侧配置直接跨运行时传递函数。\n */\nimport type {\n RuntimeScreenshotResult,\n ScreenshotFormat,\n ScreenshotTarget,\n SnapdomPluginImport,\n SnapdomScreenshotOptions\n} from '../types'\n\n/**\n * Runtime 截图参数。\n *\n * loader 只用于测试替换和 Vite 动态 import 边界;正常业务调用只需要传截图目标和 snapdom 配置。\n */\nexport interface RuntimeScreenshotOptions {\n /** 截图目标范围,用于选择 documentElement 或 selector 元素。 */\n readonly target: ScreenshotTarget\n /** 元素截图选择器,只在 `target: \"element\"` 时使用。 */\n readonly selector?: string\n /** 输出格式,决定 Blob mime type 和压缩策略。 */\n readonly format: ScreenshotFormat\n /** 有损格式质量,适用于 jpeg/webp 控制响应体积。 */\n readonly quality?: number\n /** 单次调用缩放倍率覆盖值,适合临时请求高清局部截图。 */\n readonly scale?: number\n /** 已解析 snapdom 配置,函数型配置仍以 Vite import 路径表达。 */\n readonly snapdom: Required<\n Pick<SnapdomScreenshotOptions, 'options' | 'plugins'>\n > &\n Omit<SnapdomScreenshotOptions, 'options' | 'plugins'>\n /** 测试或特殊运行环境替换 snapdom 加载方式时使用。 */\n readonly loadSnapdom?: () => Promise<{ snapdom: SnapdomFunction }>\n /** 测试或特殊运行环境替换 Vite 动态 import 时使用。 */\n readonly loadModule?: (path: string) => Promise<Record<string, unknown>>\n}\n\n/**\n * snapdom 函数边界。\n *\n * 只声明当前截图流程需要的最小能力,可以让本插件不绑定 snapdom 的完整内部类型。\n */\ntype SnapdomFunction = (\n element: Element,\n options: Record<string, unknown>\n) => Promise<{ toBlob: (options?: Record<string, unknown>) => Promise<Blob> }>\n\n/**\n * snapdom 加载器。\n *\n * 该函数由 Vite 虚拟模块注册,避免发布包 runtime 直接 import optional peer 后触发 optimizeDeps 失败。\n */\ntype SnapdomLoader = () => Promise<{ snapdom: SnapdomFunction }>\n\n/**\n * 默认 snapdom 加载器。\n *\n * 缺失 optional peer 时返回结构化错误,适合 MCP 工具把原因直接反馈给大模型。\n */\nlet snapdomLoader: SnapdomLoader = () =>\n Promise.reject(createMissingSnapdomError())\n\n/**\n * snapdom 扩展模块注册表。\n *\n * 注册表由 Vite 注入的虚拟 runtime wrapper 写入,而不是在发布的 runtime client 里直接 import 虚拟模块;\n * 这样可以避开 Vite optimizeDeps 扫描 node_modules 时无法解析虚拟模块的问题。\n */\nlet screenshotModuleRegistry: Partial<Record<string, Record<string, unknown>>> =\n {}\n\n/**\n * 注册截图扩展模块。\n *\n * Vite import 路径必须在宿主项目的 Vite 模块图里解析,适用于插件、filter、fallbackURL 需要使用 alias 或源码转换的场景。\n */\nexport function setScreenshotModuleRegistry(\n registry: Record<string, Record<string, unknown>>\n): void {\n screenshotModuleRegistry = registry\n}\n\n/**\n * 注册 snapdom 加载器。\n *\n * 只有宿主 Vite 项目可以正确解析 optional peer,因此由虚拟 runtime 入口在浏览器侧注册。\n */\nexport function setSnapdomLoader(loader: SnapdomLoader): void {\n snapdomLoader = loader\n}\n\n/**\n * 执行 runtime DOM 截图。\n *\n * snapdom 截图是 CDP 不可用时的兼容路径,因此返回结果必须带 `source: \"snapdom\"` 和限制说明。\n */\nexport async function takeRuntimeScreenshot(\n options: RuntimeScreenshotOptions\n): Promise<RuntimeScreenshotResult & { source?: 'snapdom' }> {\n const target = resolveScreenshotTarget(options.target, options.selector)\n\n if (!target.ok) {\n return target\n }\n\n const loadSnapdom = options.loadSnapdom ?? loadDefaultSnapdom\n let loaded: { snapdom: SnapdomFunction }\n\n try {\n loaded = await loadSnapdom()\n } catch (error) {\n return {\n ok: false,\n source: 'snapdom',\n error: error instanceof Error ? error.message : String(error)\n }\n }\n\n const { snapdom } = loaded\n const snapdomOptions = await createSnapdomOptions(options)\n const capture = await snapdom(target.element, snapdomOptions)\n const blob = await capture.toBlob({\n type: createMimeType(options.format),\n quality: options.quality\n })\n const data = await blobToBase64(blob)\n const rect = target.element.getBoundingClientRect()\n\n return {\n ok: true,\n source: 'snapdom',\n data,\n width: rect.width,\n height: rect.height,\n mimeType: createMimeType(options.format),\n byteLength: blob.size,\n limitations: [\n 'snapdom renders DOM to an image and may differ from browser pixels',\n 'cross-origin images, iframe content, video, WebGL, and complex CSS may be incomplete'\n ]\n }\n}\n\n/**\n * 加载默认 snapdom 实现。\n *\n * 真实加载逻辑由宿主 Vite 虚拟模块注册,适合 optional peer 缺失时把错误留到 MCP 工具响应阶段。\n */\nfunction loadDefaultSnapdom(): Promise<{ snapdom: SnapdomFunction }> {\n return snapdomLoader()\n}\n\n/**\n * 解析截图目标元素。\n *\n * runtime 降级截图只能读取页面自身 DOM;在边界处返回明确错误可以让 MCP 工具解释失败原因。\n */\nfunction resolveScreenshotTarget(\n target: ScreenshotTarget,\n selector?: string\n):\n | { ok: true; element: Element }\n | { ok: false; error: string } {\n if (target === 'element' && !selector) {\n return { ok: false, error: 'selector is required when target is element' }\n }\n\n if (target === 'element') {\n if (!selector) {\n return { ok: false, error: 'selector is required when target is element' }\n }\n\n const elementSelector = selector\n const element = document.querySelector(elementSelector)\n\n return element\n ? { ok: true, element }\n : { ok: false, error: `element not found: ${elementSelector}` }\n }\n\n return { ok: true, element: document.documentElement }\n}\n\n/**\n * 组装 snapdom options。\n *\n * 项目级配置和单次调用配置需要在浏览器端合并,因为插件、filter、fallbackURL 都依赖 Vite import。\n */\nasync function createSnapdomOptions(\n options: RuntimeScreenshotOptions\n): Promise<Record<string, unknown>> {\n const snapdomOptions: Record<string, unknown> = {\n ...options.snapdom.options,\n quality: options.quality ?? options.snapdom.options.quality,\n scale: options.scale ?? options.snapdom.options.scale,\n plugins: await loadSnapdomPlugins(options)\n }\n const loadModule = createModuleLoader(options)\n\n if (options.snapdom.filter) {\n snapdomOptions.filter = await loadDefaultExport(\n loadModule,\n options.snapdom.filter\n )\n }\n\n if (options.snapdom.fallbackURL) {\n snapdomOptions.fallbackURL = await loadDefaultExport(\n loadModule,\n options.snapdom.fallbackURL\n )\n }\n\n return removeUndefinedEntries(snapdomOptions)\n}\n\n/**\n * 加载 snapdom 插件。\n *\n * 插件只能通过 Vite import 路径进入浏览器 runtime,适用于用户插件依赖源码别名或 Vite transform 的场景。\n */\nasync function loadSnapdomPlugins(\n options: RuntimeScreenshotOptions\n): Promise<unknown[]> {\n const loadModule = createModuleLoader(options)\n\n return Promise.all(\n options.snapdom.plugins.map((plugin) => loadPluginImport(plugin, loadModule))\n )\n}\n\n/**\n * 创建模块加载器。\n *\n * 独立函数可以让测试注入 fake loader,同时真实运行时保留 Vite 对动态 import 的处理。\n */\nfunction createModuleLoader(\n options: RuntimeScreenshotOptions\n): (path: string) => Promise<Record<string, unknown>> {\n return options.loadModule ?? loadConfiguredModule\n}\n\n/**\n * 从虚拟模块读取用户配置模块。\n *\n * 这里仅读取已注册表,不直接 import 虚拟模块;发布包中的 runtime client 会被 Vite 依赖优化扫描,\n * 保留虚拟 import 会让用户项目在启动阶段失败。\n */\nfunction loadConfiguredModule(\n path: string\n): Promise<Record<string, unknown>> {\n const mod = screenshotModuleRegistry[path]\n\n if (!mod) {\n throw new Error(`screenshot module is not registered: ${path}`)\n }\n\n return Promise.resolve(mod)\n}\n\n/**\n * 加载单个插件声明。\n *\n * 插件模块可能直接导出插件对象,也可能导出插件工厂;这里按是否提供 options 决定是否调用工厂。\n */\nasync function loadPluginImport(\n plugin: SnapdomPluginImport,\n loadModule: (path: string) => Promise<Record<string, unknown>>\n): Promise<unknown> {\n const normalized =\n typeof plugin === 'string'\n ? { path: plugin, exportName: 'default' }\n : { exportName: 'default', ...plugin }\n const mod = await loadModule(normalized.path)\n const exported = mod[normalized.exportName]\n\n if (isPluginFactory(exported) && 'options' in normalized) {\n return exported(normalized.options)\n }\n\n return exported\n}\n\n/**\n * 判断导出值是否是插件工厂。\n *\n * 动态 import 的模块导出是 unknown,先收窄再调用可以避免把任意值当函数执行。\n */\nfunction isPluginFactory(value: unknown): value is (options: unknown) => unknown {\n return typeof value === 'function'\n}\n\n/**\n * 加载默认导出函数。\n *\n * filter 和 fallbackURL 是 snapdom 原生函数型扩展,路径化加载能保留函数能力但不跨运行时序列化函数。\n */\nasync function loadDefaultExport(\n loadModule: (path: string) => Promise<Record<string, unknown>>,\n path: string\n): Promise<unknown> {\n return (await loadModule(path)).default\n}\n\n/**\n * 生成图片 mime type。\n *\n * MCP 响应需要明确 mime type,方便客户端按格式解码 base64 图片。\n */\nfunction createMimeType(format: ScreenshotFormat): string {\n return `image/${format}`\n}\n\n/**\n * 将 Blob 转成 base64。\n *\n * runtime 运行在浏览器里不能依赖 Node Buffer,因此使用 ArrayBuffer 和 btoa 完成编码。\n */\nasync function blobToBase64(blob: Blob): Promise<string> {\n const bytes = new Uint8Array(await blob.arrayBuffer())\n let binary = ''\n\n for (const byte of bytes) {\n binary += String.fromCharCode(byte)\n }\n\n return btoa(binary)\n}\n\n/**\n * 删除 undefined 配置。\n *\n * snapdom options 里保留 undefined 没有语义,清理后更容易在测试和调试时确认真实传参。\n */\nfunction removeUndefinedEntries(\n value: Record<string, unknown>\n): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(value).filter(([, item]) => item !== undefined)\n )\n}\n\n/**\n * 创建缺失 snapdom 的错误。\n *\n * 错误文案必须包含安装命令,方便 MCP 客户端和大模型直接指导用户修复环境。\n */\nfunction createMissingSnapdomError(): Error {\n return new Error(\n '缺少可选依赖 @zumer/snapdom。DOM 截图降级需要该依赖,请执行:pnpm add -D @zumer/snapdom'\n )\n}\n","/**\n * Vue Runtime Bridge 负责把 Vue Devtools runtime API 暴露给 MCP 服务端。\n *\n * 该文件只处理 Vue 语义能力,适用于组件树、组件状态、Router 和 Pinia 等 CDP 无法直接表达的应用层信息。\n */\nimport {\n devtools,\n devtoolsRouterInfo,\n devtoolsState,\n getInspector,\n stringify,\n toggleHighPerfMode\n} from '@vue/devtools-kit'\nimport { createRPCClient } from 'vite-dev-rpc'\nimport type { ViteHotContext } from 'vite-hot-client'\nimport type { VueRuntimeRpc } from '../types'\nimport { getPerformanceCollector } from './performanceHook'\nimport { createRuntimeDevtoolsRpc } from './devtoolsBridge'\n\nconst PINIA_INSPECTOR_ID = 'pinia'\nconst COMPONENTS_INSPECTOR_ID = 'components'\nconst COMPONENT_HIGHLIGHT_DURATION = 5000\n\nlet highlightComponentTimeout: ReturnType<typeof setTimeout> | undefined\n\n/**\n * 同步初始化 Vue Devtools hook。\n *\n * Vue 会在应用 mount 时读取全局 hook 并注册 app,因此该函数必须在任何异步等待前执行。\n */\nexport function initializeVueDevtoolsHook(): void {\n devtools.init()\n}\n\n/**\n * 安装 Vue Runtime RPC。\n *\n * RPC 依赖 Vite hot context 传输消息,因此只能在 hot context 创建成功后安装。\n */\nexport function installVueBridge(hot: ViteHotContext): void {\n const rpcRef: { current?: VueRuntimeRpc } = {}\n const rpc = createRPCClient<VueRuntimeRpc, VueRuntimeRpc>(\n 'vite-plugin-vue-mcp-next',\n hot,\n createClientVueRuntimeRpc(() => {\n if (!rpcRef.current) {\n throw new Error('Vue runtime RPC is not initialized')\n }\n return rpcRef.current\n }),\n { timeout: -1 }\n )\n rpcRef.current = rpc\n}\n\n/**\n * 创建浏览器端 Vue RPC 实现。\n *\n * 函数单独拆分可以让每个 Vue 能力的错误边界集中处理,避免 MCP 请求因为某个组件缺失而崩溃。\n */\nfunction createClientVueRuntimeRpc(getRpc: () => VueRuntimeRpc): VueRuntimeRpc {\n return {\n ...createRuntimeDevtoolsRpc(getRpc),\n async getInspectorTree(query) {\n const inspectorTree = await devtools.api.getInspectorTree({\n inspectorId: COMPONENTS_INSPECTOR_ID,\n filter: query.componentName ?? ''\n })\n getRpc().onInspectorTreeUpdated(query.event, inspectorTree[0])\n },\n onInspectorTreeUpdated: () => undefined,\n async getInspectorState(query) {\n const targetNode = await findComponentNode(query.componentName)\n if (!targetNode) {\n getRpc().onInspectorStateUpdated(\n query.event,\n createMissingComponentError(query.componentName)\n )\n return\n }\n\n const inspectorState = await devtools.api.getInspectorState({\n inspectorId: COMPONENTS_INSPECTOR_ID,\n nodeId: targetNode.id\n })\n getRpc().onInspectorStateUpdated(query.event, stringify(inspectorState))\n },\n onInspectorStateUpdated: () => undefined,\n async editComponentState(query) {\n const targetNode = await findComponentNode(query.componentName)\n if (!targetNode) {\n return\n }\n\n devtools.ctx.api.editInspectorState({\n app: null,\n inspectorId: COMPONENTS_INSPECTOR_ID,\n nodeId: targetNode.id,\n path: query.path,\n state: {\n remove: false,\n value: parseStateValue(query.value, query.valueType)\n },\n type: query.valueType,\n set: setStateValue\n })\n },\n async highlightComponent(query) {\n const targetNode = await findComponentNode(query.componentName)\n if (!targetNode) {\n return\n }\n\n if (highlightComponentTimeout) {\n clearTimeout(highlightComponentTimeout)\n }\n\n callVueDevtoolsHook('componentHighlight', { uid: targetNode.id })\n highlightComponentTimeout = setTimeout(() => {\n callVueDevtoolsHook('componentUnhighlight')\n }, COMPONENT_HIGHLIGHT_DURATION)\n },\n getRouterInfo(query) {\n getRpc().onRouterInfoUpdated(\n query.event,\n JSON.stringify(devtoolsRouterInfo, null, 2)\n )\n },\n onRouterInfoUpdated: () => undefined,\n async getPiniaTree(query) {\n const inspectorTree = await withPiniaHighPerfDisabled(() =>\n devtools.api.getInspectorTree({\n inspectorId: PINIA_INSPECTOR_ID,\n filter: ''\n })\n )\n getRpc().onPiniaTreeUpdated(query.event, inspectorTree)\n },\n onPiniaTreeUpdated: () => undefined,\n async getPiniaState(query) {\n const result = await withPiniaHighPerfDisabled(async () => {\n const payload = {\n inspectorId: PINIA_INSPECTOR_ID,\n nodeId: query.storeName\n }\n const inspector = getInspector(payload.inspectorId)\n\n if (inspector) {\n inspector.selectedNodeId = payload.nodeId\n }\n\n return devtools.ctx.api.getInspectorState(payload)\n })\n getRpc().onPiniaInfoUpdated(query.event, stringify(result))\n },\n onPiniaInfoUpdated: () => undefined,\n async recordPerformance(query) {\n const collector = getPerformanceCollector()\n\n if (!collector) {\n getRpc().onPerformanceRecorded(\n query.event,\n createPerformanceUnavailableError()\n )\n return\n }\n\n try {\n const report = await collector.recordOnce({\n durationMs: query.durationMs,\n includeMemory: query.includeMemory,\n includeStacks: query.includeStacks\n })\n getRpc().onPerformanceRecorded(query.event, report)\n } catch (error) {\n getRpc().onPerformanceRecorded(\n query.event,\n createPerformanceError(error)\n )\n }\n },\n onPerformanceRecorded: () => undefined,\n startPerformanceRecording(query) {\n const collector = getPerformanceCollector()\n\n if (!collector) {\n getRpc().onPerformanceRecordingStarted(\n query.event,\n createPerformanceUnavailableError()\n )\n return\n }\n\n try {\n const recordingId = collector.start({\n includeMemory: query.includeMemory,\n includeStacks: query.includeStacks\n })\n getRpc().onPerformanceRecordingStarted(query.event, {\n ok: true,\n recordingId,\n startedAt: Date.now(),\n source: 'hook'\n })\n } catch (error) {\n getRpc().onPerformanceRecordingStarted(\n query.event,\n createPerformanceError(error)\n )\n }\n },\n onPerformanceRecordingStarted: () => undefined,\n stopPerformanceRecording(query) {\n const collector = getPerformanceCollector()\n\n if (!collector) {\n getRpc().onPerformanceRecordingStopped(\n query.event,\n createPerformanceUnavailableError()\n )\n return\n }\n\n try {\n const report = collector.stop(query.recordingId)\n getRpc().onPerformanceRecordingStopped(query.event, report)\n } catch (error) {\n getRpc().onPerformanceRecordingStopped(\n query.event,\n createPerformanceError(error)\n )\n }\n },\n onPerformanceRecordingStopped: () => undefined\n }\n}\n\n/**\n * Vue DevTools editInspectorState 需要的 set 回调。\n *\n * 运行时 bridge 只负责把 MCP 请求转交给 DevTools API,实际状态写入由 DevTools 内部完成;\n * 这里提供保守赋值实现,保证新版类型要求满足且不引入额外依赖。\n */\nfunction setStateValue(\n object: unknown,\n path?: string | string[],\n value?: unknown\n): void {\n if (!object || typeof object !== 'object' || !path) {\n return\n }\n\n const keys = Array.isArray(path) ? path : [path]\n const lastKey = keys.at(-1)\n\n if (!lastKey) {\n return\n }\n\n ;(object as Record<string, unknown>)[lastKey] = value\n}\n\n/**\n * 按 MCP 输入类型解析组件状态值。\n *\n * DevTools Kit 当前只接收最终 value,不再接收旧版本的 type 字段,\n * 因此这里在 bridge 内部完成基础类型转换。\n */\nfunction parseStateValue(value: string, valueType: string): unknown {\n if (valueType === 'number') {\n return Number(value)\n }\n\n if (valueType === 'boolean') {\n return value === 'true'\n }\n\n if (valueType === 'object' || valueType === 'array') {\n try {\n return JSON.parse(value) as unknown\n } catch {\n return value\n }\n }\n\n return value\n}\n\n/**\n * 调用 Vue DevTools 内部 hook。\n *\n * 当前 @vue/devtools-kit 的公开类型没有覆盖组件高亮 hook,但运行时仍提供该能力;\n * 单独收敛类型逃逸可以避免把不稳定内部事件扩散到业务逻辑。\n */\nfunction callVueDevtoolsHook(name: string, payload?: unknown): void {\n const hooks = devtools.ctx.hooks as {\n callHook: (event: string, payload?: unknown) => void\n }\n hooks.callHook(name, payload)\n}\n\n/**\n * 生成性能 RPC 不可用的统一错误回包。\n *\n * performance collector 只在 runtime client 完成安装后存在;如果 Vue bridge 先被调用,\n * 与其让请求悬空,不如明确告诉服务端稍后重试。\n */\nfunction createPerformanceUnavailableError(): {\n readonly ok: false\n readonly error: string\n} {\n return {\n ok: false,\n error: 'Performance collector is not initialized'\n }\n}\n\n/**\n * 把性能 RPC 异常收敛成结构化错误。\n *\n * 运行态采集不应该把异常直接抛回 RPC 调用链,否则会让整个 bridge 请求失败。\n */\nfunction createPerformanceError(error: unknown): {\n readonly ok: false\n readonly error: string\n} {\n return {\n ok: false,\n error: error instanceof Error ? error.message : String(error)\n }\n}\n\n/**\n * 查找组件节点。\n *\n * 组件名来自 MCP 输入,运行时必须处理找不到组件的情况,而不是直接访问 undefined.id。\n */\nasync function findComponentNode(\n componentName: string\n): Promise<{ id: string; name?: string; children?: unknown[] } | undefined> {\n const inspectorTree = await devtools.api.getInspectorTree({\n inspectorId: COMPONENTS_INSPECTOR_ID,\n filter: ''\n })\n const nodes = flattenTree(inspectorTree[0])\n\n return nodes.find((node) => node.name === componentName)\n}\n\n/**\n * 展平 Vue inspector tree。\n *\n * Vue DevTools 返回树状结构,按组件名查找状态和高亮目标时需要递归展开。\n */\nfunction flattenTree(\n root: unknown\n): Array<{ id: string; name?: string; children?: unknown[] }> {\n const result: Array<{ id: string; name?: string; children?: unknown[] }> = []\n\n const traverse = (node: unknown): void => {\n if (!isInspectorNode(node)) {\n return\n }\n\n result.push(node)\n node.children?.forEach((child) => {\n traverse(child)\n })\n }\n\n traverse(root)\n return result\n}\n\n/**\n * 校验 Vue inspector 节点的最小结构。\n *\n * DevTools 数据结构可能随版本变化,使用窄类型保护可以降低运行时异常风险。\n */\nfunction isInspectorNode(\n node: unknown\n): node is { id: string; name?: string; children?: unknown[] } {\n return Boolean(\n node &&\n typeof node === 'object' &&\n typeof (node as { id?: unknown }).id === 'string'\n )\n}\n\n/**\n * 临时关闭 Pinia high perf mode 后执行读取。\n *\n * Pinia inspector 在高性能模式下可能不返回完整状态,读取后恢复原状态可以避免影响用户调试体验。\n */\nasync function withPiniaHighPerfDisabled<T>(\n callback: () => Promise<T>\n): Promise<T> {\n const highPerfModeEnabled = devtoolsState.highPerfModeEnabled\n\n if (highPerfModeEnabled) {\n toggleHighPerfMode(false)\n }\n\n try {\n return await callback()\n } finally {\n if (highPerfModeEnabled) {\n toggleHighPerfMode(true)\n }\n }\n}\n\n/**\n * 创建组件缺失错误。\n *\n * 返回结构化错误比抛异常更适合 MCP 场景,AI 可以直接把原因反馈给用户。\n */\nfunction createMissingComponentError(componentName: string): {\n ok: false\n error: string\n} {\n return {\n ok: false,\n error: `component not found: ${componentName}`\n }\n}\n","/**\n * 运行时脚本执行请求。\n *\n * Hook fallback 仅支持表达式风格执行,复杂语句执行优先交给 CDP adapter。\n */\nexport interface RuntimeEvaluateRequest {\n /** 需要执行的表达式。 */\n readonly expression: string\n /** 是否等待 Promise 结果,默认由调用方决定。 */\n readonly awaitPromise?: boolean\n /** 执行超时时间,避免页面长任务阻塞调试链路。 */\n readonly timeoutMs: number\n}\n\n/**\n * 执行表达式风格脚本。\n *\n * 使用 Function 构造器而不是直接 eval,可以明确限定为表达式返回值;\n * 语句级调试留给 CDP Runtime.evaluate,以减少 Hook fallback 的行为边界。\n */\nexport async function evaluateExpression(\n request: RuntimeEvaluateRequest\n): Promise<unknown> {\n const value = runExpression(request.expression)\n const result =\n request.awaitPromise === false ? value : await Promise.resolve(value)\n\n return Promise.race([\n Promise.resolve(result),\n createTimeout(request.timeoutMs)\n ])\n}\n\n/**\n * 执行表达式并返回结果。\n *\n * 这里必须动态执行用户传入表达式,但 MCP 工具默认关闭该能力,只有用户显式配置\n * `runtime.evaluate.enabled` 后才会暴露入口;因此把例外集中在该函数,便于后续安全审查。\n */\nfunction runExpression(expression: string): unknown {\n // eslint-disable-next-line @typescript-eslint/no-implied-eval, @typescript-eslint/no-unsafe-call -- evaluate_script 的职责就是执行显式授权后的调试表达式。\n return new Function(`return (${expression})`)() as unknown\n}\n\n/**\n * 创建执行超时 Promise。\n *\n * 控制台执行必须有硬边界,否则 MCP 调用可能被页面内长任务永久挂起。\n */\nfunction createTimeout(timeoutMs: number): Promise<never> {\n return new Promise((_, reject) => {\n window.setTimeout(() => {\n reject(\n new Error(`evaluate_script timed out after ${String(timeoutMs)}ms`)\n )\n }, timeoutMs)\n })\n}\n","import type {\n RuntimeStorageRequest,\n RuntimeStorageResult,\n StorageScope\n} from '../types'\n\n/**\n * Runtime 存储桥接负责访问页面同源存储。\n *\n * 该文件只封装浏览器公开 Web API;Cookie 仅覆盖 document.cookie 可见的同源非 HttpOnly 值,\n * 浏览器级 Cookie 和 HttpOnly 查询仍必须交给 CDP。\n */\n\n/** Runtime 存储桥接运行环境,测试可注入内存实现,浏览器端注入真实 window。 */\nexport interface RuntimeStorageEnvironment {\n /** 当前页面 origin,用于拒绝跨源误操作。 */\n readonly origin: string\n /** 当前页面同源 localStorage。 */\n readonly localStorage: Storage\n /** 当前页面同源 sessionStorage。 */\n readonly sessionStorage: Storage\n /** 当前页面同源 IndexedDB 工厂。 */\n readonly indexedDB?: Pick<IDBFactory, 'databases' | 'open'> | MemoryIndexedDb\n /** 当前页面 document.cookie 访问器,测试可注入内存实现。 */\n readonly cookie?: RuntimeCookieAccess\n}\n\n/** Runtime 存储桥接服务,暴露给 Vite RPC 的浏览器侧实现复用。 */\nexport interface RuntimeStorageBridge {\n /** 根据固定动作访问同源存储,所有错误都会被收敛成结构化结果。 */\n manageStorage(request: RuntimeStorageRequest): Promise<RuntimeStorageResult>\n}\n\n/** Runtime Cookie 访问器,保留 document.cookie 的 getter/setter 语义以便测试替换。 */\nexport interface RuntimeCookieAccess {\n /** 读取当前页面可见 Cookie 字符串。 */\n get(): string\n /** 写入一条 document.cookie 指令。 */\n set(value: string): void\n}\n\n/** 测试用内存 IndexedDB 形态,避免单元测试依赖真实浏览器事务实现。 */\nexport interface MemoryIndexedDb {\n readonly stores: Map<string, Map<string, unknown>>\n databases(): Promise<Array<{ readonly name: string | null; readonly version: number }>>\n}\n\n/**\n * 创建 Runtime 存储桥接。\n *\n * 参数化环境让单元测试无需真实浏览器,也能验证同源限制和 Web Storage 读写删边界。\n */\nexport function createRuntimeStorageBridge(\n env: RuntimeStorageEnvironment\n): RuntimeStorageBridge {\n return {\n async manageStorage(request) {\n try {\n return await manageRuntimeStorage(env, request)\n } catch (error) {\n return createRuntimeStorageError(\n request,\n error instanceof Error ? error.message : String(error)\n )\n }\n }\n }\n}\n\nasync function manageRuntimeStorage(\n env: RuntimeStorageEnvironment,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (request.origin !== env.origin) {\n return createRuntimeStorageError(\n request,\n 'Runtime storage access is limited to the current page origin'\n )\n }\n\n if (request.scope === 'cookie') {\n return manageRuntimeCookie(env, request)\n }\n\n if (request.scope === 'indexedDB') {\n return manageRuntimeIndexedDb(env, request)\n }\n\n return manageRuntimeWebStorage(getWebStorage(env, request.scope), request)\n}\n\nfunction manageRuntimeCookie(\n env: RuntimeStorageEnvironment,\n request: RuntimeStorageRequest\n): RuntimeStorageResult {\n if (!env.cookie) {\n return createRuntimeStorageError(\n request,\n 'Runtime cookie access is unavailable',\n ['document.cookie is not available in this runtime environment']\n )\n }\n\n if (request.action === 'list') {\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n cookies: readRuntimeCookies(env.cookie)\n })\n }\n\n if (request.action === 'get') {\n assertCookieName(request)\n\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n cookies: readRuntimeCookies(env.cookie).filter(\n (cookie) => cookie.name === request.cookie.name\n )\n })\n }\n\n if (request.action === 'set') {\n assertCookieName(request)\n env.cookie.set(createRuntimeCookieWrite(request))\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'delete') {\n assertCookieName(request)\n env.cookie.set(createRuntimeCookieDelete(request))\n\n return createRuntimeStorageSuccess(request, {\n deletedCount: 1,\n skippedHttpOnlyCount: 0,\n limitations: ['HttpOnly cookies are invisible to runtime cookie access']\n })\n }\n\n const cookies = readRuntimeCookies(env.cookie)\n\n for (const cookie of cookies) {\n env.cookie.set(\n createRuntimeCookieDelete({\n ...request,\n cookie: {\n name: cookie.name,\n path: request.cookie?.path\n }\n })\n )\n }\n\n return createRuntimeStorageSuccess(request, {\n deletedCount: cookies.length,\n skippedHttpOnlyCount: 0,\n limitations: ['HttpOnly cookies are invisible to runtime cookie access']\n })\n}\n\nfunction getWebStorage(\n env: RuntimeStorageEnvironment,\n scope: StorageScope\n): Storage {\n return scope === 'sessionStorage' ? env.sessionStorage : env.localStorage\n}\n\nfunction manageRuntimeWebStorage(\n storage: Storage,\n request: RuntimeStorageRequest\n): RuntimeStorageResult {\n if (request.action === 'list') {\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n scope: request.scope,\n entries: readStorageEntries(storage)\n })\n }\n\n if (request.action === 'get') {\n assertStorageKey(request)\n\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n scope: request.scope,\n key: request.key,\n value: storage.getItem(request.key)\n })\n }\n\n if (request.action === 'set') {\n assertStorageKey(request)\n storage.setItem(request.key, request.value ?? '')\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n storage.removeItem(request.key)\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n storage.clear()\n\n return createRuntimeStorageSuccess(request, { ok: true })\n}\n\nasync function manageRuntimeIndexedDb(\n env: RuntimeStorageEnvironment,\n request: RuntimeStorageRequest\n): Promise<RuntimeStorageResult> {\n if (!env.indexedDB?.databases) {\n return createRuntimeStorageError(request, 'IndexedDB metadata API is unavailable')\n }\n\n if (request.action === 'list') {\n const databases = await env.indexedDB.databases()\n\n return createRuntimeStorageSuccess(request, {\n origin: request.origin,\n scope: request.scope,\n databases: databases.map((database) => ({\n name: database.name,\n version: database.version\n }))\n })\n }\n\n assertIndexedDbTarget(request)\n\n if ('stores' in env.indexedDB) {\n return manageMemoryIndexedDb(env.indexedDB, request)\n }\n\n return manageBrowserIndexedDb(env.indexedDB, request)\n}\n\nfunction manageMemoryIndexedDb(\n indexedDB: MemoryIndexedDb,\n request: RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n }\n): RuntimeStorageResult {\n const storeId = `${request.databaseName}:${request.objectStoreName}`\n const store = indexedDB.stores.get(storeId) ?? new Map<string, unknown>()\n indexedDB.stores.set(storeId, store)\n\n if (request.action === 'get') {\n assertStorageKey(request)\n\n return createRuntimeStorageSuccess(request, {\n key: request.key,\n value: store.get(request.key) ?? null\n })\n }\n\n if (request.action === 'set') {\n assertStorageKey(request)\n store.set(request.key, parseIndexedDbValue(request.value))\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n store.delete(request.key)\n\n return createRuntimeStorageSuccess(request, { ok: true })\n }\n\n store.clear()\n\n return createRuntimeStorageSuccess(request, { ok: true })\n}\n\nasync function manageBrowserIndexedDb(\n indexedDB: Pick<IDBFactory, 'open'>,\n request: RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n }\n): Promise<RuntimeStorageResult> {\n const database = await openIndexedDbForRequest(indexedDB, request)\n\n try {\n return await executeIndexedDbTransaction(database, request)\n } finally {\n database.close()\n }\n}\n\nfunction openIndexedDb(\n indexedDB: Pick<IDBFactory, 'open'>,\n databaseName: string\n): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(databaseName)\n request.onerror = () => {\n reject(request.error ?? new Error('IndexedDB open failed'))\n }\n request.onsuccess = () => {\n resolve(request.result)\n }\n })\n}\n\n/**\n * 按操作意图打开 IndexedDB。\n *\n * 浏览器原生 IndexedDB 只能在版本升级阶段创建 object store;set 操作代表明确写入意图,\n * 因此允许自动升版本建 store,避免 MCP 使用方必须先写一段页面脚本初始化数据库。\n */\nasync function openIndexedDbForRequest(\n indexedDB: Pick<IDBFactory, 'open'>,\n request: RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n }\n): Promise<IDBDatabase> {\n const database = await openIndexedDb(indexedDB, request.databaseName)\n\n if (\n request.action !== 'set' ||\n database.objectStoreNames.contains(request.objectStoreName)\n ) {\n return database\n }\n\n const version = database.version + 1\n database.close()\n\n return openIndexedDbWithStore(indexedDB, {\n databaseName: request.databaseName,\n objectStoreName: request.objectStoreName,\n version\n })\n}\n\n/**\n * 升级 IndexedDB 并创建缺失的 object store。\n *\n * 该函数只服务 set 的自动初始化场景;读、删、清仍要求目标 store 已存在,以便暴露错误而不是\n * 静默创建空库造成误判。\n */\nfunction openIndexedDbWithStore(\n indexedDB: Pick<IDBFactory, 'open'>,\n options: {\n readonly databaseName: string\n readonly objectStoreName: string\n readonly version: number\n }\n): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(options.databaseName, options.version)\n request.onupgradeneeded = () => {\n const database = request.result\n\n if (!database.objectStoreNames.contains(options.objectStoreName)) {\n database.createObjectStore(options.objectStoreName)\n }\n }\n request.onerror = () => {\n reject(request.error ?? new Error('IndexedDB upgrade failed'))\n }\n request.onsuccess = () => {\n resolve(request.result)\n }\n })\n}\n\nfunction executeIndexedDbTransaction(\n database: IDBDatabase,\n request: RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n }\n): Promise<RuntimeStorageResult> {\n return new Promise((resolve, reject) => {\n const mode = request.action === 'get' ? 'readonly' : 'readwrite'\n const transaction = database.transaction(request.objectStoreName, mode)\n const store = transaction.objectStore(request.objectStoreName)\n\n transaction.onerror = () => {\n reject(transaction.error ?? new Error('IndexedDB transaction failed'))\n }\n\n if (request.action === 'get') {\n assertStorageKey(request)\n const getRequest = store.get(request.key)\n getRequest.onerror = () => {\n reject(getRequest.error ?? new Error('IndexedDB get failed'))\n }\n getRequest.onsuccess = () => {\n const value: unknown = getRequest.result ?? null\n resolve(\n createRuntimeStorageSuccess(request, {\n key: request.key,\n value\n })\n )\n }\n return\n }\n\n if (request.action === 'set') {\n assertStorageKey(request)\n store.put(parseIndexedDbValue(request.value), request.key)\n transaction.oncomplete = () => {\n resolve(createRuntimeStorageSuccess(request, { ok: true }))\n }\n return\n }\n\n if (request.action === 'delete') {\n assertStorageKey(request)\n store.delete(request.key)\n transaction.oncomplete = () => {\n resolve(createRuntimeStorageSuccess(request, { ok: true }))\n }\n return\n }\n\n store.clear()\n transaction.oncomplete = () => {\n resolve(createRuntimeStorageSuccess(request, { ok: true }))\n }\n })\n}\n\nfunction readStorageEntries(storage: Storage): Array<{\n readonly key: string\n readonly value: string\n}> {\n const entries: Array<{ key: string; value: string }> = []\n\n for (let index = 0; index < storage.length; index += 1) {\n const key = storage.key(index)\n\n if (!key) {\n continue\n }\n\n const value = storage.getItem(key)\n\n if (value === null) {\n continue\n }\n\n entries.push({ key, value })\n }\n\n return entries\n}\n\nfunction readRuntimeCookies(cookieAccess: RuntimeCookieAccess): Array<{\n readonly name: string\n readonly value: string\n}> {\n return cookieAccess\n .get()\n .split(';')\n .map((item) => item.trim())\n .filter(Boolean)\n .map((item) => {\n const separatorIndex = item.indexOf('=')\n\n if (separatorIndex === -1) {\n return { name: decodeCookiePart(item), value: '' }\n }\n\n return {\n name: decodeCookiePart(item.slice(0, separatorIndex)),\n value: decodeCookiePart(item.slice(separatorIndex + 1))\n }\n })\n}\n\nfunction createRuntimeCookieWrite(request: RuntimeStorageRequest & {\n readonly cookie: NonNullable<RuntimeStorageRequest['cookie']>\n}): string {\n const value = request.cookie.value ?? request.value ?? ''\n const parts = [\n `${encodeURIComponent(request.cookie.name)}=${encodeURIComponent(value)}`\n ]\n\n appendRuntimeCookieAttributes(parts, request.cookie)\n\n return parts.join('; ')\n}\n\nfunction createRuntimeCookieDelete(request: RuntimeStorageRequest & {\n readonly cookie: NonNullable<RuntimeStorageRequest['cookie']>\n}): string {\n const parts = [\n `${encodeURIComponent(request.cookie.name)}=`,\n 'Expires=Thu, 01 Jan 1970 00:00:00 GMT',\n 'Max-Age=0'\n ]\n\n appendRuntimeCookieAttributes(parts, {\n path: request.cookie.path,\n domain: request.cookie.domain\n })\n\n return parts.join('; ')\n}\n\nfunction appendRuntimeCookieAttributes(\n parts: string[],\n cookie: Partial<NonNullable<RuntimeStorageRequest['cookie']>>\n): void {\n if (cookie.path) {\n parts.push(`Path=${cookie.path}`)\n }\n\n if (cookie.domain) {\n parts.push(`Domain=${cookie.domain}`)\n }\n\n if (cookie.expires !== undefined) {\n parts.push(`Expires=${new Date(cookie.expires * 1000).toUTCString()}`)\n }\n\n if (cookie.sameSite) {\n parts.push(`SameSite=${normalizeRuntimeSameSite(cookie.sameSite)}`)\n }\n\n if (cookie.secure) {\n parts.push('Secure')\n }\n}\n\nfunction normalizeRuntimeSameSite(\n sameSite: 'strict' | 'lax' | 'none'\n): 'Strict' | 'Lax' | 'None' {\n if (sameSite === 'strict') {\n return 'Strict'\n }\n\n if (sameSite === 'lax') {\n return 'Lax'\n }\n\n return 'None'\n}\n\nfunction decodeCookiePart(value: string): string {\n try {\n return decodeURIComponent(value)\n } catch {\n return value\n }\n}\n\nfunction assertStorageKey(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & { readonly key: string } {\n if (!request.key) {\n throw new Error('Storage key is required for this operation')\n }\n}\n\nfunction assertCookieName(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & {\n readonly cookie: NonNullable<RuntimeStorageRequest['cookie']>\n} {\n if (!request.cookie?.name) {\n throw new Error('Cookie name is required for this operation')\n }\n}\n\nfunction assertIndexedDbTarget(\n request: RuntimeStorageRequest\n): asserts request is RuntimeStorageRequest & {\n readonly databaseName: string\n readonly objectStoreName: string\n} {\n if (!request.databaseName || !request.objectStoreName) {\n throw new Error('IndexedDB databaseName and objectStoreName are required')\n }\n}\n\nfunction parseIndexedDbValue(value?: string): unknown {\n if (value === undefined) {\n return null\n }\n\n try {\n return JSON.parse(value) as unknown\n } catch {\n return value\n }\n}\n\nfunction createRuntimeStorageSuccess(\n request: RuntimeStorageRequest,\n data: unknown\n): RuntimeStorageResult {\n return {\n ok: true,\n source: 'hook',\n action: request.action,\n scope: request.scope,\n data\n }\n}\n\nfunction createRuntimeStorageError(\n request: RuntimeStorageRequest,\n error: string,\n limitations?: string[]\n): RuntimeStorageResult {\n return {\n ok: false,\n source: 'hook',\n action: request.action,\n scope: request.scope,\n error,\n limitations\n }\n}\n","import type { VueRuntimeRpc } from '../types'\nimport { createDomSnapshot, queryDomElements } from './domSnapshot'\nimport { getElementContextResolver } from './elementContext'\nimport { evaluateExpression } from './evaluateExpression'\nimport { takeRuntimeScreenshot } from './screenshot'\nimport { createRuntimeStorageBridge } from './storageBridge'\n\n/**\n * 创建通用 Runtime DevTools RPC。\n *\n * 这些能力是 CDP 不可用时的 Hook fallback,和 Vue 专属能力放在同一条 Vite RPC 通道里,\n * 可以避免再维护第二套浏览器到服务端的请求协议。\n */\nexport function createRuntimeDevtoolsRpc(\n getRpc: () => VueRuntimeRpc\n): Pick<\n VueRuntimeRpc,\n | 'getDomTree'\n | 'onDomTreeUpdated'\n | 'queryDom'\n | 'onDomQueryUpdated'\n | 'getElementContext'\n | 'onElementContextUpdated'\n | 'reloadPage'\n | 'onPageReloaded'\n | 'evaluateScript'\n | 'onEvaluateScriptUpdated'\n | 'takeScreenshot'\n | 'onScreenshotTaken'\n | 'manageStorage'\n | 'onStorageUpdated'\n> {\n return {\n getDomTree(options) {\n getRpc().onDomTreeUpdated(\n options.event,\n createDomSnapshot(document.documentElement, {\n maxDepth: options.maxDepth,\n maxNodes: options.maxNodes,\n maxTextLength: options.maxTextLength\n })\n )\n },\n onDomTreeUpdated: () => undefined,\n queryDom(options) {\n getRpc().onDomQueryUpdated(\n options.event,\n queryDomElements(options.selector, options.limit)\n )\n },\n onDomQueryUpdated: () => undefined,\n getElementContext(options) {\n try {\n getRpc().onElementContextUpdated(\n options.event,\n getElementContextResolver().getElementContext(options.elementId)\n )\n } catch (error) {\n getRpc().onElementContextUpdated(options.event, {\n ok: false,\n elementId: options.elementId,\n error: error instanceof Error ? error.message : String(error),\n limitations: ['runtime element context lookup failed']\n })\n }\n },\n onElementContextUpdated: () => undefined,\n reloadPage(options) {\n getRpc().onPageReloaded(options.event, { ok: true, source: 'hook' })\n setTimeout(() => {\n window.location.reload()\n }, 0)\n },\n onPageReloaded: () => undefined,\n async evaluateScript(options) {\n try {\n getRpc().onEvaluateScriptUpdated(options.event, {\n ok: true,\n value: await evaluateExpression(options)\n })\n } catch (error) {\n getRpc().onEvaluateScriptUpdated(options.event, {\n ok: false,\n error: error instanceof Error ? error.message : String(error)\n })\n }\n },\n onEvaluateScriptUpdated: () => undefined,\n async takeScreenshot(options) {\n try {\n getRpc().onScreenshotTaken(\n options.event,\n await takeRuntimeScreenshot(options)\n )\n } catch (error) {\n getRpc().onScreenshotTaken(options.event, {\n ok: false,\n error: error instanceof Error ? error.message : String(error)\n })\n }\n },\n onScreenshotTaken: () => undefined,\n async manageStorage(options) {\n const bridge = createRuntimeStorageBridge({\n origin: window.location.origin,\n localStorage: window.localStorage,\n sessionStorage: window.sessionStorage,\n indexedDB: window.indexedDB,\n cookie: {\n get: () => window.document.cookie,\n set: (value) => {\n window.document.cookie = value\n }\n }\n })\n getRpc().onStorageUpdated(\n options.event,\n await bridge.manageStorage(options)\n )\n },\n onStorageUpdated: () => undefined\n }\n}\n"],"mappings":";AAKA,SAAS,wBAAwB;;;ACG1B,IAAM,wBAAwB;AAG9B,IAAM,wBAAwB;AAG9B,IAAM,8BAA8B;AAGpC,IAAM,8BAA8B;AAGpC,IAAM,8BAA8B;AAGpC,IAAM,gCAAgC;AAOtC,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF;;;AClBO,IAAM,mBAAmB;AAGzB,IAAM,+BAA+B,IAAI,OAAO;AAGhD,IAAM,8BAA8B;AAGpC,IAAM,+BAA+B;AAMrC,IAAM,sCAAsC;AAG5C,IAAM,yCAAyC;AAG/C,IAAM,6CAA6C;AAoCnD,IAAM,qBAAqB;AAG3B,IAAM,8BAA8B,KAAK,kBAAkB;AAG3D,IAAM,+BACX;AAGK,IAAM,wCAAwC,KAAK,4BAA4B;AAG/E,IAAM,4BACX;AAGK,IAAM,qCAAqC,KAAK,yBAAyB;AAGzE,IAAM,iCAAiC;AAUvC,IAAM,+BACX;AAGK,IAAM,kCACX;AAGK,IAAM,+BACX;AAGK,IAAM,6CAA6C;AASnD,IAAM,2CAA2C;AAGjD,IAAM,kBAA6C;AAAA,EACxD,SAAS;AAAA,EACT,MAAM;AAAA,EACN,UAAU;AAAA,EACV,qBAAqB;AAAA,IACnB,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA,YAAY;AAAA,IACV,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,YAAY;AAAA,EACd;AAAA,EACA,OAAO;AAAA,IACL,YAAY;AAAA,EACd;AAAA,EACA,eAAe;AAAA,IACb,SAAS;AAAA,IACT,UAAU;AAAA,MACR,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,IACA,iBAAiB;AAAA,EACnB;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,UAAU;AAAA,MACR,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,KAAK,CAAC;AAAA,EACN,SAAS;AAAA,IACP,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,oBAAoB;AAAA,IACpB,qBAAqB;AAAA,IACrB,aAAa;AAAA,IACb,aAAa,CAAC,GAAG,oBAAoB;AAAA,EACvC;AAAA,EACA,KAAK;AAAA,IACH,UAAU;AAAA,IACV,UAAU;AAAA,IACV,eAAe;AAAA,EACjB;AAAA,EACA,SAAS;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA,YAAY;AAAA,IACV,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,MACP,SAAS,CAAC;AAAA,MACV,SAAS,CAAC;AAAA,IACZ;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,SAAS;AAAA,IACT,QAAQ;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA,IACX;AAAA,EACF;AACF;;;AC1MA,SAAS,cAAc;;;ACKhB,SAAS,cAAc,OAAwB;AACpD,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,oBAAI,QAAQ;AAEzB,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,CAAC,MAAc,YAA8B;AAC3C,UAAI,OAAO,YAAY,YAAY,YAAY,MAAM;AACnD,eAAO;AAAA,MACT;AAEA,UAAI,KAAK,IAAI,OAAO,GAAG;AACrB,eAAO;AAAA,MACT;AAEA,WAAK,IAAI,OAAO;AAChB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;ADRO,SAAS,mBAAmB,SAAyC;AAC1E,QAAM,kBAAkB;AAAA,IACtB,KAAK,QAAQ;AAAA,IACb,MAAM,QAAQ;AAAA,IACd,MAAM,QAAQ;AAAA,IACd,OAAO,QAAQ;AAAA,IACf,OAAO,QAAQ;AAAA,EACjB;AAEA,QAAM,OAAO,CAAC,OAA+B,SAA0B;AACrE,UAAM,iBAAiB,qBAAqB,IAAI;AAEhD,YAAQ,KAAK;AAAA,MACX,IAAI,OAAO;AAAA,MACX,QAAQ,QAAQ;AAAA,MAChB,QAAQ;AAAA,MACR;AAAA,MACA,SAAS,eAAe,KAAK,GAAG;AAAA,MAChC,MAAM;AAAA,MACN,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAEC,EAAC,CAAC,OAAO,QAAQ,QAAQ,SAAS,OAAO,EAAY,QAAQ,CAAC,UAAU;AACvE,YAAQ,KAAK,IAAI,IAAI,SAAoB;AACvC,WAAK,OAAO,IAAI;AAChB,sBAAgB,KAAK,EAAE,GAAG,IAAI;AAAA,IAChC;AAAA,EACF,CAAC;AAED,QAAM,UAAU,CAAC,UAA4B;AAC3C,YAAQ,KAAK;AAAA,MACX,IAAI,OAAO;AAAA,MACX,QAAQ,QAAQ;AAAA,MAChB,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,SAAS,MAAM;AAAA,MACf,OAAO,MAAM,iBAAiB,QAAQ,MAAM,MAAM,QAAQ;AAAA,MAC1D,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAEA,SAAO,iBAAiB,SAAS,OAAO;AAExC,SAAO,MAAM;AACX,WAAO,OAAO,SAAS,eAAe;AACtC,WAAO,oBAAoB,SAAS,OAAO;AAAA,EAC7C;AACF;AAQA,SAAS,qBAAqB,MAA2B;AACvD,SAAO,KAAK,IAAI,CAAC,QAAQ,cAAc,GAAG,CAAC;AAC7C;;;AExEA,SAAS,UAAAA,eAAc;AAEvB,IAAM,4BAA4B;AAClC,IAAM,0BAA0B;AA6BzB,IAAM,yBAAyB,6BAA6B;AAO5D,SAAS,yBAAiC;AAC/C,SAAO,GAAG,yBAAyB,GAAGA,QAAO,uBAAuB,CAAC;AACvE;AAOO,SAAS,+BAAuD;AACrE,QAAM,UAAU,oBAAI,IAAkC;AAEtD,SAAO;AAAA,IACL,SAAS,SAAS;AAChB,YAAM,YAAY,uBAAuB;AACzC,cAAQ,IAAI,WAAW;AAAA,QACrB;AAAA,QACA;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,IAAI,WAAW;AACb,aAAO,QAAQ,IAAI,SAAS;AAAA,IAC9B;AAAA,IACA,QAAQ;AACN,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AACF;;;AChEA,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AACxB,IAAM,qBAAqB;AAC3B,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AAQf,SAAS,qBAAqB,SAI5B;AACP,MAAI,CAAC,QAAQ,SAAS;AACpB;AAAA,EACF;AAEA,QAAM,WAAW;AACjB,QAAM,UAAU,cAAc;AAC9B,MAAI,SAAS;AACb,MAAI;AAEJ,SAAO,iBAAiB,WAAW,CAAC,UAAU;AAC5C,aAAS,gBAAgB,OAAO,QAAQ,QAAQ;AAAA,EAClD,CAAC;AACD,SAAO,iBAAiB,SAAS,MAAM;AACrC,aAAS;AACT,qBAAiB;AACjB,kBAAc,OAAO;AAAA,EACvB,CAAC;AACD,SAAO,iBAAiB,aAAa,CAAC,UAAU;AAC9C,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,qBAAiB,SAAS,iBAAiB,MAAM,SAAS,MAAM,OAAO,KAClE;AACL,kBAAc,SAAS,cAAc;AAAA,EACvC,CAAC;AACD,SAAO;AAAA,IACL;AAAA,IACA,CAAC,UAAU;AACT,UAAI,CAAC,UAAU,CAAC,cAAc,MAAM,MAAM,GAAG;AAC3C;AAAA,MACF;AAEA,YAAM,eAAe;AACrB,YAAM,gBAAgB;AAEtB,WAAK,cAAc,MAAM,QAAQ,UAAU,QAAQ,eAAe;AAAA,IACpE;AAAA,IACA;AAAA,EACF;AACF;AAOA,SAAS,gBACP,OACA,UACS;AACT,SACE,MAAM,WAAW,SAAS,UAC1B,MAAM,aAAa,SAAS,YAC5B,MAAM,YAAY,SAAS,WAC3B,MAAM,YAAY,SAAS;AAE/B;AAOA,SAAS,iBACP,SACA,UACQ;AACR,SAAO,QAAQ,aAAa,WAAW,KAAK,SAAS,SAAS,OAAO;AACvE;AAOA,eAAe,cACb,SACA,UACA,iBACe;AACf,QAAM,YAAY,iBAAiB,SAAS,QAAQ;AACpD,QAAM,SAAS,MAAM,cAAc,SAAS;AAE5C;AAAA,IACE,SAAS,kBAAkB,GAAG,kBAAkB,KAAK,SAAS;AAAA,IAC9D;AAAA,EACF;AACF;AAOA,eAAe,cAAc,WAAqC;AAChE,MAAI;AACF,UAAM,UAAU,UAAU,UAAU,SAAS;AAC7C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,SAAS,gBAA6B;AACpC,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,sBAAoB,OAAO;AAC3B,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC3B,UAAU;AAAA,IACV,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,SAAS;AAAA,EACX,CAAC;AACD,WAAS,KAAK,YAAY,OAAO;AACjC,SAAO;AACT;AAOA,SAAS,cAAc,SAAsB,SAAyB;AACpE,MAAI,CAAC,WAAW,eAAe,SAAS,aAAa,MAAM,QAAQ;AACjE,YAAQ,MAAM,UAAU;AACxB;AAAA,EACF;AAEA,QAAM,OAAO,QAAQ,sBAAsB;AAC3C,SAAO,OAAO,QAAQ,OAAO;AAAA,IAC3B,SAAS;AAAA,IACT,MAAM,GAAG,OAAO,KAAK,CAAC,CAAC;AAAA,IACvB,KAAK,GAAG,OAAO,KAAK,CAAC,CAAC;AAAA,IACtB,OAAO,GAAG,OAAO,KAAK,KAAK,CAAC;AAAA,IAC5B,QAAQ,GAAG,OAAO,KAAK,MAAM,CAAC;AAAA,EAChC,CAAC;AACH;AAOA,SAAS,UAAU,SAAiB,YAA0B;AAC5D,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,sBAAoB,KAAK;AACzB,QAAM,cAAc;AACpB,SAAO,OAAO,MAAM,OAAO;AAAA,IACzB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,eAAe;AAAA,EACjB,CAAC;AACD,WAAS,KAAK,YAAY,KAAK;AAC/B,aAAW,WAAW,MAAM;AAC1B,UAAM,OAAO;AAAA,EACf,GAAG,UAAU;AACf;AAOA,SAAS,cAAc,OAA6C;AAClE,SAAO;AAAA,IACL,SACE,OAAO,UAAU,YACjB,kBAAkB,SAClB,2BAA2B;AAAA,EAC/B;AACF;AAOA,SAAS,oBAAoB,SAA4B;AACvD,MAAI,OAAO,QAAQ,iBAAiB,YAAY;AAC9C,YAAQ,aAAa,eAAe,MAAM;AAAA,EAC5C;AAEA,UAAQ,QAAQ,eAAe;AACjC;AAOA,SAAS,eAAe,SAAkB,MAA6B;AACrE,MAAI,OAAO,QAAQ,iBAAiB,YAAY;AAC9C,WAAO,QAAQ,aAAa,IAAI;AAAA,EAClC;AAEA,SAAO;AACT;;;ACzOA,IAAM,4BAA4B;AAClC,IAAM,qBAAqB;AAC3B,IAAM,oBAAoB;AAuCnB,SAAS,eAAe,WAAoC;AACjE,QAAM,cAAc,0BAA0B,KAAK,SAAS;AAE5D,MAAI,aAAa;AACf,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,MAAM,YAAY,CAAC;AAAA,MACnB,MAAM,OAAO,YAAY,CAAC,CAAC;AAAA,MAC3B,QAAQ,OAAO,YAAY,CAAC,CAAC;AAAA,IAC/B;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,iBAAiB,GAAG;AAC3C,WAAO,sBAAsB,SAAS;AAAA,EACxC;AAEA,QAAM,eAAe,mBAAmB,KAAK,SAAS;AAEtD,MAAI,cAAc;AAChB,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,WAAW,aAAa,CAAC;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,QAAQ;AAAA,EACV;AACF;AAQA,SAAS,sBAAsB,WAAoC;AACjE,QAAM,QAAQ,UAAU,MAAM,kBAAkB,MAAM;AACtD,QAAM,QAAQ,MAAM,MAAM,GAAG,EAAE,OAAO,OAAO;AAE7C,MAAI,MAAM,SAAS,GAAG;AACpB,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,CAAC,GAAG,WAAW,GAAG;AACvC,QAAM,cAAc,SAAS,MAAM,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC;AAClE,QAAM,YAAY,MAAM,MAAM,SAAS,IAAI,CAAC,EAAE,KAAK,GAAG;AAEtD,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACnGO,SAAS,aAAa,MAAc,WAAkC;AAC3E,MAAI,KAAK,UAAU,WAAW;AAC5B,WAAO,EAAE,MAAM,WAAW,OAAO,gBAAgB,KAAK,OAAO;AAAA,EAC/D;AAEA,SAAO;AAAA,IACL,MAAM,KAAK,MAAM,GAAG,SAAS;AAAA,IAC7B,WAAW;AAAA,IACX,gBAAgB,KAAK;AAAA,EACvB;AACF;AAOO,SAAS,YACd,UAAkC,CAAC,GACnC,YAA+B,CAAC,GACR;AACxB,QAAM,sBAAsB,IAAI;AAAA,IAC9B,UAAU,IAAI,CAAC,SAAS,KAAK,YAAY,CAAC;AAAA,EAC5C;AAEA,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,OAAO,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;AAAA,MAC7C;AAAA,MACA,oBAAoB,IAAI,KAAK,YAAY,CAAC,IAAI,aAAa;AAAA,IAC7D,CAAC;AAAA,EACH;AACF;;;ACHO,SAAS,kBACd,MACA,SACiB;AACjB,MAAI,QAAQ;AAOZ,WAAS,MAAM,MAAY,OAAuC;AAChE,QAAI,SAAS,QAAQ,YAAY,QAAQ,QAAQ,UAAU;AACzD,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,aAAa,KAAK,WAAW;AACpC,aAAO,mBAAmB,MAAM,SAAS,MAAM;AAC7C,iBAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,QAAI,EAAE,gBAAgB,UAAU;AAC9B,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,QAAQ,YAAY;AAErC,QAAI,CAAC,UAAU,SAAS,UAAU,EAAE,SAAS,GAAG,KAAK,qBAAqB,IAAI,GAAG;AAC/E,aAAO;AAAA,IACT;AAEA,aAAS;AAET,WAAO,sBAAsB,MAAM,KAAK,CAAC,UAAU,MAAM,OAAO,QAAQ,CAAC,CAAC;AAAA,EAC5E;AAEA,SAAO,MAAM,MAAM,CAAC,KAAK,EAAE,KAAK,KAAK,QAAQ,YAAY,EAAE;AAC7D;AAOO,SAAS,iBACd,UACA,OACyB;AACzB,SAAO,MAAM,KAAK,SAAS,iBAAiB,QAAQ,CAAC,EAClD,OAAO,CAAC,YAAY,CAAC,qBAAqB,OAAO,CAAC,EAClD,MAAM,GAAG,KAAK,EACd,IAAI,CAAC,YAAY,wBAAwB,OAAO,CAAC;AACtD;AAOO,SAAS,wBAAwB,SAAqC;AAC3E,SAAO;AAAA,IACL,KAAK,QAAQ,QAAQ,YAAY;AAAA,IACjC,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,OAAO,aAAa,OAAO;AAAA,IAC3B,MAAM,cAAc,QAAQ,sBAAsB,CAAC;AAAA,EACrD;AACF;AAOA,SAAS,mBACP,MACA,SACA,aACwB;AACxB,QAAM,OAAO,KAAK,aAAa,KAAK;AAEpC,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,cAAY;AAEZ,SAAO,EAAE,KAAK,SAAS,MAAM,aAAa,MAAM,QAAQ,aAAa,EAAE,KAAK;AAC9E;AAOA,SAAS,sBACP,MACA,KACA,YACiB;AACjB,QAAM,QAAQ,aAAa,IAAI;AAC/B,QAAM,WAAW,MAAM,KAAK,KAAK,UAAU,EACxC,IAAI,CAAC,UAAU,WAAW,KAAK,CAAC,EAChC,OAAO,CAAC,UAAoC,QAAQ,KAAK,CAAC;AAE7D,SAAO;AAAA,IACL;AAAA,IACA,GAAI,KAAK,YAAY,KAAK,IAAI,EAAE,MAAM,KAAK,YAAY,KAAK,EAAE,IAAI,CAAC;AAAA,IACnE,GAAI,OAAO,KAAK,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAAA,IAC7C,GAAI,SAAS,SAAS,EAAE,SAAS,IAAI,CAAC;AAAA,EACxC;AACF;AAOO,SAAS,aAAa,SAA0C;AACrE,QAAM,QAAgC,CAAC;AAEvC,aAAW,QAAQ,MAAM,KAAK,QAAQ,UAAU,GAAG;AACjD,UAAM,KAAK,IAAI,IAAI,KAAK;AAAA,EAC1B;AAEA,MACE,OAAO,qBAAqB,eAC5B,mBAAmB,oBACnB,QAAQ,SAAS,YACjB;AACA,UAAM,QAAQ;AAAA,EAChB;AAEA,SAAO;AACT;AAOO,SAAS,cAAc,MAAuC;AACnE,SAAO;AAAA,IACL,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,EACb;AACF;AAOA,SAAS,qBAAqB,SAA2B;AACvD,SAAO,QAAQ,aAAa,qBAAqB,MAAM;AACzD;;;AC3KO,SAAS,6BACd,SACA,MACiC;AACjC,QAAM,YAAY,qBAAqB,OAAO;AAE9C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,iBAAiB,SAAS;AACvC,QAAM,OAAO,iBAAiB,SAAS;AAEvC,MAAI,CAAC,MAAM;AACT,WAAO,EAAE,KAAK;AAAA,EAChB;AAEA,QAAM,kBAAkB,qBAAqB,IAAI;AAEjD,MAAI,iBAAiB;AACnB,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,QAAQ;AAAA,MACN,MAAM,0BAA0B,MAAM,IAAI;AAAA,IAC5C;AAAA,IACA,iBAAiB;AAAA,EACnB;AACF;AAOA,SAAS,qBAAqB,SAAmD;AAC/E,MAAI,UAA0B;AAE9B,SAAO,SAAS;AACd,UAAM,YAAa,QAChB;AAEH,QAAI,sBAAsB,SAAS,GAAG;AACpC,aAAO;AAAA,IACT;AAEA,cAAU,QAAQ;AAAA,EACpB;AAEA,SAAO;AACT;AAOA,SAAS,iBAAiB,WAAoD;AAC5E,SACE,UAAU,MAAM,QAChB,UAAU,MAAM,UAChB,UAAU,MAAM;AAEpB;AAOA,SAAS,iBAAiB,WAAoD;AAC5E,SAAO,UAAU,MAAM;AACzB;AAOA,SAAS,qBACP,MACoD;AACpD,QAAM,aAAa,cAAc,IAAI;AACrC,QAAM,SAAS;AACf,QAAM,QAAQ,WAAW,YAAY,MAAM;AAE3C,MAAI,QAAQ,GAAG;AACb,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,WAAW,MAAM,QAAQ,OAAO,MAAM,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/E,QAAM,SAAS,MAAM,CAAC,GAAG,WAAW,GAAG;AACvC,QAAM,cAAc,SAAS,MAAM,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC;AAClE,QAAM,YAAY,MAAM,MAAM,SAAS,IAAI,CAAC,EAAE,KAAK,GAAG;AAEtD,MAAI,CAAC,eAAe,CAAC,WAAW;AAC9B,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAOA,SAAS,cAAc,MAAsB;AAC3C,SAAO,KAAK,QAAQ,OAAO,GAAG;AAChC;AAQA,SAAS,0BAA0B,MAAc,MAAsB;AACrE,QAAM,iBAAiB,cAAc,IAAI,EAAE,QAAQ,OAAO,EAAE;AAC5D,QAAM,iBAAiB,cAAc,IAAI;AACzC,QAAM,SAAS,GAAG,cAAc;AAEhC,MAAI,eAAe,WAAW,MAAM,GAAG;AACrC,WAAO,eAAe,MAAM,OAAO,MAAM;AAAA,EAC3C;AAEA,SAAO,eAAe,QAAQ,OAAO,EAAE;AACzC;AAOA,SAAS,sBAAsB,OAA8C;AAC3E,SAAO,QAAQ,SAAS,OAAO,UAAU,YAAY,UAAU,KAAK;AACtE;;;AC1JA,IAAI;AAOG,SAAS,6BACd,SACA;AACA,SAAO;AAAA,IACL,kBAAkB,WAAyC;AACzD,YAAM,SAAS,eAAe,SAAS;AAEvC,UAAI,OAAO,SAAS,kBAAkB;AACpC,cAAM,UAAU,QAAQ;AAAA,UACtB,mBAAmB,eAAe,SAAS,CAAC;AAAA,QAC9C;AAEA,eAAO,2BAA2B,QAAQ,SAAS,QAAQ,IAAI;AAAA,MACjE;AAEA,UAAI,OAAO,SAAS,WAAW;AAC7B,eAAO,qBAAqB,MAAM;AAAA,MACpC;AAEA,UAAI,OAAO,SAAS,WAAW;AAC7B,cAAM,SAAS,QAAQ,SAAS,IAAI,SAAS;AAE7C,YAAI,CAAC,QAAQ;AACX,iBAAO,iCAAiC,SAAS;AAAA,QACnD;AAEA,eAAO,qBAAqB,WAAW,OAAO,SAAS,QAAQ,IAAI;AAAA,MACrE;AAEA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,OAAO;AAAA,QACd;AAAA,QACA,aAAa,CAAC,2DAA2D;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AACF;AAOO,SAAS,0BACd,UACM;AACN,mBAAiB;AACnB;AAOO,SAAS,4BAAoD;AAClE,qBAAmB,6BAA6B;AAAA,IAC9C,MAAM;AAAA,IACN,UAAU;AAAA,IACV,cAAc,UAAU;AACtB,aAAO,SAAS,cAAc,QAAQ;AAAA,IACxC;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAOA,SAAS,2BACP,QACA,SACA,MACsB;AACtB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,WAAW,OAAO;AAAA,IAClB,UAAU;AAAA,IACV,cAAc;AAAA,MACZ,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO;AAAA,IACjB;AAAA,IACA,GAAI,UAAU,EAAE,WAAW,6BAA6B,SAAS,IAAI,EAAE,IAAI,CAAC;AAAA,IAC5E,GAAI,UAAU,EAAE,KAAK,wBAAwB,OAAO,EAAE,IAAI,CAAC;AAAA,IAC3D,aAAa,UAAU,CAAC,IAAI,CAAC,mCAAmC;AAAA,EAClE;AACF;AAOA,SAAS,qBACP,QACsB;AACtB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,WAAW,OAAO;AAAA,IAClB,UAAU;AAAA,IACV,iBAAiB;AAAA,MACf,aAAa,OAAO;AAAA,MACpB,WAAW,OAAO;AAAA,IACpB;AAAA,IACA,aAAa,CAAC,8DAA8D;AAAA,EAC9E;AACF;AAOA,SAAS,qBACP,WACA,SACA,MACsB;AACtB,QAAM,YAAY,6BAA6B,SAAS,IAAI;AAC5D,QAAM,aAAa,WAAW,QAAQ;AAEtC,SAAO;AAAA,IACL,IAAI;AAAA,IACJ;AAAA,IACA,UAAU,QAAQ,UAAU;AAAA,IAC5B,GAAI,aACA,EAAE,cAAc,EAAE,MAAM,YAAY,MAAM,GAAG,QAAQ,EAAE,EAAE,IACzD,CAAC;AAAA,IACL;AAAA,IACA,KAAK,wBAAwB,OAAO;AAAA,IACpC,aAAa,aACT,CAAC,+EAA+E,IAChF,CAAC,4DAA4D;AAAA,EACnE;AACF;AAOA,SAAS,iCAAiC,WAAyC;AACjF,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,IACP;AAAA,IACA,aAAa;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAOA,SAAS,eAAe,OAAuB;AAC7C,QAAM,MAAO,WAEV;AAEH,MAAI,KAAK,QAAQ;AACf,WAAO,IAAI,OAAO,KAAK;AAAA,EACzB;AAEA,SAAO,MAAM,QAAQ,UAAU,MAAM;AACvC;;;AC/MA,SAAS,UAAAC,eAAc;;;ACKhB,SAAS,kBACd,KACmC;AACnC,QAAM,SAAS,IAAI,IAAI,KAAK,uCAAuC;AACnE,QAAM,eAAe,oBAAI,IAA+B;AAExD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,aAAa,QAAQ,GAAG;AACxD,UAAM,WAAW,aAAa,IAAI,GAAG;AAErC,QAAI,aAAa,QAAW;AAC1B,mBAAa,IAAI,KAAK,KAAK;AAC3B;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,eAAS,KAAK,KAAK;AACnB;AAAA,IACF;AAEA,iBAAa,IAAI,KAAK,CAAC,UAAU,KAAK,CAAC;AAAA,EACzC;AAEA,SAAO,OAAO,YAAY,YAAY;AACxC;AAOO,SAAS,gBAAgB,KAAqB;AACnD,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,EAAE;AAAA,EACtB,QAAQ;AACN,WAAO,IAAI,MAAM,GAAG,EAAE,CAAC,KAAK;AAAA,EAC9B;AACF;;;ADOO,SAAS,wBACd,OACe;AACf,SAAO;AAAA,IACL,IAAIC,QAAO;AAAA,IACX,QAAQ,MAAM;AAAA,IACd,QAAQ;AAAA,IACR,KAAK,MAAM;AAAA,IACX,QAAQ,MAAM;AAAA,IACd,gBAAgB,YAAY,MAAM,gBAAgB,MAAM,WAAW;AAAA,IACnE,cAAc,kBAAkB,MAAM,GAAG;AAAA,IACzC,aAAa,MAAM;AAAA,IACnB,WAAW,MAAM;AAAA,EACnB;AACF;AAOO,SAAS,mBAAmB,SAAyC;AAC1E,QAAM,gBAAgB,OAAO,MAAM,KAAK,MAAM;AAC9C,QAAM,qBAAqB,OAAO;AAIlC,QAAM,eAAe,oBAAoB,UAAU;AAEnD,QAAM,eAAe,oBAAoB,UAAU;AAEnD,SAAO,QAAQ,gBAAgB,eAAe,OAAO;AAErD,MAAI,sBAAsB,gBAAgB,cAAc;AACtD,mBAAe,oBAAoB,cAAc,cAAc,OAAO;AAAA,EACxE;AAEA,SAAO,MAAM;AACX,WAAO,QAAQ;AACf,QAAI,sBAAsB,gBAAgB,cAAc;AACtD,yBAAmB,UAAU,OAAO;AACpC,yBAAmB,UAAU,OAAO;AAAA,IACtC;AAAA,EACF;AACF;AAOA,SAAS,gBACP,eACA,SACqB;AACrB,SAAO,OAAO,OAAO,SAAS;AAC5B,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,SAAS,wBAAwB;AAAA,MACrC,QAAQ,QAAQ;AAAA,MAChB,KAAK,YAAY,KAAK;AAAA,MACtB,QAAQ,eAAe,OAAO,IAAI;AAAA,MAClC,gBAAgB;AAAA,QACd,MAAM,YAAY,iBAAiB,UAAU,MAAM,UAAU;AAAA,MAC/D;AAAA,MACA,aAAa,MAAM;AAAA,MACnB,aAAa,QAAQ;AAAA,MACrB;AAAA,IACF,CAAC;AAED,QAAI;AACF,YAAM,WAAW,MAAM,cAAc,OAAO,IAAI;AAChD,YAAM,UAAU,KAAK,IAAI;AACzB,cAAQ,KAAK;AAAA,QACX,GAAG;AAAA,QACH,QAAQ,SAAS;AAAA,QACjB,iBAAiB,gBAAgB,SAAS,OAAO;AAAA,QACjD,cAAc,MAAM,iBAAiB,UAAU,QAAQ,WAAW;AAAA,QAClE;AAAA,QACA,YAAY,UAAU;AAAA,MACxB,CAAC;AACD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,UAAU,KAAK,IAAI;AACzB,cAAQ,KAAK;AAAA,QACX,GAAG;AAAA,QACH,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC5D;AAAA,QACA,YAAY,UAAU;AAAA,MACxB,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAOA,SAAS,eACP,oBACA,cACA,cACA,SACM;AACN,QAAM,SAAS,oBAAI,QAGjB;AAEF,qBAAmB,UAAU,OAAO,SAAS,KAE3C,QACA,KACA,OACA,UACA,UACM;AACN,UAAM,OAAO,CAAC,QAAQ,KAAK,OAAO,UAAU,QAAQ,EAAE;AAAA,MACpD,CAAC,SAAS,SAAS;AAAA,IACrB;AACA,WAAO,IAAI,MAAM,EAAE,QAAQ,KAAK,OAAO,GAAG,GAAG,WAAW,EAAE,CAAC;AAC3D,YAAQ,MAAM,cAAc,MAAM,IAAI;AAAA,EACxC;AAEA,qBAAmB,UAAU,OAAO,SAAS,QAExC,MACG;AACN,UAAM,CAAC,IAAI,IAAI;AACf,UAAM,QAAQ,OAAO,IAAI,IAAI;AAE7B,QAAI,OAAO;AACT,YAAM,YAAY,KAAK,IAAI;AAC3B,YAAM,OAAO;AACb,YAAM,SAAS,wBAAwB;AAAA,QACrC,QAAQ,QAAQ;AAAA,QAChB,KAAK,MAAM;AAAA,QACX,QAAQ,MAAM;AAAA,QACd,aAAa;AAAA,QACb,aAAa,QAAQ;AAAA,QACrB,WAAW,MAAM;AAAA,MACnB,CAAC;AACD,WAAK,iBAAiB,WAAW,MAAM;AACrC,cAAM,UAAU,KAAK,IAAI;AACzB,gBAAQ,KAAK;AAAA,UACX,GAAG;AAAA,UACH,QAAQ,KAAK;AAAA,UACb,iBAAiB,gBAAgB,KAAK,sBAAsB,CAAC;AAAA,UAC7D,cAAc;AAAA,YACZ,wBAAwB,IAAI;AAAA,YAC5B,QAAQ;AAAA,UACV,EAAE;AAAA,UACF;AAAA,UACA,YAAY,UAAU,MAAM;AAAA,QAC9B,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,YAAQ,MAAM,cAAc,MAAM,IAAI;AAAA,EACxC;AACF;AAOA,SAAS,YAAY,OAAkC;AACrD,MAAI,iBAAiB,SAAS;AAC5B,WAAO,MAAM;AAAA,EACf;AAEA,SAAO,OAAO,KAAK;AACrB;AAOA,SAAS,eAAe,OAA0B,MAA4B;AAC5E,MAAI,MAAM,QAAQ;AAChB,WAAO,KAAK,OAAO,YAAY;AAAA,EACjC;AAEA,MAAI,iBAAiB,SAAS;AAC5B,WAAO,MAAM,OAAO,YAAY;AAAA,EAClC;AAEA,SAAO;AACT;AAOA,SAAS,gBAAgB,SAA+C;AACtE,MAAI,CAAC,SAAS;AACZ,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,OAAO,YAAY,IAAI,QAAQ,OAAO,EAAE,QAAQ,CAAC;AAC1D;AAOA,eAAe,iBACb,UACA,aAC6B;AAC7B,MAAI;AACF,WAAO,aAAa,MAAM,SAAS,MAAM,EAAE,KAAK,GAAG,WAAW,EAAE;AAAA,EAClE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,SAAS,gBAAgB,YAA4C;AACnE,SAAO,OAAO;AAAA,IACZ,WACG,KAAK,EACL,MAAM,OAAO,EACb,OAAO,OAAO,EACd,IAAI,CAAC,SAAS;AACb,YAAM,QAAQ,KAAK,QAAQ,GAAG;AAC9B,aAAO;AAAA,QACL,KAAK,MAAM,GAAG,KAAK,EAAE,KAAK,EAAE,YAAY;AAAA,QACxC,KAAK,MAAM,QAAQ,CAAC,EAAE,KAAK;AAAA,MAC7B;AAAA,IACF,CAAC;AAAA,EACL;AACF;AAOA,SAAS,wBAAwB,KAA6B;AAC5D,MAAI;AACF,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AExSA,SAAS,UAAAC,eAAc;AA6EvB,IAAM,gCAAgC;AACtC,IAAM,uCACJ;AACF,IAAM,0CAA0C;AAOzC,SAAS,wBAAgC;AAC9C,SAAO,kBAAkBC,QAAO,CAAC;AACnC;AAaA,SAAS,gCACP,UACoB;AACpB,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,qCAAqC;AAChD,WAAO,SAAS;AAAA,EAClB;AAEA,SAAO,SAAS,KACb,MAAM,uCAAuC,EAC7C,KAAK,CAAC,SAAS,KAAK,WAAW,oCAAoC,CAAC,GACnE,MAAM,qCAAqC,MAAM;AACvD;AAOA,SAAS,+BACP,UACA,UACM;AACN,WAAS,sCAAsC;AAC/C,QAAM,qBAAqB,SAAS,KACjC,MAAM,uCAAuC,EAC7C,OAAO,CAAC,SAAS,CAAC,KAAK,WAAW,oCAAoC,CAAC,EACvE,OAAO,OAAO;AACjB,WAAS,OAAO;AAAA,IACd,GAAG;AAAA,IACH,GAAG,oCAAoC,GAAG,QAAQ;AAAA,EACpD,EAAE,KAAK,uCAAuC;AAChD;AAOA,SAAS,uBACP,SACA,UACA,UACQ;AACR,UAAQ,QAAQ,+BAA+B,QAAQ;AAEvD,MAAI,UAAU;AACZ,mCAA+B,UAAU,QAAQ;AAAA,EACnD;AAEA,SAAO;AACT;AAEO,SAAS,mBACd,SACA,UACQ;AACR,QAAM,eAAe,sBAAsB;AAE3C,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,oBAAoB,gCAAgC,QAAQ;AAElE,QAAI,mBAAmB;AACrB,aAAO,uBAAuB,SAAS,mBAAmB,QAAQ;AAAA,IACpE;AAEA,QAAI,UAAU;AACZ,aAAO,uBAAuB,SAAS,cAAc,QAAQ;AAAA,IAC/D;AAEA,UAAM,kBAAkB,QAAQ,QAAQ,6BAA6B;AAErE,QAAI,iBAAiB;AACnB,aAAO;AAAA,IACT;AAEA,WAAO,uBAAuB,SAAS,YAAY;AAAA,EACrD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,sBAA8B;AAC5C,SAAO,WAAWA,QAAO,CAAC;AAC5B;AAOO,SAAS,uBACd,OACqB;AACrB,SAAO;AAAA,IACL,QAAQ,oBAAoB;AAAA,IAC5B,QAAQ;AAAA,IACR,KAAK,MAAM;AAAA,IACX,UAAU,gBAAgB,MAAM,IAAI;AAAA,IACpC,OAAO,MAAM;AAAA,IACb,iBAAiB,MAAM;AAAA,IACvB,WAAW;AAAA,IACX,YAAY,MAAM;AAAA,IAClB,UAAU;AAAA,MACR,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AACF;;;AC/NA,SAAS,UAAAC,eAAc;;;ACehB,SAAS,wBAAwB,OAGjB;AACrB,QAAM,SAAS,mBAAmB,MAAM,aAAa;AACrD,QAAM,gBAAgB,MAAM,UAAU,OAAO,CAAC,OAAO,SAAS;AAC5D,WACE,QACA,KAAK,IAAI,GAAG,KAAK,aAAa,0CAA0C;AAAA,EAE5E,GAAG,CAAC;AACJ,QAAM,gBAAgB,MAAM,UAAU;AACtC,QAAM,YAAY,MAAM,UAAU,IAAI,CAAC,SAAS,KAAK,UAAU;AAC/D,QAAM,oBAAoB,UAAU,SAAS,KAAK,IAAI,GAAG,SAAS,IAAI;AACtE,QAAM,wBAAwB,UAAU,SACpC,KAAK;AAAA,IACH,UAAU,OAAO,CAAC,OAAO,aAAa,QAAQ,UAAU,CAAC,IACvD,UAAU;AAAA,EACd,IACA;AACJ,QAAM,gBACJ,gBAAgB,KAAK,OAAO,UAAU,aAAa,gBAAgB;AACrE,QAAM,WAAW,gBAAgB;AAAA,IAC/B;AAAA,IACA;AAAA,IACA,aAAa,OAAO;AAAA,EACtB,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAOO,SAAS,mBAAmB,SAAwC;AACzE,QAAM,QAAQ,QAAQ,CAAC,GAAG;AAC1B,QAAM,OAAO,QAAQ,GAAG,EAAE,GAAG;AAC7B,QAAM,OAAO,QAAQ,OAAO,CAAC,aAAa,WAAW;AACnD,QAAI,OAAO,OAAO,mBAAmB,UAAU;AAC7C,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,IAAI,aAAa,OAAO,cAAc;AAAA,EACpD,GAAG,CAAC;AAEJ,QAAM,QAAQ,mBAAmB,OAAO,IAAI;AAE5C,SAAO;AAAA,IACL;AAAA,IACA,uBAAuB;AAAA,IACvB,qBAAqB;AAAA,IACrB,oBAAoB,QAAQ;AAAA,IAC5B,qBACE,OAAO,UAAU,YAAY,OAAO,SAAS,WACzC,OAAO,QACP;AAAA,IACN;AAAA,EACF;AACF;AAOO,SAAS,kBACd,QACA,UAA4D,CAAC,GAC/C;AACd,SAAO;AAAA,IACL,WAAW,CAAC,GAAG,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,GAAG,EAAE;AAAA,IACtD,gBAAgB,QAAQ;AAAA,IACxB,YAAY,QAAQ;AAAA,EACtB;AACF;AAOA,SAAS,gBAAgB,OAIU;AACjC,MAAI,MAAM,iBAAiB,OAAQ,MAAM,iBAAiB,IAAI;AAC5D,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,gBAAgB,KAAK,MAAM,gBAAgB,WAAW;AAC9D,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAOA,SAAS,mBACP,OACA,MACwB;AACxB,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,UAAU;AACzD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,OAAO;AAChB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAOA,SAAS,cACP,MACA,OACQ;AACR,SAAO,cAAc,MAAM,aAAa,KAAK,WAAW,KACnD,cAAc,MAAM,YAAY,KAAK,UAAU,KAC/C,cAAc,MAAM,UAAU,KAAK,QAAQ;AAClD;AAOA,SAAS,cAAc,MAAe,OAAwB;AAC5D,UAAQ,QAAQ,OAAO,SAAS;AAClC;;;AD7FA,IAAI;AAOG,SAAS,uBAAuB,SAKd;AACvB,QAAM,YAAY,2BAA2B;AAAA,IAC3C,QAAQ,QAAQ;AAAA,IAChB,KAAK,MAAM,KAAK,IAAI;AAAA,IACpB,YAAY;AAAA,IACZ,iBAAiB,CAAC,SAAS,iBAAiB,MAAM,QAAQ,mBAAmB;AAAA,IAC7E,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,IACnB;AAAA,IACA,YAAY,OAAO,WAAW,KAAK,MAAM;AAAA,IACzC,cAAc,OAAO,aAAa,KAAK,MAAM;AAAA,EAC/C,CAAC;AAED,QAAM,qBAAqB,QAAQ,OAC/B,2BAA2B,WAAW,QAAQ,IAAI,IAClD;AAEJ,+BAA6B;AAE7B,SAAO;AACT;AAOO,SAAS,0BAA4D;AAC1E,SAAO;AACT;AAOO,SAAS,2BACd,MACsB;AACtB,QAAM,QAAmC;AAAA,IACvC,WAAW,CAAC;AAAA,IACZ,aAAa,CAAC;AAAA,IACd,eAAe,CAAC;AAAA,IAChB,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,0BAA0B;AAAA,IAC1B,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,EACvB;AAEA,QAAM,WAAW;AAAA,IACf,KAAK,gBAAgB,CAAC,SAAS;AAC7B,YAAM,UAAU,KAAK,IAAI;AAAA,IAC3B,CAAC;AAAA,IACD,KAAK,sBAAsB,CAAC,SAAS;AACnC,YAAM,UAAU,KAAK,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAEA,MAAI,KAAK,mBAAmB;AAC1B,aAAS;AAAA,MACP,KAAK,kBAAkB,CAAC,UAAU;AAChC,cAAM,YAAY,KAAK,KAAK;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,KAAK,gCAAgC;AACvC,aAAS;AAAA,MACP,KAAK,+BAA+B,CAAC,UAAU;AAC7C,cAAM,YAAY,KAAK,KAAK;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,WAAW,SAAS;AACxB,YAAM,cAAc,aAAa,OAAO,MAAM;AAAA,QAC5C,eAAe,QAAQ;AAAA,QACvB,eAAe,QAAQ;AAAA,MACzB,CAAC;AAED,YAAM,gBAAgB,MAAM,QAAQ,UAAU;AAE9C,aAAO,YAAY;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,IACA,MAAM,SAAS;AACb,UAAI,MAAM,mBAAmB;AAC3B,cAAM,IAAI,MAAM,2CAA2C;AAAA,MAC7D;AAEA,aAAO,aAAa,OAAO,MAAM,OAAO;AAAA,IAC1C;AAAA,IACA,KAAK,aAAa;AAChB,aAAO,YAAY;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,IACA,SAAS;AACP,aAAO,MAAM;AAAA,IACf;AAAA,IACA,UAAU;AACR,mCAA6B;AAC7B,iBAAW,WAAW,UAAU;AAC9B,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;AA2BA,SAAS,oBAA4B;AACnC,SAAO,eAAeC,QAAO,CAAC;AAChC;AAKA,SAAS,aACP,OACA,MACA,SAIQ;AACR,QAAM,cAAc,kBAAkB;AACtC,QAAM,UAAU,SAAS;AACzB,QAAM,YAAY,SAAS;AAC3B,QAAM,cAAc,SAAS;AAE7B,MAAI,QAAQ,eAAe;AACzB,UAAM,SAAS,KAAK,WAAW;AAC/B,QAAI,QAAQ;AACV,YAAM,cAAc,KAAK,MAAM;AAAA,IACjC;AAAA,EACF;AAEA,QAAM,oBAAoB;AAC1B,QAAM,2BAA2B,KAAK,IAAI;AAC1C,QAAM,sBAAsB,QAAQ;AACpC,QAAM,sBAAsB,QAAQ;AAEpC,SAAO;AACT;AAQA,SAAS,2BACP,WACA,MACsB;AACtB,SAAO;AAAA,IACL,MAAM,WAAW,SAAS;AACxB,YAAM,SAAS,MAAM,UAAU,WAAW,OAAO;AACjD,WAAK,MAAM;AACX,aAAO;AAAA,IACT;AAAA,IACA,MAAM,SAAS;AACb,aAAO,UAAU,MAAM,OAAO;AAAA,IAChC;AAAA,IACA,KAAK,aAAa;AAChB,YAAM,SAAS,UAAU,KAAK,WAAW;AACzC,WAAK,MAAM;AACX,aAAO;AAAA,IACT;AAAA,IACA,SAAS;AACP,aAAO,UAAU,OAAO;AAAA,IAC1B;AAAA,IACA,UAAU;AACR,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF;AACF;AAKA,SAAS,gBACP,MACA,YACe;AACf,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,KAAK,WAAW,MAAM;AAClC,WAAK,aAAa,KAAK;AACvB,cAAQ;AAAA,IACV,GAAG,UAAU;AAAA,EACf,CAAC;AACH;AAKA,SAAS,YAAY,SAcC;AACpB,QAAM,SAAS,QAAQ,gBACnB,mBAAmB,QAAQ,aAAa,IACxC;AACJ,QAAM,UAAU,wBAAwB;AAAA,IACtC,WAAW,QAAQ;AAAA,IACnB,eAAe,QAAQ,gBAAgB,QAAQ,gBAAgB,CAAC;AAAA,EAClE,CAAC;AACD,QAAM,SAAS,QAAQ,gBACnB,kBAAkB,QAAQ,aAAa;AAAA,IACrC,gBAAgB,QAAQ;AAAA,IACxB,YACE,QAAQ,YAAY,SAAS,IACzB,SACA;AAAA,EACR,CAAC,IACD;AACJ,QAAM,SAA4B;AAAA,IAChC,aAAa,QAAQ;AAAA,IACrB,QAAQ,QAAQ;AAAA,IAChB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,IACjB,YAAY,QAAQ,UAAU,QAAQ;AAAA,IACtC;AAAA,IACA,WAAW,CAAC,GAAG,QAAQ,SAAS;AAAA,IAChC;AAAA,IACA;AAAA,IACA,WAAW,QAAQ;AAAA,IACnB,aAAa,QAAQ;AAAA,EACvB;AAEA,SAAO;AACT;AAKA,SAAS,YAAY,SAKC;AACpB,QAAM,EAAE,OAAO,MAAM,aAAa,OAAO,IAAI;AAE7C,MAAI,CAAC,MAAM,qBAAqB,MAAM,sBAAsB,aAAa;AACvE,UAAM,IAAI,MAAM,oCAAoC,WAAW,EAAE;AAAA,EACnE;AAEA,MAAI,MAAM,qBAAqB;AAC7B,UAAM,SAAS,KAAK,WAAW;AAC/B,QAAI,QAAQ;AACV,YAAM,cAAc,KAAK,MAAM;AAAA,IACjC;AAAA,EACF;AAEA,QAAM,SAAS,YAAY;AAAA,IACzB,aAAa,MAAM;AAAA,IACnB,QAAQ,KAAK;AAAA,IACb,WAAW,MAAM;AAAA,IACjB,SAAS,KAAK,IAAI;AAAA,IAClB;AAAA,IACA,eAAe,MAAM;AAAA,IACrB,eAAe,MAAM;AAAA,IACrB,WAAW,MAAM;AAAA,IACjB,eAAe,MAAM;AAAA,IACrB,aAAa,MAAM;AAAA,IACnB,aAAa;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,eAAe;AACrB,QAAM,oBAAoB;AAC1B,QAAM,2BAA2B;AACjC,QAAM,sBAAsB;AAC5B,QAAM,sBAAsB;AAE5B,SAAO;AACT;AAKA,SAAS,oBAA8C;AACrD,QAAM,SAAU,YAMb;AAEH,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,WAAW,KAAK,IAAI;AAAA,IACpB,gBAAgB,OAAO;AAAA,IACvB,iBAAiB,OAAO;AAAA,IACxB,iBAAiB,OAAO;AAAA,EAC1B;AACF;AAKA,SAAS,iBACP,MACA,sBAAsB,IACV;AACZ,MAAI,OAAO,wBAAwB,aAAa;AAC9C,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AAEA,QAAM,WAAW,IAAI,oBAAoB,CAAC,SAAS;AACjD,eAAW,SAAS,KAAK,WAAW,GAAG;AACrC,UAAI,MAAM,WAAW,qBAAqB;AACxC;AAAA,MACF;AAEA,WAAK;AAAA,QACH,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,QAClB,MAAM,MAAM;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,WAAS,QAAQ,EAAE,MAAM,YAAY,UAAU,KAAK,CAAC;AAErD,SAAO,MAAM;AACX,aAAS,WAAW;AAAA,EACtB;AACF;AAKA,SAAS,2BACP,MACY;AACZ,MAAI,OAAO,wBAAwB,aAAa;AAC9C,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AAEA,QAAM,YAAY,oBAAoB,oBAAoB;AAAA,IACxD;AAAA,EACF;AAEA,MAAI,CAAC,WAAW;AACd,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AAEA,QAAM,WAAW,IAAI,oBAAoB,CAAC,SAAS;AACjD,eAAW,SAAS,KAAK,WAAW,GAAG;AACrC,WAAK;AAAA,QACH,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,QAClB,MAAM,MAAM;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,WAAS,QAAQ,EAAE,MAAM,wBAAwB,UAAU,KAAK,CAAC;AAEjE,SAAO,MAAM;AACX,aAAS,WAAW;AAAA,EACtB;AACF;AAKA,SAAS,wBACP,MACY;AACZ,QAAM,UAAU,CAAC,UAA4B;AAC3C,UAAM,QAAQ,MAAM;AACpB,UAAM,SAAS,iBAAiB,OAAO,KAAK;AAC5C,QAAI,OAAO,WAAW,KAAK,MAAM,SAAS;AACxC,WAAK,EAAE,cAAc,MAAM,QAAQ,CAAC;AACpC;AAAA,IACF;AAEA,WAAO,QAAQ,CAAC,UAAU;AACxB,WAAK,KAAK;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,SAAO,iBAAiB,SAAS,OAAO;AAExC,SAAO,MAAM;AACX,WAAO,oBAAoB,SAAS,OAAO;AAAA,EAC7C;AACF;AAKA,SAAS,+BACP,MACY;AACZ,QAAM,cAAc,CAAC,UAAuC;AAC1D,UAAM,SAAS,MAAM;AACrB,UAAM,SAAS,iBAAiB,QAAQ,KAAK;AAE7C,QAAI,OAAO,WAAW,KAAK,QAAQ,SAAS;AAC1C,WAAK,EAAE,cAAc,OAAO,QAAQ,CAAC;AACrC;AAAA,IACF;AAEA,WAAO,QAAQ,CAAC,UAAU;AACxB,WAAK,KAAK;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,SAAO,iBAAiB,sBAAsB,WAAW;AAEzD,SAAO,MAAM;AACX,WAAO,oBAAoB,sBAAsB,WAAW;AAAA,EAC9D;AACF;AAKA,SAAS,iBAAiB,OAAqC;AAC7D,MAAI,CAAC,OAAO;AACV,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,MACJ,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO,EACd,IAAI,CAAC,SAAS;AACb,UAAM,QAAQ,sCAAsC,KAAK,IAAI;AAE7D,QAAI,OAAO;AACT,aAAO;AAAA,QACL,cAAc,MAAM,CAAC,KAAK;AAAA,QAC1B,KAAK,MAAM,CAAC;AAAA,QACZ,YAAY,OAAO,MAAM,CAAC,CAAC;AAAA,QAC3B,cAAc,OAAO,MAAM,CAAC,CAAC;AAAA,MAC/B;AAAA,IACF;AAEA,WAAO,EAAE,cAAc,KAAK;AAAA,EAC9B,CAAC;AACL;;;AEzgBA,IAAI,gBAA+B,MACjC,QAAQ,OAAO,0BAA0B,CAAC;AAQ5C,IAAI,2BACF,CAAC;AAOI,SAAS,4BACd,UACM;AACN,6BAA2B;AAC7B;AAOO,SAAS,iBAAiB,QAA6B;AAC5D,kBAAgB;AAClB;AAOA,eAAsB,sBACpB,SAC2D;AAC3D,QAAM,SAAS,wBAAwB,QAAQ,QAAQ,QAAQ,QAAQ;AAEvE,MAAI,CAAC,OAAO,IAAI;AACd,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,QAAQ,eAAe;AAC3C,MAAI;AAEJ,MAAI;AACF,aAAS,MAAM,YAAY;AAAA,EAC7B,SAAS,OAAO;AACd,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D;AAAA,EACF;AAEA,QAAM,EAAE,QAAQ,IAAI;AACpB,QAAM,iBAAiB,MAAM,qBAAqB,OAAO;AACzD,QAAM,UAAU,MAAM,QAAQ,OAAO,SAAS,cAAc;AAC5D,QAAM,OAAO,MAAM,QAAQ,OAAO;AAAA,IAChC,MAAM,eAAe,QAAQ,MAAM;AAAA,IACnC,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,OAAO,MAAM,aAAa,IAAI;AACpC,QAAM,OAAO,OAAO,QAAQ,sBAAsB;AAElD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR;AAAA,IACA,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,UAAU,eAAe,QAAQ,MAAM;AAAA,IACvC,YAAY,KAAK;AAAA,IACjB,aAAa;AAAA,MACX;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAOA,SAAS,qBAA4D;AACnE,SAAO,cAAc;AACvB;AAOA,SAAS,wBACP,QACA,UAG+B;AAC/B,MAAI,WAAW,aAAa,CAAC,UAAU;AACrC,WAAO,EAAE,IAAI,OAAO,OAAO,8CAA8C;AAAA,EAC3E;AAEA,MAAI,WAAW,WAAW;AACxB,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,IAAI,OAAO,OAAO,8CAA8C;AAAA,IAC3E;AAEA,UAAM,kBAAkB;AACxB,UAAM,UAAU,SAAS,cAAc,eAAe;AAEtD,WAAO,UACH,EAAE,IAAI,MAAM,QAAQ,IACpB,EAAE,IAAI,OAAO,OAAO,sBAAsB,eAAe,GAAG;AAAA,EAClE;AAEA,SAAO,EAAE,IAAI,MAAM,SAAS,SAAS,gBAAgB;AACvD;AAOA,eAAe,qBACb,SACkC;AAClC,QAAM,iBAA0C;AAAA,IAC9C,GAAG,QAAQ,QAAQ;AAAA,IACnB,SAAS,QAAQ,WAAW,QAAQ,QAAQ,QAAQ;AAAA,IACpD,OAAO,QAAQ,SAAS,QAAQ,QAAQ,QAAQ;AAAA,IAChD,SAAS,MAAM,mBAAmB,OAAO;AAAA,EAC3C;AACA,QAAM,aAAa,mBAAmB,OAAO;AAE7C,MAAI,QAAQ,QAAQ,QAAQ;AAC1B,mBAAe,SAAS,MAAM;AAAA,MAC5B;AAAA,MACA,QAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AAEA,MAAI,QAAQ,QAAQ,aAAa;AAC/B,mBAAe,cAAc,MAAM;AAAA,MACjC;AAAA,MACA,QAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AAEA,SAAO,uBAAuB,cAAc;AAC9C;AAOA,eAAe,mBACb,SACoB;AACpB,QAAM,aAAa,mBAAmB,OAAO;AAE7C,SAAO,QAAQ;AAAA,IACb,QAAQ,QAAQ,QAAQ,IAAI,CAAC,WAAW,iBAAiB,QAAQ,UAAU,CAAC;AAAA,EAC9E;AACF;AAOA,SAAS,mBACP,SACoD;AACpD,SAAO,QAAQ,cAAc;AAC/B;AAQA,SAAS,qBACP,MACkC;AAClC,QAAM,MAAM,yBAAyB,IAAI;AAEzC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,wCAAwC,IAAI,EAAE;AAAA,EAChE;AAEA,SAAO,QAAQ,QAAQ,GAAG;AAC5B;AAOA,eAAe,iBACb,QACA,YACkB;AAClB,QAAM,aACJ,OAAO,WAAW,WACd,EAAE,MAAM,QAAQ,YAAY,UAAU,IACtC,EAAE,YAAY,WAAW,GAAG,OAAO;AACzC,QAAM,MAAM,MAAM,WAAW,WAAW,IAAI;AAC5C,QAAM,WAAW,IAAI,WAAW,UAAU;AAE1C,MAAI,gBAAgB,QAAQ,KAAK,aAAa,YAAY;AACxD,WAAO,SAAS,WAAW,OAAO;AAAA,EACpC;AAEA,SAAO;AACT;AAOA,SAAS,gBAAgB,OAAwD;AAC/E,SAAO,OAAO,UAAU;AAC1B;AAOA,eAAe,kBACb,YACA,MACkB;AAClB,UAAQ,MAAM,WAAW,IAAI,GAAG;AAClC;AAOA,SAAS,eAAe,QAAkC;AACxD,SAAO,SAAS,MAAM;AACxB;AAOA,eAAe,aAAa,MAA6B;AACvD,QAAM,QAAQ,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AACrD,MAAI,SAAS;AAEb,aAAW,QAAQ,OAAO;AACxB,cAAU,OAAO,aAAa,IAAI;AAAA,EACpC;AAEA,SAAO,KAAK,MAAM;AACpB;AAOA,SAAS,uBACP,OACyB;AACzB,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,IAAI,MAAM,SAAS,MAAS;AAAA,EAC/D;AACF;AAOA,SAAS,4BAAmC;AAC1C,SAAO,IAAI;AAAA,IACT;AAAA,EACF;AACF;;;AC9VA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAAuB;;;ACOhC,eAAsB,mBACpB,SACkB;AAClB,QAAM,QAAQ,cAAc,QAAQ,UAAU;AAC9C,QAAM,SACJ,QAAQ,iBAAiB,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,KAAK;AAEtE,SAAO,QAAQ,KAAK;AAAA,IAClB,QAAQ,QAAQ,MAAM;AAAA,IACtB,cAAc,QAAQ,SAAS;AAAA,EACjC,CAAC;AACH;AAQA,SAAS,cAAc,YAA6B;AAElD,SAAO,IAAI,SAAS,WAAW,UAAU,GAAG,EAAE;AAChD;AAOA,SAAS,cAAc,WAAmC;AACxD,SAAO,IAAI,QAAQ,CAAC,GAAG,WAAW;AAChC,WAAO,WAAW,MAAM;AACtB;AAAA,QACE,IAAI,MAAM,mCAAmC,OAAO,SAAS,CAAC,IAAI;AAAA,MACpE;AAAA,IACF,GAAG,SAAS;AAAA,EACd,CAAC;AACH;;;ACLO,SAAS,2BACd,KACsB;AACtB,SAAO;AAAA,IACL,MAAM,cAAc,SAAS;AAC3B,UAAI;AACF,eAAO,MAAM,qBAAqB,KAAK,OAAO;AAAA,MAChD,SAAS,OAAO;AACd,eAAO;AAAA,UACL;AAAA,UACA,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QACvD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,qBACb,KACA,SAC+B;AAC/B,MAAI,QAAQ,WAAW,IAAI,QAAQ;AACjC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,UAAU,UAAU;AAC9B,WAAO,oBAAoB,KAAK,OAAO;AAAA,EACzC;AAEA,MAAI,QAAQ,UAAU,aAAa;AACjC,WAAO,uBAAuB,KAAK,OAAO;AAAA,EAC5C;AAEA,SAAO,wBAAwB,cAAc,KAAK,QAAQ,KAAK,GAAG,OAAO;AAC3E;AAEA,SAAS,oBACP,KACA,SACsB;AACtB,MAAI,CAAC,IAAI,QAAQ;AACf,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,CAAC,8DAA8D;AAAA,IACjE;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,QAAQ;AAC7B,WAAO,4BAA4B,SAAS;AAAA,MAC1C,QAAQ,QAAQ;AAAA,MAChB,SAAS,mBAAmB,IAAI,MAAM;AAAA,IACxC,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,WAAW,OAAO;AAC5B,qBAAiB,OAAO;AAExB,WAAO,4BAA4B,SAAS;AAAA,MAC1C,QAAQ,QAAQ;AAAA,MAChB,SAAS,mBAAmB,IAAI,MAAM,EAAE;AAAA,QACtC,CAAC,WAAW,OAAO,SAAS,QAAQ,OAAO;AAAA,MAC7C;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,WAAW,OAAO;AAC5B,qBAAiB,OAAO;AACxB,QAAI,OAAO,IAAI,yBAAyB,OAAO,CAAC;AAEhD,WAAO,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1D;AAEA,MAAI,QAAQ,WAAW,UAAU;AAC/B,qBAAiB,OAAO;AACxB,QAAI,OAAO,IAAI,0BAA0B,OAAO,CAAC;AAEjD,WAAO,4BAA4B,SAAS;AAAA,MAC1C,cAAc;AAAA,MACd,sBAAsB;AAAA,MACtB,aAAa,CAAC,yDAAyD;AAAA,IACzE,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,mBAAmB,IAAI,MAAM;AAE7C,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO;AAAA,MACT,0BAA0B;AAAA,QACxB,GAAG;AAAA,QACH,QAAQ;AAAA,UACN,MAAM,OAAO;AAAA,UACb,MAAM,QAAQ,QAAQ;AAAA,QACxB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,4BAA4B,SAAS;AAAA,IAC1C,cAAc,QAAQ;AAAA,IACtB,sBAAsB;AAAA,IACtB,aAAa,CAAC,yDAAyD;AAAA,EACzE,CAAC;AACH;AAEA,SAAS,cACP,KACA,OACS;AACT,SAAO,UAAU,mBAAmB,IAAI,iBAAiB,IAAI;AAC/D;AAEA,SAAS,wBACP,SACA,SACsB;AACtB,MAAI,QAAQ,WAAW,QAAQ;AAC7B,WAAO,4BAA4B,SAAS;AAAA,MAC1C,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,MACf,SAAS,mBAAmB,OAAO;AAAA,IACrC,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,WAAW,OAAO;AAC5B,qBAAiB,OAAO;AAExB,WAAO,4BAA4B,SAAS;AAAA,MAC1C,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,MACf,KAAK,QAAQ;AAAA,MACb,OAAO,QAAQ,QAAQ,QAAQ,GAAG;AAAA,IACpC,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,WAAW,OAAO;AAC5B,qBAAiB,OAAO;AACxB,YAAQ,QAAQ,QAAQ,KAAK,QAAQ,SAAS,EAAE;AAEhD,WAAO,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1D;AAEA,MAAI,QAAQ,WAAW,UAAU;AAC/B,qBAAiB,OAAO;AACxB,YAAQ,WAAW,QAAQ,GAAG;AAE9B,WAAO,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1D;AAEA,UAAQ,MAAM;AAEd,SAAO,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC;AAC1D;AAEA,eAAe,uBACb,KACA,SAC+B;AAC/B,MAAI,CAAC,IAAI,WAAW,WAAW;AAC7B,WAAO,0BAA0B,SAAS,uCAAuC;AAAA,EACnF;AAEA,MAAI,QAAQ,WAAW,QAAQ;AAC7B,UAAM,YAAY,MAAM,IAAI,UAAU,UAAU;AAEhD,WAAO,4BAA4B,SAAS;AAAA,MAC1C,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,MACf,WAAW,UAAU,IAAI,CAAC,cAAc;AAAA,QACtC,MAAM,SAAS;AAAA,QACf,SAAS,SAAS;AAAA,MACpB,EAAE;AAAA,IACJ,CAAC;AAAA,EACH;AAEA,wBAAsB,OAAO;AAE7B,MAAI,YAAY,IAAI,WAAW;AAC7B,WAAO,sBAAsB,IAAI,WAAW,OAAO;AAAA,EACrD;AAEA,SAAO,uBAAuB,IAAI,WAAW,OAAO;AACtD;AAEA,SAAS,sBACP,WACA,SAIsB;AACtB,QAAM,UAAU,GAAG,QAAQ,YAAY,IAAI,QAAQ,eAAe;AAClE,QAAM,QAAQ,UAAU,OAAO,IAAI,OAAO,KAAK,oBAAI,IAAqB;AACxE,YAAU,OAAO,IAAI,SAAS,KAAK;AAEnC,MAAI,QAAQ,WAAW,OAAO;AAC5B,qBAAiB,OAAO;AAExB,WAAO,4BAA4B,SAAS;AAAA,MAC1C,KAAK,QAAQ;AAAA,MACb,OAAO,MAAM,IAAI,QAAQ,GAAG,KAAK;AAAA,IACnC,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,WAAW,OAAO;AAC5B,qBAAiB,OAAO;AACxB,UAAM,IAAI,QAAQ,KAAK,oBAAoB,QAAQ,KAAK,CAAC;AAEzD,WAAO,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1D;AAEA,MAAI,QAAQ,WAAW,UAAU;AAC/B,qBAAiB,OAAO;AACxB,UAAM,OAAO,QAAQ,GAAG;AAExB,WAAO,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC;AAAA,EAC1D;AAEA,QAAM,MAAM;AAEZ,SAAO,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC;AAC1D;AAEA,eAAe,uBACb,WACA,SAI+B;AAC/B,QAAM,WAAW,MAAM,wBAAwB,WAAW,OAAO;AAEjE,MAAI;AACF,WAAO,MAAM,4BAA4B,UAAU,OAAO;AAAA,EAC5D,UAAE;AACA,aAAS,MAAM;AAAA,EACjB;AACF;AAEA,SAAS,cACP,WACA,cACsB;AACtB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,UAAU,UAAU,KAAK,YAAY;AAC3C,YAAQ,UAAU,MAAM;AACtB,aAAO,QAAQ,SAAS,IAAI,MAAM,uBAAuB,CAAC;AAAA,IAC5D;AACA,YAAQ,YAAY,MAAM;AACxB,cAAQ,QAAQ,MAAM;AAAA,IACxB;AAAA,EACF,CAAC;AACH;AAQA,eAAe,wBACb,WACA,SAIsB;AACtB,QAAM,WAAW,MAAM,cAAc,WAAW,QAAQ,YAAY;AAEpE,MACE,QAAQ,WAAW,SACnB,SAAS,iBAAiB,SAAS,QAAQ,eAAe,GAC1D;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,SAAS,UAAU;AACnC,WAAS,MAAM;AAEf,SAAO,uBAAuB,WAAW;AAAA,IACvC,cAAc,QAAQ;AAAA,IACtB,iBAAiB,QAAQ;AAAA,IACzB;AAAA,EACF,CAAC;AACH;AAQA,SAAS,uBACP,WACA,SAKsB;AACtB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,UAAU,UAAU,KAAK,QAAQ,cAAc,QAAQ,OAAO;AACpE,YAAQ,kBAAkB,MAAM;AAC9B,YAAM,WAAW,QAAQ;AAEzB,UAAI,CAAC,SAAS,iBAAiB,SAAS,QAAQ,eAAe,GAAG;AAChE,iBAAS,kBAAkB,QAAQ,eAAe;AAAA,MACpD;AAAA,IACF;AACA,YAAQ,UAAU,MAAM;AACtB,aAAO,QAAQ,SAAS,IAAI,MAAM,0BAA0B,CAAC;AAAA,IAC/D;AACA,YAAQ,YAAY,MAAM;AACxB,cAAQ,QAAQ,MAAM;AAAA,IACxB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,4BACP,UACA,SAI+B;AAC/B,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,OAAO,QAAQ,WAAW,QAAQ,aAAa;AACrD,UAAM,cAAc,SAAS,YAAY,QAAQ,iBAAiB,IAAI;AACtE,UAAM,QAAQ,YAAY,YAAY,QAAQ,eAAe;AAE7D,gBAAY,UAAU,MAAM;AAC1B,aAAO,YAAY,SAAS,IAAI,MAAM,8BAA8B,CAAC;AAAA,IACvE;AAEA,QAAI,QAAQ,WAAW,OAAO;AAC5B,uBAAiB,OAAO;AACxB,YAAM,aAAa,MAAM,IAAI,QAAQ,GAAG;AACxC,iBAAW,UAAU,MAAM;AACzB,eAAO,WAAW,SAAS,IAAI,MAAM,sBAAsB,CAAC;AAAA,MAC9D;AACA,iBAAW,YAAY,MAAM;AAC3B,cAAM,QAAiB,WAAW,UAAU;AAC5C;AAAA,UACE,4BAA4B,SAAS;AAAA,YACnC,KAAK,QAAQ;AAAA,YACb;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,OAAO;AAC5B,uBAAiB,OAAO;AACxB,YAAM,IAAI,oBAAoB,QAAQ,KAAK,GAAG,QAAQ,GAAG;AACzD,kBAAY,aAAa,MAAM;AAC7B,gBAAQ,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC,CAAC;AAAA,MAC5D;AACA;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,UAAU;AAC/B,uBAAiB,OAAO;AACxB,YAAM,OAAO,QAAQ,GAAG;AACxB,kBAAY,aAAa,MAAM;AAC7B,gBAAQ,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC,CAAC;AAAA,MAC5D;AACA;AAAA,IACF;AAEA,UAAM,MAAM;AACZ,gBAAY,aAAa,MAAM;AAC7B,cAAQ,4BAA4B,SAAS,EAAE,IAAI,KAAK,CAAC,CAAC;AAAA,IAC5D;AAAA,EACF,CAAC;AACH;AAEA,SAAS,mBAAmB,SAGzB;AACD,QAAM,UAAiD,CAAC;AAExD,WAAS,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtD,UAAM,MAAM,QAAQ,IAAI,KAAK;AAE7B,QAAI,CAAC,KAAK;AACR;AAAA,IACF;AAEA,UAAM,QAAQ,QAAQ,QAAQ,GAAG;AAEjC,QAAI,UAAU,MAAM;AAClB;AAAA,IACF;AAEA,YAAQ,KAAK,EAAE,KAAK,MAAM,CAAC;AAAA,EAC7B;AAEA,SAAO;AACT;AAEA,SAAS,mBAAmB,cAGzB;AACD,SAAO,aACJ,IAAI,EACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO,EACd,IAAI,CAAC,SAAS;AACb,UAAM,iBAAiB,KAAK,QAAQ,GAAG;AAEvC,QAAI,mBAAmB,IAAI;AACzB,aAAO,EAAE,MAAM,iBAAiB,IAAI,GAAG,OAAO,GAAG;AAAA,IACnD;AAEA,WAAO;AAAA,MACL,MAAM,iBAAiB,KAAK,MAAM,GAAG,cAAc,CAAC;AAAA,MACpD,OAAO,iBAAiB,KAAK,MAAM,iBAAiB,CAAC,CAAC;AAAA,IACxD;AAAA,EACF,CAAC;AACL;AAEA,SAAS,yBAAyB,SAEvB;AACT,QAAM,QAAQ,QAAQ,OAAO,SAAS,QAAQ,SAAS;AACvD,QAAM,QAAQ;AAAA,IACZ,GAAG,mBAAmB,QAAQ,OAAO,IAAI,CAAC,IAAI,mBAAmB,KAAK,CAAC;AAAA,EACzE;AAEA,gCAA8B,OAAO,QAAQ,MAAM;AAEnD,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,0BAA0B,SAExB;AACT,QAAM,QAAQ;AAAA,IACZ,GAAG,mBAAmB,QAAQ,OAAO,IAAI,CAAC;AAAA,IAC1C;AAAA,IACA;AAAA,EACF;AAEA,gCAA8B,OAAO;AAAA,IACnC,MAAM,QAAQ,OAAO;AAAA,IACrB,QAAQ,QAAQ,OAAO;AAAA,EACzB,CAAC;AAED,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,8BACP,OACA,QACM;AACN,MAAI,OAAO,MAAM;AACf,UAAM,KAAK,QAAQ,OAAO,IAAI,EAAE;AAAA,EAClC;AAEA,MAAI,OAAO,QAAQ;AACjB,UAAM,KAAK,UAAU,OAAO,MAAM,EAAE;AAAA,EACtC;AAEA,MAAI,OAAO,YAAY,QAAW;AAChC,UAAM,KAAK,WAAW,IAAI,KAAK,OAAO,UAAU,GAAI,EAAE,YAAY,CAAC,EAAE;AAAA,EACvE;AAEA,MAAI,OAAO,UAAU;AACnB,UAAM,KAAK,YAAY,yBAAyB,OAAO,QAAQ,CAAC,EAAE;AAAA,EACpE;AAEA,MAAI,OAAO,QAAQ;AACjB,UAAM,KAAK,QAAQ;AAAA,EACrB;AACF;AAEA,SAAS,yBACP,UAC2B;AAC3B,MAAI,aAAa,UAAU;AACzB,WAAO;AAAA,EACT;AAEA,MAAI,aAAa,OAAO;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAuB;AAC/C,MAAI;AACF,WAAO,mBAAmB,KAAK;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBACP,SACqE;AACrE,MAAI,CAAC,QAAQ,KAAK;AAChB,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACF;AAEA,SAAS,iBACP,SAGA;AACA,MAAI,CAAC,QAAQ,QAAQ,MAAM;AACzB,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACF;AAEA,SAAS,sBACP,SAIA;AACA,MAAI,CAAC,QAAQ,gBAAgB,CAAC,QAAQ,iBAAiB;AACrD,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACF;AAEA,SAAS,oBAAoB,OAAyB;AACpD,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,4BACP,SACA,MACsB;AACtB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf;AAAA,EACF;AACF;AAEA,SAAS,0BACP,SACA,OACA,aACsB;AACtB,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf;AAAA,IACA;AAAA,EACF;AACF;;;ACnmBO,SAAS,yBACd,QAiBA;AACA,SAAO;AAAA,IACL,WAAW,SAAS;AAClB,aAAO,EAAE;AAAA,QACP,QAAQ;AAAA,QACR,kBAAkB,SAAS,iBAAiB;AAAA,UAC1C,UAAU,QAAQ;AAAA,UAClB,UAAU,QAAQ;AAAA,UAClB,eAAe,QAAQ;AAAA,QACzB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,kBAAkB,MAAM;AAAA,IACxB,SAAS,SAAS;AAChB,aAAO,EAAE;AAAA,QACP,QAAQ;AAAA,QACR,iBAAiB,QAAQ,UAAU,QAAQ,KAAK;AAAA,MAClD;AAAA,IACF;AAAA,IACA,mBAAmB,MAAM;AAAA,IACzB,kBAAkB,SAAS;AACzB,UAAI;AACF,eAAO,EAAE;AAAA,UACP,QAAQ;AAAA,UACR,0BAA0B,EAAE,kBAAkB,QAAQ,SAAS;AAAA,QACjE;AAAA,MACF,SAAS,OAAO;AACd,eAAO,EAAE,wBAAwB,QAAQ,OAAO;AAAA,UAC9C,IAAI;AAAA,UACJ,WAAW,QAAQ;AAAA,UACnB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,UAC5D,aAAa,CAAC,uCAAuC;AAAA,QACvD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,yBAAyB,MAAM;AAAA,IAC/B,WAAW,SAAS;AAClB,aAAO,EAAE,eAAe,QAAQ,OAAO,EAAE,IAAI,MAAM,QAAQ,OAAO,CAAC;AACnE,iBAAW,MAAM;AACf,eAAO,SAAS,OAAO;AAAA,MACzB,GAAG,CAAC;AAAA,IACN;AAAA,IACA,gBAAgB,MAAM;AAAA,IACtB,MAAM,eAAe,SAAS;AAC5B,UAAI;AACF,eAAO,EAAE,wBAAwB,QAAQ,OAAO;AAAA,UAC9C,IAAI;AAAA,UACJ,OAAO,MAAM,mBAAmB,OAAO;AAAA,QACzC,CAAC;AAAA,MACH,SAAS,OAAO;AACd,eAAO,EAAE,wBAAwB,QAAQ,OAAO;AAAA,UAC9C,IAAI;AAAA,UACJ,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,yBAAyB,MAAM;AAAA,IAC/B,MAAM,eAAe,SAAS;AAC5B,UAAI;AACF,eAAO,EAAE;AAAA,UACP,QAAQ;AAAA,UACR,MAAM,sBAAsB,OAAO;AAAA,QACrC;AAAA,MACF,SAAS,OAAO;AACd,eAAO,EAAE,kBAAkB,QAAQ,OAAO;AAAA,UACxC,IAAI;AAAA,UACJ,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,mBAAmB,MAAM;AAAA,IACzB,MAAM,cAAc,SAAS;AAC3B,YAAM,SAAS,2BAA2B;AAAA,QACxC,QAAQ,OAAO,SAAS;AAAA,QACxB,cAAc,OAAO;AAAA,QACrB,gBAAgB,OAAO;AAAA,QACvB,WAAW,OAAO;AAAA,QAClB,QAAQ;AAAA,UACN,KAAK,MAAM,OAAO,SAAS;AAAA,UAC3B,KAAK,CAAC,UAAU;AACd,mBAAO,SAAS,SAAS;AAAA,UAC3B;AAAA,QACF;AAAA,MACF,CAAC;AACD,aAAO,EAAE;AAAA,QACP,QAAQ;AAAA,QACR,MAAM,OAAO,cAAc,OAAO;AAAA,MACpC;AAAA,IACF;AAAA,IACA,kBAAkB,MAAM;AAAA,EAC1B;AACF;;;AHvGA,IAAM,qBAAqB;AAC3B,IAAM,0BAA0B;AAChC,IAAM,+BAA+B;AAErC,IAAI;AAOG,SAAS,4BAAkC;AAChD,WAAS,KAAK;AAChB;AAOO,SAAS,iBAAiB,KAA2B;AAC1D,QAAM,SAAsC,CAAC;AAC7C,QAAM,MAAM;AAAA,IACV;AAAA,IACA;AAAA,IACA,0BAA0B,MAAM;AAC9B,UAAI,CAAC,OAAO,SAAS;AACnB,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AACA,aAAO,OAAO;AAAA,IAChB,CAAC;AAAA,IACD,EAAE,SAAS,GAAG;AAAA,EAChB;AACA,SAAO,UAAU;AACnB;AAOA,SAAS,0BAA0B,QAA4C;AAC7E,SAAO;AAAA,IACL,GAAG,yBAAyB,MAAM;AAAA,IAClC,MAAM,iBAAiB,OAAO;AAC5B,YAAM,gBAAgB,MAAM,SAAS,IAAI,iBAAiB;AAAA,QACxD,aAAa;AAAA,QACb,QAAQ,MAAM,iBAAiB;AAAA,MACjC,CAAC;AACD,aAAO,EAAE,uBAAuB,MAAM,OAAO,cAAc,CAAC,CAAC;AAAA,IAC/D;AAAA,IACA,wBAAwB,MAAM;AAAA,IAC9B,MAAM,kBAAkB,OAAO;AAC7B,YAAM,aAAa,MAAM,kBAAkB,MAAM,aAAa;AAC9D,UAAI,CAAC,YAAY;AACf,eAAO,EAAE;AAAA,UACP,MAAM;AAAA,UACN,4BAA4B,MAAM,aAAa;AAAA,QACjD;AACA;AAAA,MACF;AAEA,YAAM,iBAAiB,MAAM,SAAS,IAAI,kBAAkB;AAAA,QAC1D,aAAa;AAAA,QACb,QAAQ,WAAW;AAAA,MACrB,CAAC;AACD,aAAO,EAAE,wBAAwB,MAAM,OAAO,UAAU,cAAc,CAAC;AAAA,IACzE;AAAA,IACA,yBAAyB,MAAM;AAAA,IAC/B,MAAM,mBAAmB,OAAO;AAC9B,YAAM,aAAa,MAAM,kBAAkB,MAAM,aAAa;AAC9D,UAAI,CAAC,YAAY;AACf;AAAA,MACF;AAEA,eAAS,IAAI,IAAI,mBAAmB;AAAA,QAClC,KAAK;AAAA,QACL,aAAa;AAAA,QACb,QAAQ,WAAW;AAAA,QACnB,MAAM,MAAM;AAAA,QACZ,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,OAAO,gBAAgB,MAAM,OAAO,MAAM,SAAS;AAAA,QACrD;AAAA,QACA,MAAM,MAAM;AAAA,QACZ,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AAAA,IACA,MAAM,mBAAmB,OAAO;AAC9B,YAAM,aAAa,MAAM,kBAAkB,MAAM,aAAa;AAC9D,UAAI,CAAC,YAAY;AACf;AAAA,MACF;AAEA,UAAI,2BAA2B;AAC7B,qBAAa,yBAAyB;AAAA,MACxC;AAEA,0BAAoB,sBAAsB,EAAE,KAAK,WAAW,GAAG,CAAC;AAChE,kCAA4B,WAAW,MAAM;AAC3C,4BAAoB,sBAAsB;AAAA,MAC5C,GAAG,4BAA4B;AAAA,IACjC;AAAA,IACA,cAAc,OAAO;AACnB,aAAO,EAAE;AAAA,QACP,MAAM;AAAA,QACN,KAAK,UAAU,oBAAoB,MAAM,CAAC;AAAA,MAC5C;AAAA,IACF;AAAA,IACA,qBAAqB,MAAM;AAAA,IAC3B,MAAM,aAAa,OAAO;AACxB,YAAM,gBAAgB,MAAM;AAAA,QAA0B,MACpD,SAAS,IAAI,iBAAiB;AAAA,UAC5B,aAAa;AAAA,UACb,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AACA,aAAO,EAAE,mBAAmB,MAAM,OAAO,aAAa;AAAA,IACxD;AAAA,IACA,oBAAoB,MAAM;AAAA,IAC1B,MAAM,cAAc,OAAO;AACzB,YAAM,SAAS,MAAM,0BAA0B,YAAY;AACzD,cAAM,UAAU;AAAA,UACd,aAAa;AAAA,UACb,QAAQ,MAAM;AAAA,QAChB;AACA,cAAM,YAAY,aAAa,QAAQ,WAAW;AAElD,YAAI,WAAW;AACb,oBAAU,iBAAiB,QAAQ;AAAA,QACrC;AAEA,eAAO,SAAS,IAAI,IAAI,kBAAkB,OAAO;AAAA,MACnD,CAAC;AACD,aAAO,EAAE,mBAAmB,MAAM,OAAO,UAAU,MAAM,CAAC;AAAA,IAC5D;AAAA,IACA,oBAAoB,MAAM;AAAA,IAC1B,MAAM,kBAAkB,OAAO;AAC7B,YAAM,YAAY,wBAAwB;AAE1C,UAAI,CAAC,WAAW;AACd,eAAO,EAAE;AAAA,UACP,MAAM;AAAA,UACN,kCAAkC;AAAA,QACpC;AACA;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,MAAM,UAAU,WAAW;AAAA,UACxC,YAAY,MAAM;AAAA,UAClB,eAAe,MAAM;AAAA,UACrB,eAAe,MAAM;AAAA,QACvB,CAAC;AACD,eAAO,EAAE,sBAAsB,MAAM,OAAO,MAAM;AAAA,MACpD,SAAS,OAAO;AACd,eAAO,EAAE;AAAA,UACP,MAAM;AAAA,UACN,uBAAuB,KAAK;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,IACA,uBAAuB,MAAM;AAAA,IAC7B,0BAA0B,OAAO;AAC/B,YAAM,YAAY,wBAAwB;AAE1C,UAAI,CAAC,WAAW;AACd,eAAO,EAAE;AAAA,UACP,MAAM;AAAA,UACN,kCAAkC;AAAA,QACpC;AACA;AAAA,MACF;AAEA,UAAI;AACF,cAAM,cAAc,UAAU,MAAM;AAAA,UAClC,eAAe,MAAM;AAAA,UACrB,eAAe,MAAM;AAAA,QACvB,CAAC;AACD,eAAO,EAAE,8BAA8B,MAAM,OAAO;AAAA,UAClD,IAAI;AAAA,UACJ;AAAA,UACA,WAAW,KAAK,IAAI;AAAA,UACpB,QAAQ;AAAA,QACV,CAAC;AAAA,MACH,SAAS,OAAO;AACd,eAAO,EAAE;AAAA,UACP,MAAM;AAAA,UACN,uBAAuB,KAAK;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,IACA,+BAA+B,MAAM;AAAA,IACrC,yBAAyB,OAAO;AAC9B,YAAM,YAAY,wBAAwB;AAE1C,UAAI,CAAC,WAAW;AACd,eAAO,EAAE;AAAA,UACP,MAAM;AAAA,UACN,kCAAkC;AAAA,QACpC;AACA;AAAA,MACF;AAEA,UAAI;AACF,cAAM,SAAS,UAAU,KAAK,MAAM,WAAW;AAC/C,eAAO,EAAE,8BAA8B,MAAM,OAAO,MAAM;AAAA,MAC5D,SAAS,OAAO;AACd,eAAO,EAAE;AAAA,UACP,MAAM;AAAA,UACN,uBAAuB,KAAK;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,IACA,+BAA+B,MAAM;AAAA,EACvC;AACF;AAQA,SAAS,cACP,QACA,MACA,OACM;AACN,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM;AAClD;AAAA,EACF;AAEA,QAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAC/C,QAAM,UAAU,KAAK,GAAG,EAAE;AAE1B,MAAI,CAAC,SAAS;AACZ;AAAA,EACF;AAEA;AAAC,EAAC,OAAmC,OAAO,IAAI;AAClD;AAQA,SAAS,gBAAgB,OAAe,WAA4B;AAClE,MAAI,cAAc,UAAU;AAC1B,WAAO,OAAO,KAAK;AAAA,EACrB;AAEA,MAAI,cAAc,WAAW;AAC3B,WAAO,UAAU;AAAA,EACnB;AAEA,MAAI,cAAc,YAAY,cAAc,SAAS;AACnD,QAAI;AACF,aAAO,KAAK,MAAM,KAAK;AAAA,IACzB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAQA,SAAS,oBAAoB,MAAc,SAAyB;AAClE,QAAM,QAAQ,SAAS,IAAI;AAG3B,QAAM,SAAS,MAAM,OAAO;AAC9B;AAQA,SAAS,oCAGP;AACA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,EACT;AACF;AAOA,SAAS,uBAAuB,OAG9B;AACA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,EAC9D;AACF;AAOA,eAAe,kBACb,eAC0E;AAC1E,QAAM,gBAAgB,MAAM,SAAS,IAAI,iBAAiB;AAAA,IACxD,aAAa;AAAA,IACb,QAAQ;AAAA,EACV,CAAC;AACD,QAAM,QAAQ,YAAY,cAAc,CAAC,CAAC;AAE1C,SAAO,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,aAAa;AACzD;AAOA,SAAS,YACP,MAC4D;AAC5D,QAAM,SAAqE,CAAC;AAE5E,QAAM,WAAW,CAAC,SAAwB;AACxC,QAAI,CAAC,gBAAgB,IAAI,GAAG;AAC1B;AAAA,IACF;AAEA,WAAO,KAAK,IAAI;AAChB,SAAK,UAAU,QAAQ,CAAC,UAAU;AAChC,eAAS,KAAK;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,WAAS,IAAI;AACb,SAAO;AACT;AAOA,SAAS,gBACP,MAC6D;AAC7D,SAAO;AAAA,IACL,QACA,OAAO,SAAS,YAChB,OAAQ,KAA0B,OAAO;AAAA,EAC3C;AACF;AAOA,eAAe,0BACb,UACY;AACZ,QAAM,sBAAsB,cAAc;AAE1C,MAAI,qBAAqB;AACvB,uBAAmB,KAAK;AAAA,EAC1B;AAEA,MAAI;AACF,WAAO,MAAM,SAAS;AAAA,EACxB,UAAE;AACA,QAAI,qBAAqB;AACvB,yBAAmB,IAAI;AAAA,IACzB;AAAA,EACF;AACF;AAOA,SAAS,4BAA4B,eAGnC;AACA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO,wBAAwB,aAAa;AAAA,EAC9C;AACF;;;AlBvYA,eAAsB,mBACpB,iBAAuC;AAAA,EACrC,eAAe,gBAAgB;AACjC,GACe;AACf,4BAA0B;AAE1B,QAAM,MAAM,MAAM,iBAAiB,4BAA4B,GAAG;AAElE,MAAI,CAAC,KAAK;AACR;AAAA,EACF;AAEA,mBAAiB,GAAG;AACpB,uBAAqB,eAAe,aAAa;AAEjD,QAAM,WAAW,uBAAuB;AAAA,IACtC,MAAM,OAAO,SAAS;AAAA,IACtB,OAAO,SAAS;AAAA,IAChB,iBAAiB,mBAAmB,OAAO,gBAAgB,MAAM;AAAA,IACjE,YAAY,OAAO;AAAA,IACnB,aAAa,OAAO;AAAA,IACpB,YAAY,SAAS;AAAA,EACvB,CAAC;AAED;AAAA,IACE,6BAA6B;AAAA,MAC3B,MAAM,eAAe,eAAe;AAAA,MACpC,UAAU;AAAA,MACV,cAAc,UAAU;AACtB,eAAO,SAAS,cAAc,QAAQ;AAAA,MACxC;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,KAAK,8BAA8B,QAAQ;AAC/C,8BAA4B;AAAA,IAC1B,QAAQ,SAAS;AAAA,IACjB,MAAM,IAAI,KAAK,KAAK,GAAG;AAAA,EACzB,CAAC;AACD,yBAAuB;AAAA,IACrB,QAAQ,SAAS;AAAA,IACjB,KAAK,QAAQ;AACX,UAAI,KAAK,+CAA+C,MAAM;AAAA,IAChE;AAAA,EACF,CAAC;AACD,qBAAmB;AAAA,IACjB,QAAQ,SAAS;AAAA,IACjB,KAAK,QAAQ;AACX,UAAI,KAAK,2CAA2C,MAAM;AAAA,IAC5D;AAAA,EACF,CAAC;AACD,qBAAmB;AAAA,IACjB,QAAQ,SAAS;AAAA,IACjB,aAAa;AAAA,IACb,aAAa,CAAC,iBAAiB,UAAU,YAAY;AAAA,IACrD,KAAK,QAAQ;AACX,UAAI,KAAK,2CAA2C,MAAM;AAAA,IAC5D;AAAA,EACF,CAAC;AACH;AAOA,SAAS,4BAA4B,SAG5B;AACP,MAAI,eAAe;AACnB,QAAM,iBAAiB,YAAY,MAAM;AACvC,YAAQ,KAAK,8BAA8B;AAAA,MACzC,QAAQ,QAAQ;AAAA,MAChB,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH,GAAG,0CAA0C;AAE7C,QAAM,aAAa,MAAY;AAC7B,QAAI,cAAc;AAChB;AAAA,IACF;AAEA,mBAAe;AACf,kBAAc,cAAc;AAC5B,YAAQ,KAAK,iCAAiC;AAAA,MAC5C,QAAQ,QAAQ;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,SAAO,iBAAiB,YAAY,YAAY,EAAE,MAAM,KAAK,CAAC;AAC9D,SAAO,iBAAiB,gBAAgB,YAAY,EAAE,MAAM,KAAK,CAAC;AACpE;","names":["nanoid","nanoid","nanoid","nanoid","nanoid","nanoid","nanoid"]}