@presto1314w/vite-devtools-browser 0.3.1 → 0.3.2
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 +2 -1
- package/dist/browser-collector.js +64 -29
- package/dist/browser.js +2 -0
- package/dist/cli.js +38 -8
- package/dist/daemon.js +68 -16
- package/dist/event-analysis.d.ts +2 -0
- package/dist/event-analysis.js +6 -0
- package/dist/trace.js +18 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -271,12 +271,13 @@ vite-browser eval <script>
|
|
|
271
271
|
|
|
272
272
|
## Current Boundaries
|
|
273
273
|
|
|
274
|
-
`v0.3.
|
|
274
|
+
`v0.3.2` 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
281
|
|
|
281
282
|
`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.
|
|
282
283
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
export function initBrowserEventCollector() {
|
|
2
|
-
if (window.__vb_events)
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
window.__vb_push
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
q.
|
|
10
|
-
|
|
2
|
+
if (!window.__vb_events) {
|
|
3
|
+
window.__vb_events = [];
|
|
4
|
+
}
|
|
5
|
+
if (!window.__vb_push) {
|
|
6
|
+
window.__vb_push = (event) => {
|
|
7
|
+
const q = window.__vb_events;
|
|
8
|
+
q.push(event);
|
|
9
|
+
if (q.length > 1000)
|
|
10
|
+
q.shift();
|
|
11
|
+
};
|
|
12
|
+
}
|
|
11
13
|
const inferFramework = () => {
|
|
12
14
|
if (window.__VUE__ || window.__VUE_DEVTOOLS_GLOBAL_HOOK__)
|
|
13
15
|
return "vue";
|
|
@@ -117,15 +119,16 @@ export function initBrowserEventCollector() {
|
|
|
117
119
|
}, 60);
|
|
118
120
|
};
|
|
119
121
|
const attachPiniaSubscriptions = () => {
|
|
120
|
-
if (window.__vb_pinia_attached)
|
|
121
|
-
return;
|
|
122
122
|
const hook = window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
|
|
123
123
|
const app = Array.isArray(hook?.apps) ? hook.apps[0] : null;
|
|
124
124
|
const pinia = window.__PINIA__ || window.pinia || app?.config?.globalProperties?.$pinia;
|
|
125
125
|
const registry = pinia?._s;
|
|
126
126
|
if (!(registry instanceof Map) || registry.size === 0)
|
|
127
127
|
return;
|
|
128
|
-
const attached =
|
|
128
|
+
const attached = window.__vb_pinia_attached ||
|
|
129
|
+
(window.__vb_pinia_attached = new Set());
|
|
130
|
+
const actionAttached = window.__vb_pinia_action_attached ||
|
|
131
|
+
(window.__vb_pinia_action_attached = new Set());
|
|
129
132
|
registry.forEach((store, storeId) => {
|
|
130
133
|
if (!store || typeof store.$subscribe !== "function" || attached.has(String(storeId)))
|
|
131
134
|
return;
|
|
@@ -161,10 +164,33 @@ export function initBrowserEventCollector() {
|
|
|
161
164
|
},
|
|
162
165
|
});
|
|
163
166
|
scheduleRender("store-update", { changedKeys });
|
|
164
|
-
},
|
|
167
|
+
},
|
|
168
|
+
// Flush synchronously so the store event is recorded before a render-time failure
|
|
169
|
+
// can short-circuit the rest of Vue's update cycle.
|
|
170
|
+
{ detached: true, flush: "sync" });
|
|
171
|
+
if (typeof store.$onAction === "function" && !actionAttached.has(String(storeId))) {
|
|
172
|
+
actionAttached.add(String(storeId));
|
|
173
|
+
store.$onAction(({ name, after }) => {
|
|
174
|
+
after(() => {
|
|
175
|
+
window.__vb_push({
|
|
176
|
+
timestamp: Date.now(),
|
|
177
|
+
type: "store-update",
|
|
178
|
+
payload: {
|
|
179
|
+
store: String(storeId),
|
|
180
|
+
mutationType: typeof name === "string" && name.length > 0 ? `action:${name}` : "action",
|
|
181
|
+
events: 0,
|
|
182
|
+
changedKeys: [],
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
scheduleRender("store-update");
|
|
186
|
+
});
|
|
187
|
+
}, true);
|
|
188
|
+
}
|
|
165
189
|
});
|
|
166
190
|
};
|
|
167
191
|
function attachViteListener() {
|
|
192
|
+
if (window.__vb_vite_listener_attached)
|
|
193
|
+
return true;
|
|
168
194
|
const hot = window.__vite_hot;
|
|
169
195
|
if (hot?.ws) {
|
|
170
196
|
hot.ws.addEventListener("message", (e) => {
|
|
@@ -181,6 +207,7 @@ export function initBrowserEventCollector() {
|
|
|
181
207
|
}
|
|
182
208
|
catch { }
|
|
183
209
|
});
|
|
210
|
+
window.__vb_vite_listener_attached = true;
|
|
184
211
|
return true;
|
|
185
212
|
}
|
|
186
213
|
return false;
|
|
@@ -194,22 +221,28 @@ export function initBrowserEventCollector() {
|
|
|
194
221
|
}
|
|
195
222
|
}, 100);
|
|
196
223
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
window.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
window.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
224
|
+
if (!window.__vb_onerror_attached) {
|
|
225
|
+
const origOnError = window.onerror;
|
|
226
|
+
window.onerror = (msg, src, line, col, err) => {
|
|
227
|
+
window.__vb_push({
|
|
228
|
+
timestamp: Date.now(),
|
|
229
|
+
type: "error",
|
|
230
|
+
payload: { message: String(msg), source: src, line, col, stack: err?.stack },
|
|
231
|
+
});
|
|
232
|
+
return origOnError ? origOnError(msg, src, line, col, err) : false;
|
|
233
|
+
};
|
|
234
|
+
window.__vb_onerror_attached = true;
|
|
235
|
+
}
|
|
236
|
+
if (!window.__vb_unhandledrejection_attached) {
|
|
237
|
+
window.addEventListener("unhandledrejection", (e) => {
|
|
238
|
+
window.__vb_push({
|
|
239
|
+
timestamp: Date.now(),
|
|
240
|
+
type: "error",
|
|
241
|
+
payload: { message: e.reason?.message, stack: e.reason?.stack },
|
|
242
|
+
});
|
|
211
243
|
});
|
|
212
|
-
|
|
244
|
+
window.__vb_unhandledrejection_attached = true;
|
|
245
|
+
}
|
|
213
246
|
const observeDom = () => {
|
|
214
247
|
const root = document.body || document.documentElement;
|
|
215
248
|
if (!root || window.__vb_render_observer)
|
|
@@ -246,7 +279,9 @@ export function initBrowserEventCollector() {
|
|
|
246
279
|
observeDom();
|
|
247
280
|
patchHistory();
|
|
248
281
|
attachPiniaSubscriptions();
|
|
249
|
-
window.
|
|
282
|
+
if (!window.__vb_pinia_retry_timer) {
|
|
283
|
+
window.__vb_pinia_retry_timer = window.setInterval(attachPiniaSubscriptions, 250);
|
|
284
|
+
}
|
|
250
285
|
scheduleRender("initial-load");
|
|
251
286
|
}
|
|
252
287
|
export function readBrowserEvents() {
|
package/dist/browser.js
CHANGED
|
@@ -36,6 +36,7 @@ async function injectEventCollector(currentPage) {
|
|
|
36
36
|
* Flush browser events into daemon event queue
|
|
37
37
|
*/
|
|
38
38
|
export async function flushBrowserEvents(currentPage, queue) {
|
|
39
|
+
await currentPage.evaluate(initBrowserEventCollector);
|
|
39
40
|
const raw = await currentPage.evaluate(readBrowserEvents);
|
|
40
41
|
for (const e of raw) {
|
|
41
42
|
queue.push(e);
|
|
@@ -275,6 +276,7 @@ export async function screenshot() {
|
|
|
275
276
|
}
|
|
276
277
|
export async function evaluate(script) {
|
|
277
278
|
const currentPage = requireCurrentPage();
|
|
279
|
+
await currentPage.evaluate(initBrowserEventCollector);
|
|
278
280
|
const result = await currentPage.evaluate(script);
|
|
279
281
|
return JSON.stringify(result, null, 2);
|
|
280
282
|
}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
|
+
import { realpathSync } from "node:fs";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
3
6
|
import { send } from "./client.js";
|
|
7
|
+
class CliExit extends Error {
|
|
8
|
+
code;
|
|
9
|
+
constructor(code) {
|
|
10
|
+
super(`CLI_EXIT:${code}`);
|
|
11
|
+
this.code = code;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
4
14
|
export function normalizeUrl(value) {
|
|
5
15
|
if (value.includes("://"))
|
|
6
16
|
return value;
|
|
@@ -255,16 +265,36 @@ OPTIONS
|
|
|
255
265
|
`;
|
|
256
266
|
}
|
|
257
267
|
function isEntrypoint(argv1) {
|
|
258
|
-
|
|
268
|
+
if (!argv1)
|
|
269
|
+
return false;
|
|
270
|
+
try {
|
|
271
|
+
const current = realpathSync(fileURLToPath(import.meta.url));
|
|
272
|
+
const target = realpathSync(resolve(argv1));
|
|
273
|
+
return current === target;
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return Boolean(argv1 && import.meta.url.endsWith(argv1.replaceAll("\\", "/")));
|
|
277
|
+
}
|
|
259
278
|
}
|
|
260
279
|
async function main() {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
280
|
+
try {
|
|
281
|
+
await runCli(process.argv, {
|
|
282
|
+
send,
|
|
283
|
+
readFile: readFileSync,
|
|
284
|
+
stdout: (text) => process.stdout.write(`${text}\n`),
|
|
285
|
+
stderr: (text) => process.stderr.write(`${text}\n`),
|
|
286
|
+
exit: ((code) => {
|
|
287
|
+
throw new CliExit(code);
|
|
288
|
+
}),
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
if (error instanceof CliExit) {
|
|
293
|
+
process.exitCode = error.code;
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
268
298
|
}
|
|
269
299
|
if (isEntrypoint(process.argv[1])) {
|
|
270
300
|
void main().catch((error) => {
|
package/dist/daemon.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createServer } from "node:net";
|
|
2
2
|
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
3
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
import * as browser from "./browser.js";
|
|
5
6
|
import { correlateErrorWithHMR, formatErrorCorrelationReport } from "./correlate.js";
|
|
@@ -18,19 +19,8 @@ export function cleanError(err) {
|
|
|
18
19
|
}
|
|
19
20
|
export function createRunner(api = browser) {
|
|
20
21
|
return async function run(cmd) {
|
|
21
|
-
// Flush browser events to daemon queue before processing command
|
|
22
22
|
const queue = api.getEventQueue();
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const currentPage = api.getCurrentPage();
|
|
26
|
-
if (currentPage) {
|
|
27
|
-
await api.flushBrowserEvents(currentPage, queue);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
// Ignore flush errors (page might not be open yet)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
23
|
+
await flushCurrentPageEvents(api, queue);
|
|
34
24
|
// Browser control
|
|
35
25
|
if (cmd.action === "open") {
|
|
36
26
|
await api.open(cmd.url);
|
|
@@ -114,8 +104,8 @@ export function createRunner(api = browser) {
|
|
|
114
104
|
return { ok: true, data };
|
|
115
105
|
}
|
|
116
106
|
if (cmd.action === "correlate-renders") {
|
|
117
|
-
const events =
|
|
118
|
-
const data = formatPropagationTraceReport(
|
|
107
|
+
const events = await getSettledEventWindow(api, queue, cmd.windowMs ?? 5000);
|
|
108
|
+
const data = formatPropagationTraceReport(await buildPropagationTrace(api, events));
|
|
119
109
|
return { ok: true, data };
|
|
120
110
|
}
|
|
121
111
|
if (cmd.action === "diagnose-hmr") {
|
|
@@ -128,8 +118,8 @@ export function createRunner(api = browser) {
|
|
|
128
118
|
return { ok: true, data };
|
|
129
119
|
}
|
|
130
120
|
if (cmd.action === "diagnose-propagation") {
|
|
131
|
-
const events =
|
|
132
|
-
const data = formatPropagationDiagnosisReport(diagnosePropagation(
|
|
121
|
+
const events = await getSettledEventWindow(api, queue, cmd.windowMs ?? 5000);
|
|
122
|
+
const data = formatPropagationDiagnosisReport(diagnosePropagation(await buildPropagationTrace(api, events)));
|
|
133
123
|
return { ok: true, data };
|
|
134
124
|
}
|
|
135
125
|
if (cmd.action === "logs") {
|
|
@@ -143,6 +133,10 @@ export function createRunner(api = browser) {
|
|
|
143
133
|
}
|
|
144
134
|
if (cmd.action === "eval") {
|
|
145
135
|
const data = await api.evaluate(cmd.script);
|
|
136
|
+
await settleCurrentPage(api, 120);
|
|
137
|
+
await flushCurrentPageEvents(api, queue);
|
|
138
|
+
await settleCurrentPage(api, 180);
|
|
139
|
+
await flushCurrentPageEvents(api, queue);
|
|
146
140
|
return { ok: true, data };
|
|
147
141
|
}
|
|
148
142
|
if (cmd.action === "network") {
|
|
@@ -152,6 +146,64 @@ export function createRunner(api = browser) {
|
|
|
152
146
|
return { ok: false, error: `unknown action: ${cmd.action}` };
|
|
153
147
|
};
|
|
154
148
|
}
|
|
149
|
+
async function buildPropagationTrace(api, events) {
|
|
150
|
+
const trace = correlateRenderPropagation(events);
|
|
151
|
+
if (!trace)
|
|
152
|
+
return null;
|
|
153
|
+
if (trace.errorMessages.length > 0)
|
|
154
|
+
return trace;
|
|
155
|
+
const currentError = String(await api.errors(false, false));
|
|
156
|
+
if (!currentError || currentError === "no errors")
|
|
157
|
+
return trace;
|
|
158
|
+
return {
|
|
159
|
+
...trace,
|
|
160
|
+
errorMessages: [currentError, ...trace.errorMessages],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
async function flushCurrentPageEvents(api, queue) {
|
|
164
|
+
if (!queue)
|
|
165
|
+
return;
|
|
166
|
+
try {
|
|
167
|
+
const currentPage = api.getCurrentPage();
|
|
168
|
+
if (currentPage) {
|
|
169
|
+
await api.flushBrowserEvents(currentPage, queue);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// Ignore flush errors (page might not be open yet)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async function getSettledEventWindow(api, queue, windowMs) {
|
|
177
|
+
if (!queue)
|
|
178
|
+
return [];
|
|
179
|
+
let events = queue.window(windowMs);
|
|
180
|
+
if (hasPropagationSignals(events))
|
|
181
|
+
return events;
|
|
182
|
+
for (const delayMs of [120, 300]) {
|
|
183
|
+
await settleCurrentPage(api, delayMs);
|
|
184
|
+
await flushCurrentPageEvents(api, queue);
|
|
185
|
+
events = queue.window(windowMs);
|
|
186
|
+
if (hasPropagationSignals(events))
|
|
187
|
+
return events;
|
|
188
|
+
}
|
|
189
|
+
return events;
|
|
190
|
+
}
|
|
191
|
+
function hasPropagationSignals(events) {
|
|
192
|
+
return events.some((event) => event.type === "render" || event.type === "store-update");
|
|
193
|
+
}
|
|
194
|
+
async function settleCurrentPage(api, delayMs) {
|
|
195
|
+
const currentPage = api.getCurrentPage();
|
|
196
|
+
if (!currentPage) {
|
|
197
|
+
await sleep(delayMs);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
await currentPage.waitForTimeout(delayMs);
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
await sleep(delayMs);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
155
207
|
export async function dispatchLine(line, socket, run = createRunner(), onClose) {
|
|
156
208
|
let cmd;
|
|
157
209
|
try {
|
package/dist/event-analysis.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export declare function getRenderLabel(payload: RenderEventPayload): string;
|
|
|
27
27
|
export declare function getStoreName(payload: StoreUpdatePayload): string | null;
|
|
28
28
|
export declare function getChangedKeys(payload: StoreUpdatePayload): string[];
|
|
29
29
|
export declare function getStoreHints(payload: RenderEventPayload): string[];
|
|
30
|
+
export declare function getRenderReason(payload: RenderEventPayload): string | null;
|
|
31
|
+
export declare function getRenderChangedKeys(payload: RenderEventPayload): string[];
|
|
30
32
|
export declare function getNetworkUrl(payload: NetworkEventPayload): string | null;
|
|
31
33
|
export declare function getErrorMessage(payload: ErrorEventPayload): string | null;
|
|
32
34
|
export declare function uniqueStrings(values: string[]): string[];
|
package/dist/event-analysis.js
CHANGED
|
@@ -59,6 +59,12 @@ export function getChangedKeys(payload) {
|
|
|
59
59
|
export function getStoreHints(payload) {
|
|
60
60
|
return payload.storeHints.filter((value) => value.length > 0);
|
|
61
61
|
}
|
|
62
|
+
export function getRenderReason(payload) {
|
|
63
|
+
return typeof payload.reason === "string" && payload.reason.length > 0 ? payload.reason : null;
|
|
64
|
+
}
|
|
65
|
+
export function getRenderChangedKeys(payload) {
|
|
66
|
+
return payload.changedKeys.filter((value) => value.length > 0);
|
|
67
|
+
}
|
|
62
68
|
export function getNetworkUrl(payload) {
|
|
63
69
|
return payload.url.length > 0 ? payload.url : null;
|
|
64
70
|
}
|
package/dist/trace.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractModulesFromHmrEvent, getChangedKeys, getErrorEvents, getErrorMessage, getHmrEvents, getNetworkEvents, getNetworkUrl, getRenderEvents, getRenderLabel, getStoreHints, getStoreName, getStoreUpdateEvents, sortEventsChronologically, uniqueStrings, } from "./event-analysis.js";
|
|
1
|
+
import { extractModulesFromHmrEvent, getChangedKeys, getErrorEvents, getErrorMessage, getHmrEvents, getNetworkEvents, getNetworkUrl, getRenderChangedKeys, getRenderEvents, getRenderLabel, getRenderReason, getStoreHints, getStoreName, getStoreUpdateEvents, sortEventsChronologically, uniqueStrings, } from "./event-analysis.js";
|
|
2
2
|
export function correlateRenderPropagation(events) {
|
|
3
3
|
const recent = sortEventsChronologically(events);
|
|
4
4
|
const renderEvents = getRenderEvents(recent);
|
|
@@ -9,10 +9,24 @@ export function correlateRenderPropagation(events) {
|
|
|
9
9
|
const networkEvents = getNetworkEvents(recent);
|
|
10
10
|
const errorEvents = getErrorEvents(recent);
|
|
11
11
|
const sourceModules = uniqueStrings(hmrEvents.flatMap(extractModulesFromHmrEvent));
|
|
12
|
-
const
|
|
13
|
-
const changedKeys = uniqueStrings(storeEvents.flatMap((event) => getChangedKeys(event.payload)));
|
|
14
|
-
const renderComponents = uniqueStrings(renderEvents.map((event) => getRenderLabel(event.payload)).filter(Boolean));
|
|
12
|
+
const explicitStoreUpdates = uniqueStrings(storeEvents.map((event) => getStoreName(event.payload)).filter((value) => value != null));
|
|
15
13
|
const storeHints = uniqueStrings(renderEvents.flatMap((event) => getStoreHints(event.payload)));
|
|
14
|
+
const inferredStoreUpdates = explicitStoreUpdates.length > 0
|
|
15
|
+
? explicitStoreUpdates
|
|
16
|
+
: uniqueStrings(renderEvents
|
|
17
|
+
.filter((event) => getRenderReason(event.payload) === "store-update")
|
|
18
|
+
.flatMap((event) => getStoreHints(event.payload)));
|
|
19
|
+
const storeUpdates = inferredStoreUpdates.length > 0
|
|
20
|
+
? inferredStoreUpdates
|
|
21
|
+
: storeHints.length === 1
|
|
22
|
+
? storeHints
|
|
23
|
+
: [];
|
|
24
|
+
const changedKeys = uniqueStrings(storeEvents.length > 0
|
|
25
|
+
? storeEvents.flatMap((event) => getChangedKeys(event.payload))
|
|
26
|
+
: renderEvents
|
|
27
|
+
.filter((event) => getRenderReason(event.payload) === "store-update")
|
|
28
|
+
.flatMap((event) => getRenderChangedKeys(event.payload)));
|
|
29
|
+
const renderComponents = uniqueStrings(renderEvents.map((event) => getRenderLabel(event.payload)).filter(Boolean));
|
|
16
30
|
const networkUrls = uniqueStrings(networkEvents.map((event) => getNetworkUrl(event.payload)).filter((value) => value != null));
|
|
17
31
|
const errorMessages = uniqueStrings(errorEvents.map((event) => getErrorMessage(event.payload)).filter((value) => value != null));
|
|
18
32
|
const confidence = inferConfidence(sourceModules, storeUpdates, renderComponents, errorMessages);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@presto1314w/vite-devtools-browser",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Runtime diagnostics CLI for Vite apps with event-stream correlation, HMR diagnosis, framework inspection, and mapped errors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|