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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -35,6 +35,11 @@ var MCP_TOOL_NAMES = {
35
35
  getNetworkRequests: "get_network_requests",
36
36
  getNetworkRequestDetail: "get_network_request_detail",
37
37
  clearNetworkRequests: "clear_network_requests",
38
+ listStorage: "list_storage",
39
+ getStorageItem: "get_storage_item",
40
+ setStorageItem: "set_storage_item",
41
+ deleteStorageItem: "delete_storage_item",
42
+ clearStorage: "clear_storage",
38
43
  recordPerformance: "record_performance",
39
44
  startPerformanceRecording: "start_performance_recording",
40
45
  stopPerformanceRecording: "stop_performance_recording",
@@ -57,11 +62,6 @@ var RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID = `\0${VIRTUAL_SNAPDOM_LOADER_ID}`;
57
62
  var DEFAULT_MCP_CLIENT_SERVER_NAME = "vite-mcp-next";
58
63
  var LEGACY_MCP_CLIENT_SERVER_NAMES = ["vue-mcp-next"];
59
64
  var RUNTIME_PAGE_RECONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-reconnected";
60
- var RUNTIME_PAGE_CONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-connected";
61
- var RUNTIME_PAGE_DISCONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-disconnected";
62
- var RUNTIME_PAGE_HEARTBEAT_EVENT = "vite-plugin-vue-mcp-next:heartbeat";
63
- var DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS = 45e3;
64
- var DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS = 45e3;
65
65
  var DEFAULT_OPTIONS = {
66
66
  mcpPath: DEFAULT_MCP_PATH,
67
67
  host: "localhost",
@@ -1511,9 +1511,431 @@ function getPathname(url) {
1511
1511
  }
1512
1512
  }
1513
1513
 
1514
- // src/mcp/tools/screenshot.ts
1514
+ // src/mcp/tools/storage.ts
1515
1515
  import { z as z7 } from "zod";
1516
1516
 
1517
+ // src/cdp/cdpStorage.ts
1518
+ function createCdpStorageAdapter(client) {
1519
+ return {
1520
+ async manageStorage(request) {
1521
+ try {
1522
+ return await manageCdpStorage(client, request);
1523
+ } catch (error) {
1524
+ return createCdpStorageError(
1525
+ request,
1526
+ error instanceof Error ? error.message : String(error)
1527
+ );
1528
+ }
1529
+ }
1530
+ };
1531
+ }
1532
+ async function manageCdpStorage(client, request) {
1533
+ if (request.scope === "cookie") {
1534
+ return manageCdpCookies(client, request);
1535
+ }
1536
+ if (request.scope === "indexedDB") {
1537
+ return manageCdpIndexedDb(client, request);
1538
+ }
1539
+ return manageCdpDomStorage(client, request);
1540
+ }
1541
+ async function manageCdpCookies(client, request) {
1542
+ if (request.action === "list" || request.action === "get") {
1543
+ const result2 = await client.Storage.getCookies();
1544
+ const cookies2 = result2.cookies.filter(
1545
+ (cookie) => isCookieInOrigin(cookie, request.origin)
1546
+ );
1547
+ return createCdpStorageSuccess(request, {
1548
+ origin: request.origin,
1549
+ cookies: request.action === "get" && request.cookie?.name ? cookies2.filter((cookie) => cookie.name === request.cookie?.name) : cookies2
1550
+ });
1551
+ }
1552
+ if (request.action === "set") {
1553
+ if (!request.cookie?.name) {
1554
+ throw new Error("Cookie name is required for set operation");
1555
+ }
1556
+ await client.Storage.setCookies({
1557
+ cookies: [
1558
+ {
1559
+ name: request.cookie.name,
1560
+ value: request.cookie.value ?? request.value ?? "",
1561
+ url: request.cookie.url ?? request.origin,
1562
+ domain: request.cookie.domain,
1563
+ path: request.cookie.path,
1564
+ httpOnly: request.cookie.httpOnly,
1565
+ secure: request.cookie.secure,
1566
+ sameSite: normalizeCookieSameSite(request.cookie.sameSite),
1567
+ expires: request.cookie.expires
1568
+ }
1569
+ ]
1570
+ });
1571
+ return createCdpStorageSuccess(request, { ok: true });
1572
+ }
1573
+ const result = await client.Storage.getCookies();
1574
+ const cookies = result.cookies.filter(
1575
+ (cookie) => isCookieInOrigin(cookie, request.origin)
1576
+ );
1577
+ const candidates = request.action === "delete" && request.cookie?.name ? cookies.filter((cookie) => cookie.name === request.cookie?.name) : cookies;
1578
+ const deletable = candidates.filter((cookie) => !cookie.httpOnly);
1579
+ const skippedHttpOnlyCount = candidates.length - deletable.length;
1580
+ for (const cookie of deletable) {
1581
+ await client.Network.deleteCookies({
1582
+ name: cookie.name,
1583
+ domain: cookie.domain,
1584
+ path: cookie.path
1585
+ });
1586
+ }
1587
+ return createCdpStorageSuccess(request, {
1588
+ deletedCount: deletable.length,
1589
+ skippedHttpOnlyCount
1590
+ });
1591
+ }
1592
+ async function manageCdpDomStorage(client, request) {
1593
+ const storageId = {
1594
+ securityOrigin: request.origin,
1595
+ isLocalStorage: request.scope === "localStorage"
1596
+ };
1597
+ if (request.action === "list") {
1598
+ const result2 = await client.DOMStorage.getDOMStorageItems({ storageId });
1599
+ return createCdpStorageSuccess(request, {
1600
+ origin: request.origin,
1601
+ scope: request.scope,
1602
+ entries: result2.entries.map(([key, value]) => ({ key, value }))
1603
+ });
1604
+ }
1605
+ if (request.action === "get") {
1606
+ assertStorageKey(request);
1607
+ const result2 = await client.DOMStorage.getDOMStorageItems({ storageId });
1608
+ const entry = result2.entries.find(([key]) => key === request.key);
1609
+ return createCdpStorageSuccess(request, {
1610
+ key: request.key,
1611
+ value: entry?.[1] ?? null
1612
+ });
1613
+ }
1614
+ if (request.action === "set") {
1615
+ assertStorageKey(request);
1616
+ await client.DOMStorage.setDOMStorageItem({
1617
+ storageId,
1618
+ key: request.key,
1619
+ value: request.value ?? ""
1620
+ });
1621
+ return createCdpStorageSuccess(request, { ok: true });
1622
+ }
1623
+ if (request.action === "delete") {
1624
+ assertStorageKey(request);
1625
+ await client.DOMStorage.removeDOMStorageItem({
1626
+ storageId,
1627
+ key: request.key
1628
+ });
1629
+ return createCdpStorageSuccess(request, { ok: true });
1630
+ }
1631
+ const result = await client.DOMStorage.getDOMStorageItems({ storageId });
1632
+ for (const [key] of result.entries) {
1633
+ await client.DOMStorage.removeDOMStorageItem({ storageId, key });
1634
+ }
1635
+ return createCdpStorageSuccess(request, { deletedCount: result.entries.length });
1636
+ }
1637
+ async function manageCdpIndexedDb(client, request) {
1638
+ if (request.action === "list") {
1639
+ const result = await client.IndexedDB.requestDatabaseNames({
1640
+ securityOrigin: request.origin
1641
+ });
1642
+ return createCdpStorageSuccess(request, {
1643
+ origin: request.origin,
1644
+ databases: result.databaseNames
1645
+ });
1646
+ }
1647
+ assertIndexedDbTarget(request);
1648
+ if (request.action === "get") {
1649
+ const result = await client.IndexedDB.requestData({
1650
+ securityOrigin: request.origin,
1651
+ databaseName: request.databaseName,
1652
+ objectStoreName: request.objectStoreName,
1653
+ indexName: request.indexName ?? "",
1654
+ skipCount: 0,
1655
+ pageSize: 100
1656
+ });
1657
+ return createCdpStorageSuccess(request, {
1658
+ entries: result.objectStoreDataEntries,
1659
+ hasMore: result.hasMore
1660
+ });
1661
+ }
1662
+ if (request.action === "delete") {
1663
+ assertStorageKey(request);
1664
+ await client.IndexedDB.deleteObjectStoreEntries({
1665
+ securityOrigin: request.origin,
1666
+ databaseName: request.databaseName,
1667
+ objectStoreName: request.objectStoreName,
1668
+ keyRange: createExactCdpKeyRange(request.key)
1669
+ });
1670
+ return createCdpStorageSuccess(request, { ok: true });
1671
+ }
1672
+ if (request.action === "clear") {
1673
+ if (request.objectStoreName) {
1674
+ await client.IndexedDB.clearObjectStore({
1675
+ securityOrigin: request.origin,
1676
+ databaseName: request.databaseName,
1677
+ objectStoreName: request.objectStoreName
1678
+ });
1679
+ return createCdpStorageSuccess(request, { ok: true });
1680
+ }
1681
+ await client.IndexedDB.deleteDatabase({
1682
+ securityOrigin: request.origin,
1683
+ databaseName: request.databaseName
1684
+ });
1685
+ return createCdpStorageSuccess(request, { ok: true });
1686
+ }
1687
+ return createCdpStorageError(
1688
+ request,
1689
+ "IndexedDB set operation requires runtime bridge"
1690
+ );
1691
+ }
1692
+ function isCookieInOrigin(cookie, origin) {
1693
+ const hostname = new URL(origin).hostname;
1694
+ const domain = cookie.domain?.replace(/^\./, "");
1695
+ return Boolean(domain && (hostname === domain || hostname.endsWith(`.${domain}`)));
1696
+ }
1697
+ function normalizeCookieSameSite(sameSite) {
1698
+ if (!sameSite) {
1699
+ return void 0;
1700
+ }
1701
+ if (sameSite === "strict") {
1702
+ return "Strict";
1703
+ }
1704
+ if (sameSite === "lax") {
1705
+ return "Lax";
1706
+ }
1707
+ return "None";
1708
+ }
1709
+ function createExactCdpKeyRange(key) {
1710
+ const parsedKey = parseJsonValue(key);
1711
+ return {
1712
+ lower: parsedKey,
1713
+ upper: parsedKey,
1714
+ lowerOpen: false,
1715
+ upperOpen: false
1716
+ };
1717
+ }
1718
+ function parseJsonValue(value) {
1719
+ try {
1720
+ return JSON.parse(value);
1721
+ } catch {
1722
+ return value;
1723
+ }
1724
+ }
1725
+ function assertStorageKey(request) {
1726
+ if (!request.key) {
1727
+ throw new Error("Storage key is required for this operation");
1728
+ }
1729
+ }
1730
+ function assertIndexedDbTarget(request) {
1731
+ if (!request.databaseName || !request.objectStoreName) {
1732
+ throw new Error("IndexedDB databaseName and objectStoreName are required");
1733
+ }
1734
+ }
1735
+ function createCdpStorageSuccess(request, data) {
1736
+ return {
1737
+ ok: true,
1738
+ source: "cdp",
1739
+ action: request.action,
1740
+ scope: request.scope,
1741
+ data
1742
+ };
1743
+ }
1744
+ function createCdpStorageError(request, error) {
1745
+ return {
1746
+ ok: false,
1747
+ source: "cdp",
1748
+ action: request.action,
1749
+ scope: request.scope,
1750
+ error
1751
+ };
1752
+ }
1753
+
1754
+ // src/mcp/tools/storage.ts
1755
+ function registerStorageTools(server, ctx) {
1756
+ registerStorageTool(server, MCP_TOOL_NAMES.listStorage, {
1757
+ description: "List same-origin storage and CDP cookies when available.",
1758
+ inputSchema: {
1759
+ pageId: z7.string().optional()
1760
+ },
1761
+ action: "list",
1762
+ handler: (input) => handleListStorage(ctx, input.pageId)
1763
+ });
1764
+ registerStorageTool(server, MCP_TOOL_NAMES.getStorageItem, {
1765
+ description: "Read one storage entry.",
1766
+ inputSchema: createStorageInputSchema(),
1767
+ action: "get",
1768
+ handler: (input) => handleStorageAction(ctx, { ...input, action: "get" })
1769
+ });
1770
+ registerStorageTool(server, MCP_TOOL_NAMES.setStorageItem, {
1771
+ description: "Write one storage entry.",
1772
+ inputSchema: createStorageInputSchema(),
1773
+ action: "set",
1774
+ handler: (input) => handleStorageAction(ctx, { ...input, action: "set" })
1775
+ });
1776
+ registerStorageTool(server, MCP_TOOL_NAMES.deleteStorageItem, {
1777
+ description: "Delete one storage entry.",
1778
+ inputSchema: createStorageInputSchema(),
1779
+ action: "delete",
1780
+ handler: (input) => handleStorageAction(ctx, { ...input, action: "delete" })
1781
+ });
1782
+ registerStorageTool(server, MCP_TOOL_NAMES.clearStorage, {
1783
+ description: "Clear one storage scope.",
1784
+ inputSchema: createStorageInputSchema(),
1785
+ action: "clear",
1786
+ handler: (input) => handleStorageAction(ctx, { ...input, action: "clear" })
1787
+ });
1788
+ }
1789
+ function registerStorageTool(server, name, options) {
1790
+ server.registerTool(
1791
+ name,
1792
+ {
1793
+ description: options.description,
1794
+ inputSchema: options.inputSchema
1795
+ },
1796
+ (async (input) => options.handler(
1797
+ input
1798
+ ))
1799
+ );
1800
+ }
1801
+ function createStorageInputSchema() {
1802
+ return {
1803
+ pageId: z7.string().optional(),
1804
+ scope: z7.enum(["localStorage", "sessionStorage", "indexedDB", "cookie"]).optional(),
1805
+ key: z7.string().optional(),
1806
+ value: z7.string().optional(),
1807
+ databaseName: z7.string().optional(),
1808
+ objectStoreName: z7.string().optional(),
1809
+ indexName: z7.string().optional(),
1810
+ cookie: z7.object({
1811
+ name: z7.string(),
1812
+ value: z7.string().optional(),
1813
+ domain: z7.string().optional(),
1814
+ path: z7.string().optional(),
1815
+ url: z7.string().optional(),
1816
+ httpOnly: z7.boolean().optional(),
1817
+ secure: z7.boolean().optional(),
1818
+ sameSite: z7.enum(["strict", "lax", "none"]).optional(),
1819
+ expires: z7.number().optional()
1820
+ }).optional()
1821
+ };
1822
+ }
1823
+ async function handleListStorage(ctx, pageId) {
1824
+ let baseRequest;
1825
+ try {
1826
+ baseRequest = createStorageRequest(ctx, {
1827
+ pageId,
1828
+ action: "list",
1829
+ scope: "localStorage"
1830
+ });
1831
+ } catch (error) {
1832
+ return createToolError(error instanceof Error ? error.message : String(error));
1833
+ }
1834
+ const [localStorage, sessionStorage, indexedDB] = await Promise.all([
1835
+ requestRuntimeStorage(ctx, { ...baseRequest, scope: "localStorage" }),
1836
+ requestRuntimeStorage(ctx, { ...baseRequest, scope: "sessionStorage" }),
1837
+ requestRuntimeStorage(ctx, { ...baseRequest, scope: "indexedDB" })
1838
+ ]);
1839
+ const cookie = await listCookiesIfCdpAvailable(ctx, baseRequest, pageId);
1840
+ return createToolResponse({
1841
+ ok: true,
1842
+ origin: baseRequest.origin,
1843
+ localStorage: extractStorageData(localStorage),
1844
+ sessionStorage: extractStorageData(sessionStorage),
1845
+ indexedDB: extractStorageData(indexedDB),
1846
+ cookie
1847
+ });
1848
+ }
1849
+ async function handleStorageAction(ctx, input) {
1850
+ let request;
1851
+ try {
1852
+ request = createStorageRequest(ctx, input);
1853
+ } catch (error) {
1854
+ return createToolError(error instanceof Error ? error.message : String(error));
1855
+ }
1856
+ const cdp = await connectCdpForPage(ctx, input.pageId);
1857
+ if (cdp && shouldUseCdpStorage(request)) {
1858
+ try {
1859
+ const result2 = await createCdpStorageAdapter(cdp.client).manageStorage(
1860
+ request
1861
+ );
1862
+ return createToolResponse(result2);
1863
+ } finally {
1864
+ await closeCdpClient(cdp.client);
1865
+ }
1866
+ }
1867
+ const result = await requestRuntimeStorage(ctx, request);
1868
+ return createToolResponse(result);
1869
+ }
1870
+ async function requestRuntimeStorage(ctx, request) {
1871
+ return requestRuntimeData(ctx, (event) => {
1872
+ void ctx.rpcServer?.manageStorage({
1873
+ ...request,
1874
+ event
1875
+ });
1876
+ });
1877
+ }
1878
+ async function listCookiesIfCdpAvailable(ctx, request, pageId) {
1879
+ if (!hasCdpConfig2(ctx)) {
1880
+ return extractStorageData(
1881
+ await requestRuntimeStorage(ctx, { ...request, scope: "cookie" })
1882
+ );
1883
+ }
1884
+ const cdp = await connectCdpForPage(ctx, pageId);
1885
+ if (!cdp) {
1886
+ return extractStorageData(
1887
+ await requestRuntimeStorage(ctx, { ...request, scope: "cookie" })
1888
+ );
1889
+ }
1890
+ try {
1891
+ const result = await createCdpStorageAdapter(cdp.client).manageStorage({
1892
+ ...request,
1893
+ scope: "cookie"
1894
+ });
1895
+ return extractStorageData(result);
1896
+ } finally {
1897
+ await closeCdpClient(cdp.client);
1898
+ }
1899
+ }
1900
+ function extractStorageData(result) {
1901
+ if (!isStorageResultRecord(result)) {
1902
+ return result;
1903
+ }
1904
+ return result.data ?? result;
1905
+ }
1906
+ function isStorageResultRecord(value) {
1907
+ return typeof value === "object" && value !== null && "ok" in value;
1908
+ }
1909
+ function shouldUseCdpStorage(request) {
1910
+ return request.scope === "cookie";
1911
+ }
1912
+ function createStorageRequest(ctx, input) {
1913
+ const page = resolvePageTarget(ctx, input.pageId);
1914
+ const origin = new URL(page.url).origin;
1915
+ return {
1916
+ event: "",
1917
+ pageId: page.pageId,
1918
+ origin,
1919
+ action: input.action,
1920
+ scope: normalizeScope(input.scope),
1921
+ key: input.key,
1922
+ value: input.value,
1923
+ databaseName: input.databaseName,
1924
+ objectStoreName: input.objectStoreName,
1925
+ indexName: input.indexName,
1926
+ cookie: input.cookie
1927
+ };
1928
+ }
1929
+ function normalizeScope(scope) {
1930
+ return scope ?? "localStorage";
1931
+ }
1932
+ function hasCdpConfig2(ctx) {
1933
+ return Boolean(ctx.options.cdp.browserUrl || ctx.options.cdp.wsEndpoint);
1934
+ }
1935
+
1936
+ // src/mcp/tools/screenshot.ts
1937
+ import { z as z8 } from "zod";
1938
+
1517
1939
  // src/cdp/cdpScreenshot.ts
1518
1940
  async function cdpCaptureScreenshot(options) {
1519
1941
  if (options.target === "element") {
@@ -1672,14 +2094,14 @@ function createProjectRelativePath(ctx, filePath) {
1672
2094
  var DEFAULT_SCREENSHOT_TARGET = "viewport";
1673
2095
  var DEFAULT_SCREENSHOT_FORMAT = "png";
1674
2096
  var screenshotInputSchema = {
1675
- pageId: z7.string().optional(),
1676
- target: z7.enum(["viewport", "fullPage", "element"]).optional(),
1677
- selector: z7.string().optional(),
1678
- format: z7.enum(["png", "jpeg", "webp"]).optional(),
1679
- prefer: z7.enum(["auto", "cdp", "runtime"]).optional(),
1680
- quality: z7.number().optional(),
1681
- scale: z7.number().optional(),
1682
- snapdom: z7.record(z7.string(), z7.unknown()).optional()
2097
+ pageId: z8.string().optional(),
2098
+ target: z8.enum(["viewport", "fullPage", "element"]).optional(),
2099
+ selector: z8.string().optional(),
2100
+ format: z8.enum(["png", "jpeg", "webp"]).optional(),
2101
+ prefer: z8.enum(["auto", "cdp", "runtime"]).optional(),
2102
+ quality: z8.number().optional(),
2103
+ scale: z8.number().optional(),
2104
+ snapdom: z8.record(z8.string(), z8.unknown()).optional()
1683
2105
  };
1684
2106
  function registerScreenshotTools(server, ctx) {
1685
2107
  server.registerTool(
@@ -1799,7 +2221,7 @@ function isScreenshotImagePayload(result) {
1799
2221
 
1800
2222
  // src/mcp/tools/vue.ts
1801
2223
  import { nanoid as nanoid3 } from "nanoid";
1802
- import { z as z8 } from "zod";
2224
+ import { z as z9 } from "zod";
1803
2225
  function registerVueTools(server, ctx) {
1804
2226
  server.registerTool(
1805
2227
  MCP_TOOL_NAMES.getComponentTree,
@@ -1812,7 +2234,7 @@ function registerVueTools(server, ctx) {
1812
2234
  MCP_TOOL_NAMES.getComponentState,
1813
2235
  {
1814
2236
  description: "Get Vue component state.",
1815
- inputSchema: { componentName: z8.string() }
2237
+ inputSchema: { componentName: z9.string() }
1816
2238
  },
1817
2239
  async ({ componentName }) => requestVueData(ctx, (event) => {
1818
2240
  void ctx.rpcServer?.getInspectorState({ event, componentName });
@@ -1823,10 +2245,10 @@ function registerVueTools(server, ctx) {
1823
2245
  {
1824
2246
  description: "Edit Vue component state.",
1825
2247
  inputSchema: {
1826
- componentName: z8.string(),
1827
- path: z8.array(z8.string()),
1828
- value: z8.string(),
1829
- valueType: z8.enum(["string", "number", "boolean", "object", "array"])
2248
+ componentName: z9.string(),
2249
+ path: z9.array(z9.string()),
2250
+ value: z9.string(),
2251
+ valueType: z9.enum(["string", "number", "boolean", "object", "array"])
1830
2252
  }
1831
2253
  },
1832
2254
  ({ componentName, path: path8, value, valueType }) => {
@@ -1846,7 +2268,7 @@ function registerVueTools(server, ctx) {
1846
2268
  MCP_TOOL_NAMES.highlightComponent,
1847
2269
  {
1848
2270
  description: "Highlight a Vue component.",
1849
- inputSchema: { componentName: z8.string() }
2271
+ inputSchema: { componentName: z9.string() }
1850
2272
  },
1851
2273
  ({ componentName }) => {
1852
2274
  if (!ctx.rpcServer) {
@@ -1874,7 +2296,7 @@ function registerVueTools(server, ctx) {
1874
2296
  MCP_TOOL_NAMES.getPiniaState,
1875
2297
  {
1876
2298
  description: "Get Pinia store state.",
1877
- inputSchema: { storeName: z8.string() }
2299
+ inputSchema: { storeName: z9.string() }
1878
2300
  },
1879
2301
  async ({ storeName }) => requestVueData(ctx, (event) => {
1880
2302
  void ctx.rpcServer?.getPiniaState({ event, storeName });
@@ -1921,6 +2343,7 @@ function createMcpServer(ctx, vite) {
1921
2343
  registerConsoleTools(server, ctx);
1922
2344
  registerEvaluateTools(server, ctx);
1923
2345
  registerNetworkTools(server, ctx);
2346
+ registerStorageTools(server, ctx);
1924
2347
  registerPerformanceTools(server, ctx);
1925
2348
  registerVueTools(server, ctx);
1926
2349
  return server;
@@ -2009,6 +2432,10 @@ function createServerVueRuntimeRpc(ctx) {
2009
2432
  onScreenshotTaken: (event, data) => {
2010
2433
  void ctx.hooks.callHook(event, data);
2011
2434
  },
2435
+ manageStorage: () => void 0,
2436
+ onStorageUpdated: (event, data) => {
2437
+ void ctx.hooks.callHook(event, data);
2438
+ },
2012
2439
  recordPerformance: () => void 0,
2013
2440
  onPerformanceRecorded: (event, data) => {
2014
2441
  void ctx.hooks.callHook(event, data);
@@ -2917,53 +3344,32 @@ function vueMcpNext(userOptions = {}) {
2917
3344
  () => createMcpServer(ctx, server),
2918
3345
  server
2919
3346
  );
2920
- const lastSeenAt = /* @__PURE__ */ new Map();
2921
- const heartbeatTimer = setInterval(() => {
2922
- const now = Date.now();
2923
- for (const [pageId, seenAt] of lastSeenAt) {
2924
- const target = ctx.pages.get(pageId);
2925
- if (!target || target.source !== "runtime" || !target.connected) {
2926
- lastSeenAt.delete(pageId);
2927
- continue;
2928
- }
2929
- if (now - seenAt >= DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS) {
2930
- ctx.pages.disconnect(pageId, now);
2931
- lastSeenAt.delete(pageId);
3347
+ server.ws.on(
3348
+ "vite-plugin-vue-mcp-next:page-connected",
3349
+ (payload) => {
3350
+ if (isRuntimePageTarget(payload)) {
3351
+ ctx.pages.upsert(payload);
3352
+ void ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, payload);
3353
+ void cdpLifecycle.connectPage(payload);
2932
3354
  }
2933
3355
  }
2934
- }, DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS);
2935
- server.ws.on(RUNTIME_PAGE_CONNECTED_EVENT, (payload) => {
2936
- if (isRuntimePageTarget(payload)) {
2937
- ctx.pages.upsert(payload);
2938
- lastSeenAt.set(payload.pageId, Date.now());
2939
- void ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, payload);
2940
- void cdpLifecycle.connectPage(payload);
2941
- }
2942
- });
2943
- server.ws.on(RUNTIME_PAGE_HEARTBEAT_EVENT, (payload) => {
2944
- if (isRuntimeHeartbeatTarget(payload)) {
2945
- const target = ctx.pages.get(payload.pageId);
2946
- if (target?.source === "runtime" && target.connected) {
2947
- lastSeenAt.set(payload.pageId, payload.timestamp);
3356
+ );
3357
+ server.ws.on(
3358
+ "vite-plugin-vue-mcp-next:console-record",
3359
+ (payload) => {
3360
+ if (isConsoleRecord(payload)) {
3361
+ ctx.consoleRecords.push(payload);
2948
3362
  }
2949
3363
  }
2950
- });
2951
- server.ws.on(RUNTIME_PAGE_DISCONNECTED_EVENT, (payload) => {
2952
- if (isRuntimeDisconnectTarget(payload)) {
2953
- ctx.pages.disconnect(payload.pageId);
2954
- lastSeenAt.delete(payload.pageId);
2955
- }
2956
- });
2957
- server.ws.on("vite-plugin-vue-mcp-next:console-record", (payload) => {
2958
- if (isConsoleRecord(payload)) {
2959
- ctx.consoleRecords.push(payload);
2960
- }
2961
- });
2962
- server.ws.on("vite-plugin-vue-mcp-next:network-record", (payload) => {
2963
- if (isNetworkRecord(payload)) {
2964
- ctx.networkRecords.push(payload);
3364
+ );
3365
+ server.ws.on(
3366
+ "vite-plugin-vue-mcp-next:network-record",
3367
+ (payload) => {
3368
+ if (isNetworkRecord(payload)) {
3369
+ ctx.networkRecords.push(payload);
3370
+ }
2965
3371
  }
2966
- });
3372
+ );
2967
3373
  server.ws.on(
2968
3374
  "vite-plugin-vue-mcp-next:performance-record",
2969
3375
  (payload) => {
@@ -2993,7 +3399,6 @@ function vueMcpNext(userOptions = {}) {
2993
3399
  }, 300);
2994
3400
  }
2995
3401
  server.httpServer?.once("close", () => {
2996
- clearInterval(heartbeatTimer);
2997
3402
  void cdpLifecycle.closeAll();
2998
3403
  });
2999
3404
  },
@@ -3018,20 +3423,6 @@ function isRuntimePageTarget(payload) {
3018
3423
  const target = payload;
3019
3424
  return target.source === "runtime" && typeof target.pageId === "string" && typeof target.url === "string" && typeof target.pathname === "string" && typeof target.connected === "boolean" && (target.runtimeClientId === void 0 || typeof target.runtimeClientId === "string");
3020
3425
  }
3021
- function isRuntimeHeartbeatTarget(payload) {
3022
- if (!payload || typeof payload !== "object") {
3023
- return false;
3024
- }
3025
- const target = payload;
3026
- return typeof target.pageId === "string" && typeof target.timestamp === "number";
3027
- }
3028
- function isRuntimeDisconnectTarget(payload) {
3029
- if (!payload || typeof payload !== "object") {
3030
- return false;
3031
- }
3032
- const target = payload;
3033
- return typeof target.pageId === "string";
3034
- }
3035
3426
  function isConsoleRecord(payload) {
3036
3427
  if (!payload || typeof payload !== "object") {
3037
3428
  return false;