@0x1f320.sh/why-did-you-render-mcp 1.0.0-dev.3 → 1.0.0-dev.5

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,14 +1,69 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/client/utils/describe-value.ts
3
+ const MAX_DEPTH = 8;
4
+ function serialize(value, seen, depth) {
5
+ if (value === null) return null;
6
+ if (value === void 0) return null;
7
+ if (typeof value === "function") return {
8
+ type: "function",
9
+ name: value.name || "anonymous"
10
+ };
11
+ if (typeof value === "boolean") return value;
12
+ if (typeof value === "number") {
13
+ if (Number.isNaN(value)) return "NaN";
14
+ if (!Number.isFinite(value)) return value > 0 ? "Infinity" : "-Infinity";
15
+ if (Object.is(value, -0)) return "-0";
16
+ return value;
17
+ }
18
+ if (typeof value === "string") return value;
19
+ if (typeof value === "bigint") return value.toString();
20
+ if (typeof value === "symbol") return value.toString();
21
+ if (seen.has(value)) return "[Circular]";
22
+ if (depth >= MAX_DEPTH) return "[MaxDepth]";
23
+ seen.add(value);
24
+ if (Array.isArray(value)) return value.map((item) => serialize(item, seen, depth + 1));
25
+ const ctorName = Object.getPrototypeOf(value)?.constructor?.name;
26
+ if (ctorName && ctorName !== "Object") {
27
+ if (value instanceof Date) return value.toISOString();
28
+ if (value instanceof RegExp) return String(value);
29
+ if (value instanceof Map) {
30
+ const entries = {};
31
+ for (const [k, v] of value.entries()) entries[String(k)] = serialize(v, seen, depth + 1);
32
+ return {
33
+ type: "Map",
34
+ entries
35
+ };
36
+ }
37
+ if (value instanceof Set) return {
38
+ type: "Set",
39
+ values: [...value].map((v) => serialize(v, seen, depth + 1))
40
+ };
41
+ if (value instanceof Promise) return "Promise";
42
+ if (value instanceof Error) return {
43
+ type: "Error",
44
+ name: value.name,
45
+ message: value.message
46
+ };
47
+ if (typeof Node !== "undefined" && value instanceof Node && value instanceof Element) {
48
+ const attrs = {};
49
+ for (const attr of value.attributes) attrs[attr.name] = attr.value;
50
+ return {
51
+ type: "dom",
52
+ tagName: value.tagName.toLowerCase(),
53
+ attrs
54
+ };
55
+ }
56
+ return {
57
+ type: "class",
58
+ name: ctorName
59
+ };
60
+ }
61
+ const result = {};
62
+ for (const key of Object.keys(value)) result[key] = serialize(value[key], seen, depth + 1);
63
+ return result;
64
+ }
3
65
  function describeValue(value) {
4
- if (value === null) return "null";
5
- if (value === void 0) return "undefined";
6
- if (typeof value === "function") return `function ${value.name || "anonymous"}`;
7
- if (typeof value !== "object") return String(value);
8
- if (Array.isArray(value)) return `Array(${value.length})`;
9
- const name = Object.getPrototypeOf(value)?.constructor?.name;
10
- if (name && name !== "Object") return name;
11
- return "Object";
66
+ return serialize(value, /* @__PURE__ */ new WeakSet(), 0);
12
67
  }
13
68
  //#endregion
14
69
  //#region src/client/utils/sanitize-differences.ts
@@ -50,21 +105,27 @@ function patchDevToolsHook(onCommit) {
50
105
  function buildOptions(opts) {
51
106
  const wsUrl = opts?.wsUrl ?? DEFAULT_WS_URL;
52
107
  const projectId = opts?.projectId ?? globalThis.location?.origin ?? "default";
108
+ const MAX_QUEUE_SIZE = 1e3;
109
+ const BASE_DELAY = 1e3;
110
+ const MAX_DELAY = 3e4;
53
111
  let ws = null;
54
112
  let queue = [];
55
113
  let commitId = 0;
114
+ let retryDelay = BASE_DELAY;
56
115
  patchDevToolsHook(() => {
57
116
  commitId++;
58
117
  });
59
118
  function connect() {
60
119
  ws = new WebSocket(wsUrl);
61
120
  ws.addEventListener("open", () => {
121
+ retryDelay = BASE_DELAY;
62
122
  for (const msg of queue) ws?.send(JSON.stringify(msg));
63
123
  queue = [];
64
124
  });
65
125
  ws.addEventListener("close", () => {
66
126
  ws = null;
67
- setTimeout(connect, 1e3);
127
+ setTimeout(connect, retryDelay);
128
+ retryDelay = Math.min(retryDelay * 2, MAX_DELAY);
68
129
  });
69
130
  ws.addEventListener("error", () => {
70
131
  ws?.close();
@@ -73,7 +134,10 @@ function buildOptions(opts) {
73
134
  connect();
74
135
  function send(msg) {
75
136
  if (ws?.readyState === WebSocket.OPEN) ws.send(JSON.stringify(msg));
76
- else queue.push(msg);
137
+ else {
138
+ if (queue.length >= MAX_QUEUE_SIZE) queue.shift();
139
+ queue.push(msg);
140
+ }
77
141
  }
78
142
  let pendingBatch = null;
79
143
  let flushScheduled = false;
@@ -1,13 +1,68 @@
1
1
  //#region src/client/utils/describe-value.ts
2
+ const MAX_DEPTH = 8;
3
+ function serialize(value, seen, depth) {
4
+ if (value === null) return null;
5
+ if (value === void 0) return null;
6
+ if (typeof value === "function") return {
7
+ type: "function",
8
+ name: value.name || "anonymous"
9
+ };
10
+ if (typeof value === "boolean") return value;
11
+ if (typeof value === "number") {
12
+ if (Number.isNaN(value)) return "NaN";
13
+ if (!Number.isFinite(value)) return value > 0 ? "Infinity" : "-Infinity";
14
+ if (Object.is(value, -0)) return "-0";
15
+ return value;
16
+ }
17
+ if (typeof value === "string") return value;
18
+ if (typeof value === "bigint") return value.toString();
19
+ if (typeof value === "symbol") return value.toString();
20
+ if (seen.has(value)) return "[Circular]";
21
+ if (depth >= MAX_DEPTH) return "[MaxDepth]";
22
+ seen.add(value);
23
+ if (Array.isArray(value)) return value.map((item) => serialize(item, seen, depth + 1));
24
+ const ctorName = Object.getPrototypeOf(value)?.constructor?.name;
25
+ if (ctorName && ctorName !== "Object") {
26
+ if (value instanceof Date) return value.toISOString();
27
+ if (value instanceof RegExp) return String(value);
28
+ if (value instanceof Map) {
29
+ const entries = {};
30
+ for (const [k, v] of value.entries()) entries[String(k)] = serialize(v, seen, depth + 1);
31
+ return {
32
+ type: "Map",
33
+ entries
34
+ };
35
+ }
36
+ if (value instanceof Set) return {
37
+ type: "Set",
38
+ values: [...value].map((v) => serialize(v, seen, depth + 1))
39
+ };
40
+ if (value instanceof Promise) return "Promise";
41
+ if (value instanceof Error) return {
42
+ type: "Error",
43
+ name: value.name,
44
+ message: value.message
45
+ };
46
+ if (typeof Node !== "undefined" && value instanceof Node && value instanceof Element) {
47
+ const attrs = {};
48
+ for (const attr of value.attributes) attrs[attr.name] = attr.value;
49
+ return {
50
+ type: "dom",
51
+ tagName: value.tagName.toLowerCase(),
52
+ attrs
53
+ };
54
+ }
55
+ return {
56
+ type: "class",
57
+ name: ctorName
58
+ };
59
+ }
60
+ const result = {};
61
+ for (const key of Object.keys(value)) result[key] = serialize(value[key], seen, depth + 1);
62
+ return result;
63
+ }
2
64
  function describeValue(value) {
3
- if (value === null) return "null";
4
- if (value === void 0) return "undefined";
5
- if (typeof value === "function") return `function ${value.name || "anonymous"}`;
6
- if (typeof value !== "object") return String(value);
7
- if (Array.isArray(value)) return `Array(${value.length})`;
8
- const name = Object.getPrototypeOf(value)?.constructor?.name;
9
- if (name && name !== "Object") return name;
10
- return "Object";
65
+ return serialize(value, /* @__PURE__ */ new WeakSet(), 0);
11
66
  }
12
67
  //#endregion
13
68
  //#region src/client/utils/sanitize-differences.ts
@@ -49,21 +104,27 @@ function patchDevToolsHook(onCommit) {
49
104
  function buildOptions(opts) {
50
105
  const wsUrl = opts?.wsUrl ?? DEFAULT_WS_URL;
51
106
  const projectId = opts?.projectId ?? globalThis.location?.origin ?? "default";
107
+ const MAX_QUEUE_SIZE = 1e3;
108
+ const BASE_DELAY = 1e3;
109
+ const MAX_DELAY = 3e4;
52
110
  let ws = null;
53
111
  let queue = [];
54
112
  let commitId = 0;
113
+ let retryDelay = BASE_DELAY;
55
114
  patchDevToolsHook(() => {
56
115
  commitId++;
57
116
  });
58
117
  function connect() {
59
118
  ws = new WebSocket(wsUrl);
60
119
  ws.addEventListener("open", () => {
120
+ retryDelay = BASE_DELAY;
61
121
  for (const msg of queue) ws?.send(JSON.stringify(msg));
62
122
  queue = [];
63
123
  });
64
124
  ws.addEventListener("close", () => {
65
125
  ws = null;
66
- setTimeout(connect, 1e3);
126
+ setTimeout(connect, retryDelay);
127
+ retryDelay = Math.min(retryDelay * 2, MAX_DELAY);
67
128
  });
68
129
  ws.addEventListener("error", () => {
69
130
  ws?.close();
@@ -72,7 +133,10 @@ function buildOptions(opts) {
72
133
  connect();
73
134
  function send(msg) {
74
135
  if (ws?.readyState === WebSocket.OPEN) ws.send(JSON.stringify(msg));
75
- else queue.push(msg);
136
+ else {
137
+ if (queue.length >= MAX_QUEUE_SIZE) queue.shift();
138
+ queue.push(msg);
139
+ }
76
140
  }
77
141
  let pendingBatch = null;
78
142
  let flushScheduled = false;
@@ -370,10 +370,22 @@ const server = new McpServer({
370
370
  });
371
371
  registerTools(server);
372
372
  async function main() {
373
- createWsServer(Number(process.env.WDYR_WS_PORT) || DEFAULT_WS_PORT);
373
+ const wss = createWsServer(Number(process.env.WDYR_WS_PORT) || DEFAULT_WS_PORT);
374
374
  const transport = new StdioServerTransport();
375
375
  await server.connect(transport);
376
376
  console.error("[wdyr-mcp] MCP server running on stdio");
377
+ let shuttingDown = false;
378
+ async function shutdown() {
379
+ if (shuttingDown) return;
380
+ shuttingDown = true;
381
+ console.error("[wdyr-mcp] Shutting down…");
382
+ wss?.close();
383
+ await server.close();
384
+ process.exit(0);
385
+ }
386
+ process.stdin.on("end", shutdown);
387
+ process.on("SIGTERM", shutdown);
388
+ process.on("SIGINT", shutdown);
377
389
  }
378
390
  main().catch((error) => {
379
391
  console.error("[wdyr-mcp] Fatal error:", error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0x1f320.sh/why-did-you-render-mcp",
3
- "version": "1.0.0-dev.3",
3
+ "version": "1.0.0-dev.5",
4
4
  "type": "module",
5
5
  "description": "MCP server that collects why-did-you-render data from browser and exposes it to coding agents",
6
6
  "license": "MIT",