@presto1314w/vite-devtools-browser 0.3.2 → 0.3.3

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/README.md CHANGED
@@ -271,13 +271,15 @@ vite-browser eval <script>
271
271
 
272
272
  ## Current Boundaries
273
273
 
274
- `v0.3.2` is strong at:
274
+ `v0.3.3` is strong at:
275
275
  - surfacing runtime state as structured shell output
276
276
  - linking current errors to recent HMR and module activity
277
277
  - detecting common HMR failure patterns with confidence levels
278
278
  - narrowing likely store/module -> render paths in Vue-first flows
279
279
  - capturing browser-side runtime errors even when the Vite overlay is absent
280
- - turning sparse live Vue/Pinia repro signals into actionable `store -> render -> error` guidance more reliably
280
+ - correlating sparse HMR traces back to the right source module more reliably
281
+ - retaining `changedKeys` and source-module hints when one side of the event stream is incomplete
282
+ - clearing stale runtime errors after recovery so the current page lifecycle is easier to trust
281
283
 
282
284
  `correlate renders` and `diagnose propagation` are **high-confidence propagation clues**, not strict causal proof. They do not reliably trace deep chains like `store -> component A -> component B -> error` across arbitrary graphs, and intentionally fall back to conservative output when evidence is incomplete.
283
285
 
package/dist/browser.d.ts CHANGED
@@ -7,6 +7,17 @@ export { formatHmrTrace, formatModuleGraphSnapshot, formatModuleGraphTrace, form
7
7
  export type ModuleGraphMode = "snapshot" | "trace" | "clear";
8
8
  export declare function setEventQueue(queue: EventQueue): void;
9
9
  export declare function getEventQueue(): EventQueue | null;
10
+ export declare function getTrackedHmrEvents(windowMs?: number): Array<{
11
+ timestamp: number;
12
+ type: "hmr-update" | "hmr-error";
13
+ payload: {
14
+ path?: string;
15
+ message?: string;
16
+ updates?: Array<{
17
+ path?: string;
18
+ }>;
19
+ };
20
+ }>;
10
21
  export declare function getCurrentPage(): Page | null;
11
22
  /**
12
23
  * Flush browser events into daemon event queue
package/dist/browser.js CHANGED
@@ -19,6 +19,20 @@ export function setEventQueue(queue) {
19
19
  export function getEventQueue() {
20
20
  return eventQueue;
21
21
  }
22
+ export function getTrackedHmrEvents(windowMs = 5000) {
23
+ const cutoff = Date.now() - windowMs;
24
+ return session.hmrEvents
25
+ .filter((event) => event.timestamp >= cutoff)
26
+ .map((event) => ({
27
+ timestamp: event.timestamp,
28
+ type: event.type === "error" ? "hmr-error" : "hmr-update",
29
+ payload: {
30
+ path: event.path,
31
+ message: event.message,
32
+ updates: event.path ? [{ path: event.path }] : [],
33
+ },
34
+ }));
35
+ }
22
36
  export function getCurrentPage() {
23
37
  return getSessionPage(session);
24
38
  }
@@ -150,7 +164,7 @@ export async function goto(url) {
150
164
  }
151
165
  export async function back() {
152
166
  const currentPage = await ensurePage();
153
- await currentPage.goBack({ waitUntil: "domcontentloaded" });
167
+ await navigateAndRefreshContext(currentPage, () => currentPage.goBack({ waitUntil: "domcontentloaded" }));
154
168
  }
155
169
  export async function reload() {
156
170
  const currentPage = await ensurePage();
@@ -317,8 +331,12 @@ function requireCurrentPage() {
317
331
  }
318
332
  async function navigateAndRefreshContext(currentPage, navigate, refreshFramework = false) {
319
333
  await navigate();
334
+ clearRuntimeErrors();
320
335
  await injectEventCollector(currentPage);
321
336
  if (refreshFramework) {
322
337
  await detectFramework();
323
338
  }
324
339
  }
340
+ function clearRuntimeErrors() {
341
+ session.runtimeErrors.length = 0;
342
+ }
package/dist/cli.js CHANGED
File without changes
package/dist/daemon.js CHANGED
@@ -6,6 +6,7 @@ import * as browser from "./browser.js";
6
6
  import { correlateErrorWithHMR, formatErrorCorrelationReport } from "./correlate.js";
7
7
  import { diagnoseHMR, formatDiagnosisReport } from "./diagnose.js";
8
8
  import { diagnosePropagation, formatPropagationDiagnosisReport } from "./diagnose-propagation.js";
9
+ import { extractModules } from "./event-analysis.js";
9
10
  import { socketDir, socketPath, pidFile } from "./paths.js";
10
11
  import { correlateRenderPropagation, formatPropagationTraceReport } from "./trace.js";
11
12
  import { EventQueue } from "./event-queue.js";
@@ -100,12 +101,20 @@ export function createRunner(api = browser) {
100
101
  if (cmd.action === "correlate-errors") {
101
102
  const errorText = String(await api.errors(Boolean(cmd.mapped), Boolean(cmd.inlineSource)));
102
103
  const events = queue ? queue.window(cmd.windowMs ?? 5000) : [];
103
- const data = formatErrorCorrelationReport(errorText, errorText === "no errors" ? null : correlateErrorWithHMR(errorText, events, cmd.windowMs ?? 5000));
104
+ const fallbackHmrEvents = readTrackedHmrEvents(api, cmd.windowMs ?? 5000);
105
+ const hmrTraceText = String(await api.viteHMRTrace("trace", 20));
106
+ const fallbackModules = extractModules(hmrTraceText);
107
+ const baseCorrelation = errorText === "no errors"
108
+ ? null
109
+ : correlateErrorWithHMR(errorText, [...events, ...fallbackHmrEvents], cmd.windowMs ?? 5000);
110
+ const data = formatErrorCorrelationReport(errorText, errorText === "no errors"
111
+ ? null
112
+ : upgradeErrorCorrelation(baseCorrelation, fallbackModules, cmd.windowMs ?? 5000));
104
113
  return { ok: true, data };
105
114
  }
106
115
  if (cmd.action === "correlate-renders") {
107
116
  const events = await getSettledEventWindow(api, queue, cmd.windowMs ?? 5000);
108
- const data = formatPropagationTraceReport(await buildPropagationTrace(api, events));
117
+ const data = formatPropagationTraceReport(await buildPropagationTrace(api, events, cmd.windowMs ?? 5000));
109
118
  return { ok: true, data };
110
119
  }
111
120
  if (cmd.action === "diagnose-hmr") {
@@ -119,7 +128,7 @@ export function createRunner(api = browser) {
119
128
  }
120
129
  if (cmd.action === "diagnose-propagation") {
121
130
  const events = await getSettledEventWindow(api, queue, cmd.windowMs ?? 5000);
122
- const data = formatPropagationDiagnosisReport(diagnosePropagation(await buildPropagationTrace(api, events)));
131
+ const data = formatPropagationDiagnosisReport(diagnosePropagation(await buildPropagationTrace(api, events, cmd.windowMs ?? 5000)));
123
132
  return { ok: true, data };
124
133
  }
125
134
  if (cmd.action === "logs") {
@@ -146,20 +155,89 @@ export function createRunner(api = browser) {
146
155
  return { ok: false, error: `unknown action: ${cmd.action}` };
147
156
  };
148
157
  }
149
- async function buildPropagationTrace(api, events) {
150
- const trace = correlateRenderPropagation(events);
158
+ async function buildPropagationTrace(api, events, windowMs) {
159
+ const hmrTraceText = String(await api.viteHMRTrace("trace", 20));
160
+ const fallbackModules = extractModules(hmrTraceText);
161
+ const trace = correlateRenderPropagation([...events, ...readTrackedHmrEvents(api, windowMs)]);
151
162
  if (!trace)
152
163
  return null;
153
- if (trace.errorMessages.length > 0)
154
- return trace;
164
+ let augmented = trace;
165
+ if (augmented.sourceModules.length === 0 && fallbackModules.length > 0) {
166
+ augmented = {
167
+ ...augmented,
168
+ sourceModules: fallbackModules,
169
+ };
170
+ }
171
+ if (augmented.changedKeys.length === 0 && augmented.storeUpdates.length > 0) {
172
+ const inferredChangedKeys = await inferLikelyChangedKeys(api, augmented.storeUpdates[0]);
173
+ if (inferredChangedKeys.length > 0) {
174
+ augmented = {
175
+ ...augmented,
176
+ changedKeys: inferredChangedKeys,
177
+ };
178
+ }
179
+ }
180
+ if (augmented.errorMessages.length > 0)
181
+ return augmented;
155
182
  const currentError = String(await api.errors(false, false));
156
183
  if (!currentError || currentError === "no errors")
157
- return trace;
184
+ return augmented;
185
+ return {
186
+ ...augmented,
187
+ errorMessages: [currentError, ...augmented.errorMessages],
188
+ };
189
+ }
190
+ function upgradeErrorCorrelation(correlation, fallbackModules, windowMs) {
191
+ if (fallbackModules.length === 0)
192
+ return correlation;
193
+ if (!correlation)
194
+ return synthesizeErrorCorrelation(fallbackModules, windowMs);
195
+ if (correlation.matchingModules.length > 0)
196
+ return correlation;
197
+ return synthesizeErrorCorrelation(fallbackModules, windowMs, correlation.relatedEvents);
198
+ }
199
+ function synthesizeErrorCorrelation(modules, windowMs, relatedEvents = []) {
200
+ if (modules.length === 0)
201
+ return null;
158
202
  return {
159
- ...trace,
160
- errorMessages: [currentError, ...trace.errorMessages],
203
+ summary: `HMR update observed within ${windowMs}ms of the current error`,
204
+ detail: `Matching modules: ${modules.join(", ")}\nRecent events considered: ${modules.length}`,
205
+ confidence: "high",
206
+ windowMs,
207
+ matchingModules: modules,
208
+ relatedEvents: relatedEvents.length > 0
209
+ ? relatedEvents
210
+ : modules.map((module) => ({
211
+ timestamp: Date.now(),
212
+ type: "hmr-update",
213
+ payload: {
214
+ path: module,
215
+ updates: [{ path: module }],
216
+ },
217
+ })),
161
218
  };
162
219
  }
220
+ async function inferLikelyChangedKeys(api, storeName) {
221
+ try {
222
+ const raw = await api.evaluate(`(() => {
223
+ const store = window.__PINIA__?._s?.get(${JSON.stringify(storeName)});
224
+ if (!store) return [];
225
+ return Object.keys(store).filter((key) => store[key] === undefined);
226
+ })()`);
227
+ const parsed = JSON.parse(String(raw));
228
+ return Array.isArray(parsed) ? parsed.filter((value) => typeof value === "string" && value.length > 0) : [];
229
+ }
230
+ catch {
231
+ return [];
232
+ }
233
+ }
234
+ function readTrackedHmrEvents(api, windowMs) {
235
+ const reader = api.getTrackedHmrEvents;
236
+ if (typeof reader !== "function")
237
+ return [];
238
+ const events = reader(windowMs);
239
+ return Array.isArray(events) ? events : [];
240
+ }
163
241
  async function flushCurrentPageEvents(api, queue) {
164
242
  if (!queue)
165
243
  return;
package/dist/trace.js CHANGED
@@ -21,11 +21,12 @@ export function correlateRenderPropagation(events) {
21
21
  : storeHints.length === 1
22
22
  ? storeHints
23
23
  : [];
24
- const changedKeys = uniqueStrings(storeEvents.length > 0
25
- ? storeEvents.flatMap((event) => getChangedKeys(event.payload))
26
- : renderEvents
24
+ const changedKeys = uniqueStrings([
25
+ ...storeEvents.flatMap((event) => getChangedKeys(event.payload)),
26
+ ...renderEvents
27
27
  .filter((event) => getRenderReason(event.payload) === "store-update")
28
- .flatMap((event) => getRenderChangedKeys(event.payload)));
28
+ .flatMap((event) => getRenderChangedKeys(event.payload)),
29
+ ]);
29
30
  const renderComponents = uniqueStrings(renderEvents.map((event) => getRenderLabel(event.payload)).filter(Boolean));
30
31
  const networkUrls = uniqueStrings(networkEvents.map((event) => getNetworkUrl(event.payload)).filter((value) => value != null));
31
32
  const errorMessages = uniqueStrings(errorEvents.map((event) => getErrorMessage(event.payload)).filter((value) => value != null));
package/package.json CHANGED
@@ -1,65 +1,63 @@
1
- {
2
- "name": "@presto1314w/vite-devtools-browser",
3
- "version": "0.3.2",
4
- "description": "Runtime diagnostics CLI for Vite apps with event-stream correlation, HMR diagnosis, framework inspection, and mapped errors",
5
- "license": "MIT",
6
- "keywords": [
7
- "vite",
8
- "devtools",
9
- "debugging",
10
- "runtime-diagnostics",
11
- "hmr",
12
- "module-graph",
13
- "sourcemap",
14
- "vue",
15
- "react",
16
- "svelte",
17
- "cli",
18
- "ai-agents"
19
- ],
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/MapleCity1314/vite-browser.git"
23
- },
24
- "homepage": "https://github.com/MapleCity1314/vite-browser#readme",
25
- "bugs": {
26
- "url": "https://github.com/MapleCity1314/vite-browser/issues"
27
- },
28
- "type": "module",
29
- "engines": {
30
- "node": ">=20"
31
- },
32
- "files": [
33
- "dist"
34
- ],
35
- "bin": {
36
- "vite-browser": "dist/cli.js"
37
- },
38
- "scripts": {
39
- "start": "node --import tsx src/cli.ts",
40
- "dev": "tsx src/cli.ts",
41
- "typecheck": "tsc --noEmit",
42
- "build": "tsc -p tsconfig.build.json",
43
- "prepack": "pnpm build",
44
- "test": "vitest run",
45
- "test:watch": "vitest",
46
- "test:coverage": "vitest run --coverage",
47
- "test:evals": "vitest run --dir test/evals",
48
- "test:evals:ci": "vitest run --dir test/evals --coverage --reporter=default",
49
- "test:evals:e2e": "pnpm build && vitest run --config vitest.e2e.config.ts"
50
- },
51
- "dependencies": {
52
- "playwright": "^1.50.0",
53
- "source-map-js": "^1.2.1"
54
- },
55
- "devDependencies": {
56
- "@types/node": "^22.0.0",
57
- "@vitest/coverage-v8": "^4.0.18",
58
- "@vue/devtools-kit": "^7.3.2",
59
- "@vue/devtools-api": "^7.3.2",
60
- "tsx": "^4.20.6",
61
- "typescript": "^5.7.0",
62
- "vitest": "^4.0.16"
63
- },
64
- "packageManager": "pnpm@10.29.2"
65
- }
1
+ {
2
+ "name": "@presto1314w/vite-devtools-browser",
3
+ "version": "0.3.3",
4
+ "description": "Runtime diagnostics CLI for Vite apps with event-stream correlation, HMR diagnosis, framework inspection, and mapped errors",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "vite",
8
+ "devtools",
9
+ "debugging",
10
+ "runtime-diagnostics",
11
+ "hmr",
12
+ "module-graph",
13
+ "sourcemap",
14
+ "vue",
15
+ "react",
16
+ "svelte",
17
+ "cli",
18
+ "ai-agents"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/MapleCity1314/vite-browser.git"
23
+ },
24
+ "homepage": "https://github.com/MapleCity1314/vite-browser#readme",
25
+ "bugs": {
26
+ "url": "https://github.com/MapleCity1314/vite-browser/issues"
27
+ },
28
+ "type": "module",
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "bin": {
36
+ "vite-browser": "dist/cli.js"
37
+ },
38
+ "dependencies": {
39
+ "playwright": "^1.50.0",
40
+ "source-map-js": "^1.2.1"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.0.0",
44
+ "@vitest/coverage-v8": "^4.0.18",
45
+ "@vue/devtools-kit": "^7.3.2",
46
+ "@vue/devtools-api": "^7.3.2",
47
+ "tsx": "^4.20.6",
48
+ "typescript": "^5.7.0",
49
+ "vitest": "^4.0.16"
50
+ },
51
+ "scripts": {
52
+ "start": "node --import tsx src/cli.ts",
53
+ "dev": "tsx src/cli.ts",
54
+ "typecheck": "tsc --noEmit",
55
+ "build": "tsc -p tsconfig.build.json",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest",
58
+ "test:coverage": "vitest run --coverage",
59
+ "test:evals": "vitest run --dir test/evals",
60
+ "test:evals:ci": "vitest run --dir test/evals --coverage --reporter=default",
61
+ "test:evals:e2e": "pnpm build && vitest run --config vitest.e2e.config.ts"
62
+ }
63
+ }