@xiaou66/vite-plugin-vue-mcp-next 1.1.0 → 1.1.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.
package/dist/index.cjs CHANGED
@@ -94,6 +94,11 @@ var RESOLVED_VIRTUAL_SNAPDOM_LOADER_ID = `\0${VIRTUAL_SNAPDOM_LOADER_ID}`;
94
94
  var DEFAULT_MCP_CLIENT_SERVER_NAME = "vite-mcp-next";
95
95
  var LEGACY_MCP_CLIENT_SERVER_NAMES = ["vue-mcp-next"];
96
96
  var RUNTIME_PAGE_RECONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-reconnected";
97
+ var RUNTIME_PAGE_CONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-connected";
98
+ var RUNTIME_PAGE_DISCONNECTED_EVENT = "vite-plugin-vue-mcp-next:page-disconnected";
99
+ var RUNTIME_PAGE_HEARTBEAT_EVENT = "vite-plugin-vue-mcp-next:heartbeat";
100
+ var DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS = 45e3;
101
+ var DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS = 45e3;
97
102
  var DEFAULT_OPTIONS = {
98
103
  mcpPath: DEFAULT_MCP_PATH,
99
104
  host: "localhost",
@@ -2949,32 +2954,53 @@ function vueMcpNext(userOptions = {}) {
2949
2954
  () => createMcpServer(ctx, server),
2950
2955
  server
2951
2956
  );
2952
- server.ws.on(
2953
- "vite-plugin-vue-mcp-next:page-connected",
2954
- (payload) => {
2955
- if (isRuntimePageTarget(payload)) {
2956
- ctx.pages.upsert(payload);
2957
- void ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, payload);
2958
- void cdpLifecycle.connectPage(payload);
2957
+ const lastSeenAt = /* @__PURE__ */ new Map();
2958
+ const heartbeatTimer = setInterval(() => {
2959
+ const now = Date.now();
2960
+ for (const [pageId, seenAt] of lastSeenAt) {
2961
+ const target = ctx.pages.get(pageId);
2962
+ if (!target || target.source !== "runtime" || !target.connected) {
2963
+ lastSeenAt.delete(pageId);
2964
+ continue;
2959
2965
  }
2960
- }
2961
- );
2962
- server.ws.on(
2963
- "vite-plugin-vue-mcp-next:console-record",
2964
- (payload) => {
2965
- if (isConsoleRecord(payload)) {
2966
- ctx.consoleRecords.push(payload);
2966
+ if (now - seenAt >= DEFAULT_RUNTIME_PAGE_HEARTBEAT_TIMEOUT_MS) {
2967
+ ctx.pages.disconnect(pageId, now);
2968
+ lastSeenAt.delete(pageId);
2967
2969
  }
2968
2970
  }
2969
- );
2970
- server.ws.on(
2971
- "vite-plugin-vue-mcp-next:network-record",
2972
- (payload) => {
2973
- if (isNetworkRecord(payload)) {
2974
- ctx.networkRecords.push(payload);
2971
+ }, DEFAULT_RUNTIME_PAGE_HEARTBEAT_SCAN_INTERVAL_MS);
2972
+ server.ws.on(RUNTIME_PAGE_CONNECTED_EVENT, (payload) => {
2973
+ if (isRuntimePageTarget(payload)) {
2974
+ ctx.pages.upsert(payload);
2975
+ lastSeenAt.set(payload.pageId, Date.now());
2976
+ void ctx.hooks.callHook(RUNTIME_PAGE_RECONNECTED_EVENT, payload);
2977
+ void cdpLifecycle.connectPage(payload);
2978
+ }
2979
+ });
2980
+ server.ws.on(RUNTIME_PAGE_HEARTBEAT_EVENT, (payload) => {
2981
+ if (isRuntimeHeartbeatTarget(payload)) {
2982
+ const target = ctx.pages.get(payload.pageId);
2983
+ if (target?.source === "runtime" && target.connected) {
2984
+ lastSeenAt.set(payload.pageId, payload.timestamp);
2975
2985
  }
2976
2986
  }
2977
- );
2987
+ });
2988
+ server.ws.on(RUNTIME_PAGE_DISCONNECTED_EVENT, (payload) => {
2989
+ if (isRuntimeDisconnectTarget(payload)) {
2990
+ ctx.pages.disconnect(payload.pageId);
2991
+ lastSeenAt.delete(payload.pageId);
2992
+ }
2993
+ });
2994
+ server.ws.on("vite-plugin-vue-mcp-next:console-record", (payload) => {
2995
+ if (isConsoleRecord(payload)) {
2996
+ ctx.consoleRecords.push(payload);
2997
+ }
2998
+ });
2999
+ server.ws.on("vite-plugin-vue-mcp-next:network-record", (payload) => {
3000
+ if (isNetworkRecord(payload)) {
3001
+ ctx.networkRecords.push(payload);
3002
+ }
3003
+ });
2978
3004
  server.ws.on(
2979
3005
  "vite-plugin-vue-mcp-next:performance-record",
2980
3006
  (payload) => {
@@ -3004,6 +3030,7 @@ function vueMcpNext(userOptions = {}) {
3004
3030
  }, 300);
3005
3031
  }
3006
3032
  server.httpServer?.once("close", () => {
3033
+ clearInterval(heartbeatTimer);
3007
3034
  void cdpLifecycle.closeAll();
3008
3035
  });
3009
3036
  },
@@ -3028,6 +3055,20 @@ function isRuntimePageTarget(payload) {
3028
3055
  const target = payload;
3029
3056
  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");
3030
3057
  }
3058
+ function isRuntimeHeartbeatTarget(payload) {
3059
+ if (!payload || typeof payload !== "object") {
3060
+ return false;
3061
+ }
3062
+ const target = payload;
3063
+ return typeof target.pageId === "string" && typeof target.timestamp === "number";
3064
+ }
3065
+ function isRuntimeDisconnectTarget(payload) {
3066
+ if (!payload || typeof payload !== "object") {
3067
+ return false;
3068
+ }
3069
+ const target = payload;
3070
+ return typeof target.pageId === "string";
3071
+ }
3031
3072
  function isConsoleRecord(payload) {
3032
3073
  if (!payload || typeof payload !== "object") {
3033
3074
  return false;