@lytjs/devtools-extension 6.4.0 → 6.6.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.cjs +1703 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +1590 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +54 -54
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1703 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var reactivity = require('@lytjs/reactivity');
|
|
4
|
+
var commonString = require('@lytjs/common-string');
|
|
5
|
+
|
|
6
|
+
// src/state.ts
|
|
7
|
+
var devtoolsState = reactivity.signal({
|
|
8
|
+
enabled: false,
|
|
9
|
+
connected: false,
|
|
10
|
+
recording: false
|
|
11
|
+
});
|
|
12
|
+
var stateSubscribers = /* @__PURE__ */ new Set();
|
|
13
|
+
function getState() {
|
|
14
|
+
return devtoolsState();
|
|
15
|
+
}
|
|
16
|
+
function enable() {
|
|
17
|
+
devtoolsState.set({ ...devtoolsState(), enabled: true });
|
|
18
|
+
}
|
|
19
|
+
function disable() {
|
|
20
|
+
devtoolsState.set({ ...devtoolsState(), enabled: false });
|
|
21
|
+
}
|
|
22
|
+
function setConnected(connected) {
|
|
23
|
+
devtoolsState.set({ ...devtoolsState(), connected });
|
|
24
|
+
}
|
|
25
|
+
function startRecording() {
|
|
26
|
+
devtoolsState.set({ ...devtoolsState(), recording: true });
|
|
27
|
+
}
|
|
28
|
+
function stopRecording() {
|
|
29
|
+
devtoolsState.set({ ...devtoolsState(), recording: false });
|
|
30
|
+
}
|
|
31
|
+
function subscribeState(callback) {
|
|
32
|
+
let isActive2 = true;
|
|
33
|
+
const stopEffect = reactivity.effect(() => {
|
|
34
|
+
const currentState = devtoolsState();
|
|
35
|
+
if (isActive2) {
|
|
36
|
+
callback(currentState);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const cleanup = () => {
|
|
40
|
+
if (isActive2) {
|
|
41
|
+
isActive2 = false;
|
|
42
|
+
stateSubscribers.delete(cleanup);
|
|
43
|
+
stopEffect();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
stateSubscribers.add(cleanup);
|
|
47
|
+
return cleanup;
|
|
48
|
+
}
|
|
49
|
+
function clearStateSubscribers() {
|
|
50
|
+
stateSubscribers.forEach((callback) => callback(devtoolsState()));
|
|
51
|
+
stateSubscribers.clear();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/component-tree.ts
|
|
55
|
+
var components = /* @__PURE__ */ new Map();
|
|
56
|
+
var idCounter = 0;
|
|
57
|
+
function generateComponentId() {
|
|
58
|
+
return `component-${++idCounter}-${Date.now().toString(36)}`;
|
|
59
|
+
}
|
|
60
|
+
function registerComponent(info) {
|
|
61
|
+
components.set(info.id, info);
|
|
62
|
+
if (info.parentId) {
|
|
63
|
+
const parent = components.get(info.parentId);
|
|
64
|
+
if (parent && !parent.children.includes(info.id)) {
|
|
65
|
+
parent.children.push(info.id);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function unregisterComponent(id) {
|
|
70
|
+
const component = components.get(id);
|
|
71
|
+
if (component?.parentId) {
|
|
72
|
+
const parent = components.get(component.parentId);
|
|
73
|
+
if (parent) {
|
|
74
|
+
parent.children = parent.children.filter((cid) => cid !== id);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
components.delete(id);
|
|
78
|
+
}
|
|
79
|
+
function getComponentById2(id) {
|
|
80
|
+
return components.get(id);
|
|
81
|
+
}
|
|
82
|
+
function getAllComponents() {
|
|
83
|
+
return Array.from(components.values());
|
|
84
|
+
}
|
|
85
|
+
function getRootComponents() {
|
|
86
|
+
return Array.from(components.values()).filter((c) => !c.parentId);
|
|
87
|
+
}
|
|
88
|
+
function clearComponents() {
|
|
89
|
+
components.clear();
|
|
90
|
+
}
|
|
91
|
+
function getComponentCount() {
|
|
92
|
+
return components.size;
|
|
93
|
+
}
|
|
94
|
+
function buildComponentTree() {
|
|
95
|
+
const roots = [];
|
|
96
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
97
|
+
for (const component of components.values()) {
|
|
98
|
+
const node = {
|
|
99
|
+
id: component.id,
|
|
100
|
+
name: component.name,
|
|
101
|
+
type: "component",
|
|
102
|
+
children: [],
|
|
103
|
+
props: component.props || {},
|
|
104
|
+
emits: [],
|
|
105
|
+
slots: Object.keys(component.slots || {})
|
|
106
|
+
};
|
|
107
|
+
nodeMap.set(component.id, node);
|
|
108
|
+
}
|
|
109
|
+
for (const component of components.values()) {
|
|
110
|
+
const node = nodeMap.get(component.id);
|
|
111
|
+
if (!node) continue;
|
|
112
|
+
if (component.parentId) {
|
|
113
|
+
const parent = nodeMap.get(component.parentId);
|
|
114
|
+
if (parent) {
|
|
115
|
+
node.parent = component.parentId;
|
|
116
|
+
parent.children.push(node);
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
roots.push(node);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return roots;
|
|
123
|
+
}
|
|
124
|
+
function getComponentTree() {
|
|
125
|
+
return buildComponentTree();
|
|
126
|
+
}
|
|
127
|
+
function clearComponentRegistry() {
|
|
128
|
+
components.clear();
|
|
129
|
+
idCounter = 0;
|
|
130
|
+
}
|
|
131
|
+
function autoRegisterFromInstance(instance) {
|
|
132
|
+
const id = generateComponentId();
|
|
133
|
+
const name = instance.type || instance.name || "Anonymous";
|
|
134
|
+
const props = {};
|
|
135
|
+
if (instance.props) {
|
|
136
|
+
for (const [key, value] of Object.entries(instance.props)) {
|
|
137
|
+
if (typeof value !== "function") {
|
|
138
|
+
props[key] = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const info = {
|
|
143
|
+
id,
|
|
144
|
+
name,
|
|
145
|
+
parentId: instance.parent,
|
|
146
|
+
children: [],
|
|
147
|
+
props,
|
|
148
|
+
slots: instance.slots
|
|
149
|
+
};
|
|
150
|
+
registerComponent(info);
|
|
151
|
+
if (instance.children && Array.isArray(instance.children)) {
|
|
152
|
+
for (const child of instance.children) {
|
|
153
|
+
const childId = autoRegisterFromInstance({ ...child, parent: id });
|
|
154
|
+
if (!info.children.includes(childId)) {
|
|
155
|
+
info.children.push(childId);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return id;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/signals.ts
|
|
163
|
+
var signals = /* @__PURE__ */ new Map();
|
|
164
|
+
var signalIdCounter = 0;
|
|
165
|
+
function generateSignalId() {
|
|
166
|
+
return `signal-${++signalIdCounter}-${Date.now().toString(36)}`;
|
|
167
|
+
}
|
|
168
|
+
function registerSignal(info) {
|
|
169
|
+
signals.set(info.id, info);
|
|
170
|
+
}
|
|
171
|
+
function unregisterSignal(id) {
|
|
172
|
+
signals.delete(id);
|
|
173
|
+
}
|
|
174
|
+
function getSignals() {
|
|
175
|
+
return Array.from(signals.values());
|
|
176
|
+
}
|
|
177
|
+
function getSignalById(id) {
|
|
178
|
+
return signals.get(id);
|
|
179
|
+
}
|
|
180
|
+
function getSignalValue(id) {
|
|
181
|
+
const signal2 = signals.get(id);
|
|
182
|
+
return signal2?.value;
|
|
183
|
+
}
|
|
184
|
+
function setSignalValue(id, value) {
|
|
185
|
+
const signal2 = signals.get(id);
|
|
186
|
+
if (!signal2) return false;
|
|
187
|
+
signal2.value = value;
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
function getSignalsByComponent(componentId) {
|
|
191
|
+
return Array.from(signals.values()).filter((s) => s.componentId === componentId);
|
|
192
|
+
}
|
|
193
|
+
function clearSignals() {
|
|
194
|
+
signals.clear();
|
|
195
|
+
}
|
|
196
|
+
function clearSignalRegistry() {
|
|
197
|
+
signals.clear();
|
|
198
|
+
signalIdCounter = 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/events.ts
|
|
202
|
+
var events = [];
|
|
203
|
+
var maxEvents = 1e3;
|
|
204
|
+
var isRecording = false;
|
|
205
|
+
var eventSubscribers = [];
|
|
206
|
+
function setMaxEvents(max) {
|
|
207
|
+
maxEvents = max;
|
|
208
|
+
}
|
|
209
|
+
function recordEvent(typeOrEvent, data) {
|
|
210
|
+
let record;
|
|
211
|
+
if (typeof typeOrEvent === "string") {
|
|
212
|
+
record = {
|
|
213
|
+
id: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
|
|
214
|
+
timestamp: Date.now(),
|
|
215
|
+
type: typeOrEvent,
|
|
216
|
+
data
|
|
217
|
+
};
|
|
218
|
+
} else {
|
|
219
|
+
record = {
|
|
220
|
+
...typeOrEvent,
|
|
221
|
+
id: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
|
|
222
|
+
timestamp: Date.now()
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
events.push(record);
|
|
226
|
+
if (events.length > maxEvents) {
|
|
227
|
+
events.splice(0, events.length - maxEvents);
|
|
228
|
+
}
|
|
229
|
+
eventSubscribers.forEach((callback) => {
|
|
230
|
+
try {
|
|
231
|
+
callback(record);
|
|
232
|
+
} catch (e) {
|
|
233
|
+
console.error("[DevTools Events] Subscriber error:", e);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
return record;
|
|
237
|
+
}
|
|
238
|
+
function getEvents() {
|
|
239
|
+
return [...events];
|
|
240
|
+
}
|
|
241
|
+
function getEventsByComponent(componentId) {
|
|
242
|
+
return events.filter((e) => e.componentId === componentId);
|
|
243
|
+
}
|
|
244
|
+
function getEventsByType(type) {
|
|
245
|
+
return events.filter((e) => e.type === type);
|
|
246
|
+
}
|
|
247
|
+
function clearEvents() {
|
|
248
|
+
events.length = 0;
|
|
249
|
+
}
|
|
250
|
+
function getEventStats() {
|
|
251
|
+
const stats = {};
|
|
252
|
+
events.forEach((e) => {
|
|
253
|
+
stats[e.type] = (stats[e.type] || 0) + 1;
|
|
254
|
+
});
|
|
255
|
+
return stats;
|
|
256
|
+
}
|
|
257
|
+
function startRecording2() {
|
|
258
|
+
isRecording = true;
|
|
259
|
+
}
|
|
260
|
+
function stopRecording2() {
|
|
261
|
+
isRecording = false;
|
|
262
|
+
}
|
|
263
|
+
function isEventRecording() {
|
|
264
|
+
return isRecording;
|
|
265
|
+
}
|
|
266
|
+
function subscribeEvents(callback) {
|
|
267
|
+
eventSubscribers.push(callback);
|
|
268
|
+
return () => {
|
|
269
|
+
const index = eventSubscribers.indexOf(callback);
|
|
270
|
+
if (index > -1) {
|
|
271
|
+
eventSubscribers.splice(index, 1);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function getEventCount() {
|
|
276
|
+
return events.length;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/snapshots.ts
|
|
280
|
+
var snapshots = /* @__PURE__ */ new Map();
|
|
281
|
+
var snapshotIdCounter = 0;
|
|
282
|
+
function generateSnapshotId() {
|
|
283
|
+
return `snapshot-${++snapshotIdCounter}-${Date.now().toString(36)}`;
|
|
284
|
+
}
|
|
285
|
+
function takeSnapshot(components2, signals2, events2) {
|
|
286
|
+
const snapshot = {
|
|
287
|
+
id: generateSnapshotId(),
|
|
288
|
+
timestamp: Date.now(),
|
|
289
|
+
components: components2 || [],
|
|
290
|
+
signals: signals2 || [],
|
|
291
|
+
events: events2 || []
|
|
292
|
+
};
|
|
293
|
+
snapshots.set(snapshot.id, snapshot);
|
|
294
|
+
return snapshot;
|
|
295
|
+
}
|
|
296
|
+
function createSnapshot(id, data, description) {
|
|
297
|
+
const snapshot = {
|
|
298
|
+
id,
|
|
299
|
+
timestamp: Date.now(),
|
|
300
|
+
components: [],
|
|
301
|
+
signals: Object.entries(data).map(([name, value]) => ({
|
|
302
|
+
id: `signal-${name}`,
|
|
303
|
+
name,
|
|
304
|
+
type: "signal",
|
|
305
|
+
value,
|
|
306
|
+
dependencies: [],
|
|
307
|
+
dependents: []
|
|
308
|
+
})),
|
|
309
|
+
events: description ? [
|
|
310
|
+
{
|
|
311
|
+
id: `event-${Date.now()}`,
|
|
312
|
+
type: "store:mutation",
|
|
313
|
+
timestamp: Date.now(),
|
|
314
|
+
payload: { description }
|
|
315
|
+
}
|
|
316
|
+
] : []
|
|
317
|
+
};
|
|
318
|
+
snapshots.set(id, snapshot);
|
|
319
|
+
return snapshot;
|
|
320
|
+
}
|
|
321
|
+
function getSnapshot(id) {
|
|
322
|
+
return snapshots.get(id);
|
|
323
|
+
}
|
|
324
|
+
function getSnapshotById(id) {
|
|
325
|
+
return snapshots.get(id);
|
|
326
|
+
}
|
|
327
|
+
function getAllSnapshots() {
|
|
328
|
+
return Array.from(snapshots.values()).sort((a, b) => a.timestamp - b.timestamp);
|
|
329
|
+
}
|
|
330
|
+
function getSnapshots() {
|
|
331
|
+
return getAllSnapshots();
|
|
332
|
+
}
|
|
333
|
+
function deleteSnapshot(id) {
|
|
334
|
+
return snapshots.delete(id);
|
|
335
|
+
}
|
|
336
|
+
function clearSnapshots() {
|
|
337
|
+
snapshots.clear();
|
|
338
|
+
}
|
|
339
|
+
function exportSnapshots() {
|
|
340
|
+
return JSON.stringify(getAllSnapshots(), null, 2);
|
|
341
|
+
}
|
|
342
|
+
function importSnapshots(json) {
|
|
343
|
+
try {
|
|
344
|
+
const parsed = JSON.parse(json);
|
|
345
|
+
parsed.forEach((s) => snapshots.set(s.id, s));
|
|
346
|
+
return parsed;
|
|
347
|
+
} catch (e) {
|
|
348
|
+
console.error("[DevTools Snapshots] Import failed:", e);
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function restoreSnapshot(snapshot) {
|
|
353
|
+
try {
|
|
354
|
+
if (!snapshot.signals || snapshot.signals.length === 0) {
|
|
355
|
+
console.warn("[DevTools Snapshots] No signals to restore in snapshot:", snapshot.id);
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
let allSuccess = true;
|
|
359
|
+
for (const signalInfo of snapshot.signals) {
|
|
360
|
+
try {
|
|
361
|
+
const success = setSignalValue(signalInfo.id, signalInfo.value);
|
|
362
|
+
if (!success) {
|
|
363
|
+
console.warn(
|
|
364
|
+
`[DevTools Snapshots] Failed to restore signal "${signalInfo.name}" (id: ${signalInfo.id}): not found in registry`
|
|
365
|
+
);
|
|
366
|
+
allSuccess = false;
|
|
367
|
+
}
|
|
368
|
+
} catch (err) {
|
|
369
|
+
console.error(`[DevTools Snapshots] Error restoring signal "${signalInfo.name}":`, err);
|
|
370
|
+
allSuccess = false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
console.warn("[DevTools Snapshots] Snapshot restored:", snapshot.id);
|
|
374
|
+
return allSuccess;
|
|
375
|
+
} catch (e) {
|
|
376
|
+
console.error("[DevTools Snapshots] Restore failed:", e);
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/bridge.ts
|
|
382
|
+
var handlers = /* @__PURE__ */ new Map();
|
|
383
|
+
var genericHandlers = /* @__PURE__ */ new Set();
|
|
384
|
+
var isActive = false;
|
|
385
|
+
function onPanelMessage(typeOrHandler, handler) {
|
|
386
|
+
if (typeof typeOrHandler === "function") {
|
|
387
|
+
genericHandlers.add(typeOrHandler);
|
|
388
|
+
return () => {
|
|
389
|
+
genericHandlers.delete(typeOrHandler);
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
const type = typeOrHandler;
|
|
393
|
+
if (!handler) {
|
|
394
|
+
throw new Error("Handler is required when specifying a message type");
|
|
395
|
+
}
|
|
396
|
+
if (!handlers.has(type)) {
|
|
397
|
+
handlers.set(type, /* @__PURE__ */ new Set());
|
|
398
|
+
}
|
|
399
|
+
handlers.get(type).add(handler);
|
|
400
|
+
return () => {
|
|
401
|
+
handlers.get(type)?.delete(handler);
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
function sendToPanel(message) {
|
|
405
|
+
const typeHandlers = handlers.get(message.type);
|
|
406
|
+
if (typeHandlers) {
|
|
407
|
+
typeHandlers.forEach((handler) => {
|
|
408
|
+
try {
|
|
409
|
+
handler(message);
|
|
410
|
+
} catch (e) {
|
|
411
|
+
console.error("[DevTools Bridge] Handler error:", e);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
genericHandlers.forEach((handler) => {
|
|
416
|
+
try {
|
|
417
|
+
handler(message);
|
|
418
|
+
} catch (e) {
|
|
419
|
+
console.error("[DevTools Bridge] Generic handler error:", e);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
function broadcastToPanel(message) {
|
|
424
|
+
handlers.forEach((typeHandlers, type) => {
|
|
425
|
+
if (type !== message.type) return;
|
|
426
|
+
typeHandlers.forEach((handler) => {
|
|
427
|
+
try {
|
|
428
|
+
handler(message);
|
|
429
|
+
} catch (e) {
|
|
430
|
+
console.error("[DevTools Bridge] Broadcast error:", e);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
genericHandlers.forEach((handler) => {
|
|
435
|
+
try {
|
|
436
|
+
handler(message);
|
|
437
|
+
} catch (e) {
|
|
438
|
+
console.error("[DevTools Bridge] Generic broadcast error:", e);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
function clearHandlers() {
|
|
443
|
+
handlers.clear();
|
|
444
|
+
genericHandlers.clear();
|
|
445
|
+
}
|
|
446
|
+
function activateBridge() {
|
|
447
|
+
isActive = true;
|
|
448
|
+
}
|
|
449
|
+
function deactivateBridge() {
|
|
450
|
+
isActive = false;
|
|
451
|
+
}
|
|
452
|
+
function isBridgeActive() {
|
|
453
|
+
return isActive;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// src/api.ts
|
|
457
|
+
function createDevToolsAPI() {
|
|
458
|
+
return {
|
|
459
|
+
getState() {
|
|
460
|
+
return getState();
|
|
461
|
+
},
|
|
462
|
+
enable() {
|
|
463
|
+
enable();
|
|
464
|
+
},
|
|
465
|
+
disable() {
|
|
466
|
+
disable();
|
|
467
|
+
},
|
|
468
|
+
getComponentTree() {
|
|
469
|
+
return getComponentTree();
|
|
470
|
+
},
|
|
471
|
+
getComponentById(id) {
|
|
472
|
+
return getComponentById2(id);
|
|
473
|
+
},
|
|
474
|
+
getSignals() {
|
|
475
|
+
return getSignals();
|
|
476
|
+
},
|
|
477
|
+
getSignalValue(id) {
|
|
478
|
+
const signalInfo = getSignalById(id);
|
|
479
|
+
return signalInfo?.value;
|
|
480
|
+
},
|
|
481
|
+
startRecording() {
|
|
482
|
+
startRecording2();
|
|
483
|
+
},
|
|
484
|
+
stopRecording() {
|
|
485
|
+
stopRecording2();
|
|
486
|
+
},
|
|
487
|
+
getEvents(filter) {
|
|
488
|
+
const allEvents = getEvents();
|
|
489
|
+
if (!filter) return allEvents;
|
|
490
|
+
return allEvents.filter((e) => filter.includes(e.type));
|
|
491
|
+
},
|
|
492
|
+
clearEvents() {
|
|
493
|
+
clearEvents();
|
|
494
|
+
},
|
|
495
|
+
takeSnapshot() {
|
|
496
|
+
return takeSnapshot();
|
|
497
|
+
},
|
|
498
|
+
restoreSnapshot(snapshot) {
|
|
499
|
+
restoreSnapshot(snapshot);
|
|
500
|
+
},
|
|
501
|
+
getSnapshots() {
|
|
502
|
+
return getSnapshots();
|
|
503
|
+
},
|
|
504
|
+
sendToPanel(message) {
|
|
505
|
+
sendToPanel(message);
|
|
506
|
+
},
|
|
507
|
+
onPanelMessage(handler) {
|
|
508
|
+
return onPanelMessage(handler);
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
function trackStoreMutation(storeId, type, payload) {
|
|
513
|
+
if (!isEventRecording()) return;
|
|
514
|
+
recordEvent("store:mutation", { storeId, mutationType: type, payload });
|
|
515
|
+
}
|
|
516
|
+
function registerStoreSignals(storeId, state) {
|
|
517
|
+
const signalIds = /* @__PURE__ */ new Map();
|
|
518
|
+
for (const [key, value] of Object.entries(state)) {
|
|
519
|
+
const id = commonString.generateId("signal");
|
|
520
|
+
const name = `${storeId}.${key}`;
|
|
521
|
+
registerSignal({ id, name, type: "signal", value });
|
|
522
|
+
signalIds.set(key, id);
|
|
523
|
+
}
|
|
524
|
+
return signalIds;
|
|
525
|
+
}
|
|
526
|
+
function unregisterStoreSignals(signalIds) {
|
|
527
|
+
for (const id of signalIds.values()) {
|
|
528
|
+
unregisterSignal(id);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// src/router-integration.ts
|
|
533
|
+
function trackRouterNavigation(from, to) {
|
|
534
|
+
if (!isEventRecording()) return;
|
|
535
|
+
recordEvent("router:navigation", {
|
|
536
|
+
from: { path: from.path, fullPath: from.fullPath },
|
|
537
|
+
to: { path: to.path, fullPath: to.fullPath }
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/panel/state-editor.ts
|
|
542
|
+
var editorState = {
|
|
543
|
+
selectedComponentId: null,
|
|
544
|
+
expandedPaths: /* @__PURE__ */ new Set(),
|
|
545
|
+
editHistory: []
|
|
546
|
+
};
|
|
547
|
+
function extractComponentState(componentId) {
|
|
548
|
+
const component = getComponentById(componentId);
|
|
549
|
+
if (!component) return null;
|
|
550
|
+
const state = {};
|
|
551
|
+
const props = {};
|
|
552
|
+
for (const [key, value] of Object.entries(component.props || {})) {
|
|
553
|
+
props[key] = {
|
|
554
|
+
type: "primitive",
|
|
555
|
+
value,
|
|
556
|
+
editable: true,
|
|
557
|
+
path: `props.${key}`
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
const signals2 = getSignals();
|
|
561
|
+
for (const signal2 of signals2) {
|
|
562
|
+
if (isSignalBelongsToComponent(
|
|
563
|
+
signal2,
|
|
564
|
+
componentId
|
|
565
|
+
)) {
|
|
566
|
+
state[signal2.name] = {
|
|
567
|
+
type: signal2.type,
|
|
568
|
+
value: signal2.value,
|
|
569
|
+
editable: signal2.type !== "computed",
|
|
570
|
+
path: signal2.name
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return {
|
|
575
|
+
componentId,
|
|
576
|
+
componentName: component.name,
|
|
577
|
+
state,
|
|
578
|
+
props
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
function isSignalBelongsToComponent(signal2, componentId) {
|
|
582
|
+
const signalWithMeta = signal2;
|
|
583
|
+
if (signalWithMeta.componentId === componentId) {
|
|
584
|
+
return true;
|
|
585
|
+
}
|
|
586
|
+
const component = getComponentById(componentId);
|
|
587
|
+
if (component && signal2.name.startsWith(`${component.name}_`)) {
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
function applyStateEdit(componentId, path, value) {
|
|
593
|
+
try {
|
|
594
|
+
const oldValue = getStateValue(componentId, path);
|
|
595
|
+
const signalId = findSignalIdForPath(componentId, path);
|
|
596
|
+
if (!signalId) {
|
|
597
|
+
return {
|
|
598
|
+
success: false,
|
|
599
|
+
error: `Signal not found for path: ${path}`
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
const success = setSignalValue(signalId, value);
|
|
603
|
+
if (!success) {
|
|
604
|
+
return {
|
|
605
|
+
success: false,
|
|
606
|
+
error: "Failed to set signal value"
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
const record = {
|
|
610
|
+
id: `edit-${Date.now()}`,
|
|
611
|
+
timestamp: Date.now(),
|
|
612
|
+
componentId,
|
|
613
|
+
path,
|
|
614
|
+
oldValue,
|
|
615
|
+
newValue: value
|
|
616
|
+
};
|
|
617
|
+
editorState.editHistory.push(record);
|
|
618
|
+
recordEvent("signal:changed", {
|
|
619
|
+
signalId,
|
|
620
|
+
path,
|
|
621
|
+
oldValue,
|
|
622
|
+
newValue: value,
|
|
623
|
+
componentId
|
|
624
|
+
});
|
|
625
|
+
sendToPanel({
|
|
626
|
+
type: "STATE_EDITED",
|
|
627
|
+
payload: {
|
|
628
|
+
componentId,
|
|
629
|
+
path,
|
|
630
|
+
oldValue,
|
|
631
|
+
newValue: value,
|
|
632
|
+
timestamp: record.timestamp
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
return {
|
|
636
|
+
success: true,
|
|
637
|
+
oldValue,
|
|
638
|
+
newValue: value
|
|
639
|
+
};
|
|
640
|
+
} catch (error) {
|
|
641
|
+
return {
|
|
642
|
+
success: false,
|
|
643
|
+
error: error instanceof Error ? error.message : String(error)
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function getStateValue(componentId, path) {
|
|
648
|
+
const componentState = extractComponentState(componentId);
|
|
649
|
+
if (!componentState) return void 0;
|
|
650
|
+
const parts = path.split(".");
|
|
651
|
+
let current = componentState.state;
|
|
652
|
+
for (const part of parts) {
|
|
653
|
+
if (current && typeof current === "object" && part in current) {
|
|
654
|
+
current = current[part];
|
|
655
|
+
} else {
|
|
656
|
+
return void 0;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return current;
|
|
660
|
+
}
|
|
661
|
+
function findSignalIdForPath(componentId, path) {
|
|
662
|
+
const signals2 = getSignals();
|
|
663
|
+
const component = getComponentById(componentId);
|
|
664
|
+
for (const signal2 of signals2) {
|
|
665
|
+
if (isSignalBelongsToComponent(
|
|
666
|
+
signal2,
|
|
667
|
+
componentId
|
|
668
|
+
)) {
|
|
669
|
+
const stateName = component ? signal2.name.substring(component.name.length + 1) : signal2.name;
|
|
670
|
+
if (stateName === path || signal2.name === path) {
|
|
671
|
+
return signal2.id;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
function setNestedValue(obj, path, value) {
|
|
678
|
+
const parts = path.split(".");
|
|
679
|
+
let current = obj;
|
|
680
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
681
|
+
const part = parts[i];
|
|
682
|
+
if (!(part in current) || typeof current[part] !== "object") {
|
|
683
|
+
current[part] = {};
|
|
684
|
+
}
|
|
685
|
+
current = current[part];
|
|
686
|
+
}
|
|
687
|
+
const lastPart = parts[parts.length - 1];
|
|
688
|
+
current[lastPart] = value;
|
|
689
|
+
return true;
|
|
690
|
+
}
|
|
691
|
+
function getNestedValue(obj, path) {
|
|
692
|
+
const parts = path.split(".");
|
|
693
|
+
let current = obj;
|
|
694
|
+
for (const part of parts) {
|
|
695
|
+
if (current && typeof current === "object" && part in current) {
|
|
696
|
+
current = current[part];
|
|
697
|
+
} else {
|
|
698
|
+
return void 0;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return current;
|
|
702
|
+
}
|
|
703
|
+
function parseValue(input, targetType) {
|
|
704
|
+
const trimmed = input.trim();
|
|
705
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]") || trimmed === "true" || trimmed === "false" || trimmed === "null" || /^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
706
|
+
try {
|
|
707
|
+
return JSON.parse(trimmed);
|
|
708
|
+
} catch {
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
switch (targetType) {
|
|
712
|
+
case "number":
|
|
713
|
+
return parseFloat(trimmed) || 0;
|
|
714
|
+
case "boolean":
|
|
715
|
+
return trimmed === "true" || trimmed === "1";
|
|
716
|
+
case "string":
|
|
717
|
+
default:
|
|
718
|
+
return trimmed;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
function formatValue(value) {
|
|
722
|
+
if (value === null) return "null";
|
|
723
|
+
if (value === void 0) return "undefined";
|
|
724
|
+
if (typeof value === "string") return `"${value}"`;
|
|
725
|
+
if (typeof value === "function") return "\u0192()";
|
|
726
|
+
if (Array.isArray(value)) return `Array(${value.length})`;
|
|
727
|
+
if (typeof value === "object") {
|
|
728
|
+
try {
|
|
729
|
+
return JSON.stringify(value, null, 2);
|
|
730
|
+
} catch {
|
|
731
|
+
return "{...}";
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return String(value);
|
|
735
|
+
}
|
|
736
|
+
function getEditHistory() {
|
|
737
|
+
return [...editorState.editHistory];
|
|
738
|
+
}
|
|
739
|
+
function clearEditHistory() {
|
|
740
|
+
editorState.editHistory = [];
|
|
741
|
+
}
|
|
742
|
+
function undoLastEdit() {
|
|
743
|
+
const lastEdit = editorState.editHistory.pop();
|
|
744
|
+
if (!lastEdit) {
|
|
745
|
+
return { success: false, error: "No edits to undo" };
|
|
746
|
+
}
|
|
747
|
+
return applyStateEdit(lastEdit.componentId, lastEdit.path, lastEdit.oldValue);
|
|
748
|
+
}
|
|
749
|
+
function initStateEditor() {
|
|
750
|
+
const unsubscribe = onPanelMessage((message) => {
|
|
751
|
+
const msg = message;
|
|
752
|
+
switch (msg.type) {
|
|
753
|
+
case "GET_COMPONENT_STATE":
|
|
754
|
+
handleGetComponentState(msg.data);
|
|
755
|
+
break;
|
|
756
|
+
case "EDIT_STATE":
|
|
757
|
+
handleEditState(msg.data);
|
|
758
|
+
break;
|
|
759
|
+
case "GET_EDIT_HISTORY":
|
|
760
|
+
sendToPanel({
|
|
761
|
+
type: "EDIT_HISTORY",
|
|
762
|
+
payload: getEditHistory()
|
|
763
|
+
});
|
|
764
|
+
break;
|
|
765
|
+
case "UNDO_LAST_EDIT":
|
|
766
|
+
handleUndoLastEdit();
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
return unsubscribe;
|
|
771
|
+
}
|
|
772
|
+
function handleGetComponentState(data) {
|
|
773
|
+
if (!data?.componentId) return;
|
|
774
|
+
const state = extractComponentState(data.componentId);
|
|
775
|
+
sendToPanel({
|
|
776
|
+
type: "COMPONENT_STATE",
|
|
777
|
+
payload: state
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
function handleEditState(data) {
|
|
781
|
+
if (!data) return;
|
|
782
|
+
const result = applyStateEdit(data.componentId, data.path, data.value);
|
|
783
|
+
sendToPanel({
|
|
784
|
+
type: "STATE_EDIT_RESULT",
|
|
785
|
+
payload: {
|
|
786
|
+
...result,
|
|
787
|
+
componentId: data.componentId,
|
|
788
|
+
path: data.path
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
function handleUndoLastEdit() {
|
|
793
|
+
const result = undoLastEdit();
|
|
794
|
+
sendToPanel({
|
|
795
|
+
type: "UNDO_RESULT",
|
|
796
|
+
payload: result
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// src/panel/time-travel.ts
|
|
801
|
+
var timeTravelState = {
|
|
802
|
+
isRecording: false,
|
|
803
|
+
currentIndex: -1,
|
|
804
|
+
history: [],
|
|
805
|
+
maxHistorySize: 1e3
|
|
806
|
+
};
|
|
807
|
+
var recordingStartTime = 0;
|
|
808
|
+
var unsubscribeEvents = null;
|
|
809
|
+
function startHistoryRecording() {
|
|
810
|
+
if (timeTravelState.isRecording) return;
|
|
811
|
+
timeTravelState.isRecording = true;
|
|
812
|
+
recordingStartTime = Date.now();
|
|
813
|
+
unsubscribeEvents = subscribeEvents((event) => {
|
|
814
|
+
const eventWithPayload = event;
|
|
815
|
+
addHistoryEntry({
|
|
816
|
+
type: "event",
|
|
817
|
+
description: formatEventDescription(eventWithPayload),
|
|
818
|
+
data: { event: eventWithPayload }
|
|
819
|
+
});
|
|
820
|
+
});
|
|
821
|
+
const snapshot = takeSnapshot();
|
|
822
|
+
addHistoryEntry({
|
|
823
|
+
type: "snapshot",
|
|
824
|
+
description: "Initial state",
|
|
825
|
+
data: { snapshot }
|
|
826
|
+
});
|
|
827
|
+
sendToPanel({
|
|
828
|
+
type: "TIME_TRAVEL_STATUS",
|
|
829
|
+
payload: { isRecording: true, currentIndex: timeTravelState.currentIndex }
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
function stopHistoryRecording() {
|
|
833
|
+
if (!timeTravelState.isRecording) return;
|
|
834
|
+
timeTravelState.isRecording = false;
|
|
835
|
+
if (unsubscribeEvents) {
|
|
836
|
+
unsubscribeEvents();
|
|
837
|
+
unsubscribeEvents = null;
|
|
838
|
+
}
|
|
839
|
+
sendToPanel({
|
|
840
|
+
type: "TIME_TRAVEL_STATUS",
|
|
841
|
+
payload: { isRecording: false, currentIndex: timeTravelState.currentIndex }
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
function addHistoryEntry(entry) {
|
|
845
|
+
const historyEntry = {
|
|
846
|
+
...entry,
|
|
847
|
+
id: `history-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
848
|
+
timestamp: Date.now(),
|
|
849
|
+
index: timeTravelState.history.length
|
|
850
|
+
};
|
|
851
|
+
timeTravelState.history.push(historyEntry);
|
|
852
|
+
if (timeTravelState.history.length > timeTravelState.maxHistorySize) {
|
|
853
|
+
timeTravelState.history.shift();
|
|
854
|
+
timeTravelState.history.forEach((h, i) => {
|
|
855
|
+
h.index = i;
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
timeTravelState.currentIndex = timeTravelState.history.length - 1;
|
|
859
|
+
sendToPanel({
|
|
860
|
+
type: "HISTORY_UPDATED",
|
|
861
|
+
payload: {
|
|
862
|
+
entry: historyEntry,
|
|
863
|
+
totalEntries: timeTravelState.history.length,
|
|
864
|
+
currentIndex: timeTravelState.currentIndex
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
function formatEventDescription(event) {
|
|
869
|
+
switch (event.type) {
|
|
870
|
+
case "component:created":
|
|
871
|
+
return `Component created: ${event.payload?.name || "Unknown"}`;
|
|
872
|
+
case "component:mounted":
|
|
873
|
+
return `Component mounted: ${event.payload?.name || "Unknown"}`;
|
|
874
|
+
case "component:updated":
|
|
875
|
+
return `Component updated: ${event.payload?.name || "Unknown"}`;
|
|
876
|
+
case "component:unmounted":
|
|
877
|
+
return `Component unmounted: ${event.payload?.name || "Unknown"}`;
|
|
878
|
+
case "signal:changed":
|
|
879
|
+
return `State changed: ${event.payload?.path || "Unknown"}`;
|
|
880
|
+
case "store:mutation":
|
|
881
|
+
return `Store mutation: ${event.payload?.type || "Unknown"}`;
|
|
882
|
+
case "router:navigation":
|
|
883
|
+
return `Navigation: ${event.payload?.to || "Unknown"}`;
|
|
884
|
+
case "error:captured":
|
|
885
|
+
return `Error: ${event.payload?.message || "Unknown"}`;
|
|
886
|
+
default:
|
|
887
|
+
return `Event: ${event.type}`;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
function jumpToHistory(index) {
|
|
891
|
+
if (index < 0 || index >= timeTravelState.history.length) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
const entry = timeTravelState.history[index];
|
|
895
|
+
timeTravelState.currentIndex = index;
|
|
896
|
+
if (entry.data.snapshot) {
|
|
897
|
+
restoreSnapshot(entry.data.snapshot);
|
|
898
|
+
} else if (entry.data.event?.type === "signal:changed") {
|
|
899
|
+
const payload = entry.data.event.payload;
|
|
900
|
+
if (payload?.signalId && payload?.newValue !== void 0) {
|
|
901
|
+
setSignalValue(payload.signalId, payload.newValue);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
sendToPanel({
|
|
905
|
+
type: "TIME_TRAVEL_JUMP",
|
|
906
|
+
payload: {
|
|
907
|
+
index,
|
|
908
|
+
entry,
|
|
909
|
+
canGoBack: index > 0,
|
|
910
|
+
canGoForward: index < timeTravelState.history.length - 1
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
return true;
|
|
914
|
+
}
|
|
915
|
+
function goBack() {
|
|
916
|
+
if (timeTravelState.currentIndex <= 0) {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
return jumpToHistory(timeTravelState.currentIndex - 1);
|
|
920
|
+
}
|
|
921
|
+
function goForward() {
|
|
922
|
+
if (timeTravelState.currentIndex >= timeTravelState.history.length - 1) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
return jumpToHistory(timeTravelState.currentIndex + 1);
|
|
926
|
+
}
|
|
927
|
+
function goToStart() {
|
|
928
|
+
if (timeTravelState.history.length === 0) {
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
return jumpToHistory(0);
|
|
932
|
+
}
|
|
933
|
+
function goToEnd() {
|
|
934
|
+
if (timeTravelState.history.length === 0) {
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
937
|
+
return jumpToHistory(timeTravelState.history.length - 1);
|
|
938
|
+
}
|
|
939
|
+
function getHistory() {
|
|
940
|
+
return [...timeTravelState.history];
|
|
941
|
+
}
|
|
942
|
+
function getCurrentIndex() {
|
|
943
|
+
return timeTravelState.currentIndex;
|
|
944
|
+
}
|
|
945
|
+
function clearHistory() {
|
|
946
|
+
timeTravelState.history = [];
|
|
947
|
+
timeTravelState.currentIndex = -1;
|
|
948
|
+
clearEvents();
|
|
949
|
+
sendToPanel({
|
|
950
|
+
type: "HISTORY_CLEARED",
|
|
951
|
+
payload: {}
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
function exportHistory() {
|
|
955
|
+
const exportData = {
|
|
956
|
+
version: "1.0.0",
|
|
957
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
958
|
+
history: timeTravelState.history,
|
|
959
|
+
snapshots: getSnapshots(),
|
|
960
|
+
metadata: {
|
|
961
|
+
totalEvents: timeTravelState.history.filter((h) => h.type === "event").length,
|
|
962
|
+
recordingDuration: recordingStartTime ? Date.now() - recordingStartTime : 0
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
return JSON.stringify(exportData, null, 2);
|
|
966
|
+
}
|
|
967
|
+
function importHistory(json) {
|
|
968
|
+
try {
|
|
969
|
+
const data = JSON.parse(json);
|
|
970
|
+
if (!data.version || !data.history) {
|
|
971
|
+
throw new Error("Invalid export format");
|
|
972
|
+
}
|
|
973
|
+
clearHistory();
|
|
974
|
+
timeTravelState.history = data.history.map((h, i) => ({
|
|
975
|
+
...h,
|
|
976
|
+
index: i
|
|
977
|
+
}));
|
|
978
|
+
timeTravelState.currentIndex = timeTravelState.history.length - 1;
|
|
979
|
+
sendToPanel({
|
|
980
|
+
type: "HISTORY_IMPORTED",
|
|
981
|
+
payload: {
|
|
982
|
+
totalEntries: timeTravelState.history.length,
|
|
983
|
+
currentIndex: timeTravelState.currentIndex
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
return true;
|
|
987
|
+
} catch (error) {
|
|
988
|
+
sendToPanel({
|
|
989
|
+
type: "HISTORY_IMPORT_ERROR",
|
|
990
|
+
payload: { error: error instanceof Error ? error.message : String(error) }
|
|
991
|
+
});
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
function downloadHistory(filename) {
|
|
996
|
+
if (typeof document === "undefined" || typeof Blob === "undefined" || typeof URL === "undefined") {
|
|
997
|
+
console.warn("[DevTools TimeTravel] downloadHistory is only available in browser environment");
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
const data = exportHistory();
|
|
1001
|
+
const blob = new Blob([data], { type: "application/json" });
|
|
1002
|
+
const url = URL.createObjectURL(blob);
|
|
1003
|
+
const a = document.createElement("a");
|
|
1004
|
+
a.href = url;
|
|
1005
|
+
a.download = filename || `lytjs-history-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`;
|
|
1006
|
+
document.body.appendChild(a);
|
|
1007
|
+
a.click();
|
|
1008
|
+
document.body.removeChild(a);
|
|
1009
|
+
URL.revokeObjectURL(url);
|
|
1010
|
+
}
|
|
1011
|
+
function compareSnapshots(snapshot1, snapshot2) {
|
|
1012
|
+
const diffs = [];
|
|
1013
|
+
const signals1 = new Map(snapshot1.signals.map((s) => [s.id, s]));
|
|
1014
|
+
const signals2 = new Map(snapshot2.signals.map((s) => [s.id, s]));
|
|
1015
|
+
for (const [id, signal2] of signals2) {
|
|
1016
|
+
const signal1 = signals1.get(id);
|
|
1017
|
+
if (!signal1) {
|
|
1018
|
+
diffs.push({
|
|
1019
|
+
path: `signals.${signal2.name}`,
|
|
1020
|
+
oldValue: void 0,
|
|
1021
|
+
newValue: signal2.value
|
|
1022
|
+
});
|
|
1023
|
+
} else if (JSON.stringify(signal1.value) !== JSON.stringify(signal2.value)) {
|
|
1024
|
+
diffs.push({
|
|
1025
|
+
path: `signals.${signal2.name}`,
|
|
1026
|
+
oldValue: signal1.value,
|
|
1027
|
+
newValue: signal2.value
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
for (const [id, signal1] of signals1) {
|
|
1032
|
+
if (!signals2.has(id)) {
|
|
1033
|
+
diffs.push({
|
|
1034
|
+
path: `signals.${signal1.name}`,
|
|
1035
|
+
oldValue: signal1.value,
|
|
1036
|
+
newValue: void 0
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
return diffs;
|
|
1041
|
+
}
|
|
1042
|
+
function getStateDiffForEntry(index) {
|
|
1043
|
+
if (index <= 0 || index >= timeTravelState.history.length) {
|
|
1044
|
+
return [];
|
|
1045
|
+
}
|
|
1046
|
+
const currentEntry = timeTravelState.history[index];
|
|
1047
|
+
const previousEntry = timeTravelState.history[index - 1];
|
|
1048
|
+
if (currentEntry.data.snapshot && previousEntry.data.snapshot) {
|
|
1049
|
+
return compareSnapshots(previousEntry.data.snapshot, currentEntry.data.snapshot);
|
|
1050
|
+
}
|
|
1051
|
+
return currentEntry.data.stateDiff || [];
|
|
1052
|
+
}
|
|
1053
|
+
function initTimeTravel() {
|
|
1054
|
+
const unsubscribe = onPanelMessage((message) => {
|
|
1055
|
+
const msg = message;
|
|
1056
|
+
switch (msg.type) {
|
|
1057
|
+
case "START_TIME_TRAVEL_RECORDING":
|
|
1058
|
+
startHistoryRecording();
|
|
1059
|
+
break;
|
|
1060
|
+
case "STOP_TIME_TRAVEL_RECORDING":
|
|
1061
|
+
stopHistoryRecording();
|
|
1062
|
+
break;
|
|
1063
|
+
case "JUMP_TO_HISTORY":
|
|
1064
|
+
handleJumpToHistory(msg.data);
|
|
1065
|
+
break;
|
|
1066
|
+
case "GO_BACK":
|
|
1067
|
+
handleGoBack();
|
|
1068
|
+
break;
|
|
1069
|
+
case "GO_FORWARD":
|
|
1070
|
+
handleGoForward();
|
|
1071
|
+
break;
|
|
1072
|
+
case "GO_TO_START":
|
|
1073
|
+
handleGoToStart();
|
|
1074
|
+
break;
|
|
1075
|
+
case "GO_TO_END":
|
|
1076
|
+
handleGoToEnd();
|
|
1077
|
+
break;
|
|
1078
|
+
case "GET_HISTORY":
|
|
1079
|
+
sendToPanel({
|
|
1080
|
+
type: "HISTORY_LIST",
|
|
1081
|
+
payload: {
|
|
1082
|
+
history: getHistory(),
|
|
1083
|
+
currentIndex: getCurrentIndex(),
|
|
1084
|
+
isRecording: timeTravelState.isRecording
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
break;
|
|
1088
|
+
case "CLEAR_HISTORY":
|
|
1089
|
+
clearHistory();
|
|
1090
|
+
break;
|
|
1091
|
+
case "EXPORT_HISTORY":
|
|
1092
|
+
handleExportHistory();
|
|
1093
|
+
break;
|
|
1094
|
+
case "IMPORT_HISTORY":
|
|
1095
|
+
handleImportHistory(msg.data);
|
|
1096
|
+
break;
|
|
1097
|
+
case "GET_STATE_DIFF":
|
|
1098
|
+
handleGetStateDiff(msg.data);
|
|
1099
|
+
break;
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
return unsubscribe;
|
|
1103
|
+
}
|
|
1104
|
+
function handleJumpToHistory(data) {
|
|
1105
|
+
if (data) {
|
|
1106
|
+
const success = jumpToHistory(data.index);
|
|
1107
|
+
sendToPanel({
|
|
1108
|
+
type: "JUMP_RESULT",
|
|
1109
|
+
payload: { success, index: data.index }
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
function handleGoBack() {
|
|
1114
|
+
const success = goBack();
|
|
1115
|
+
sendToPanel({
|
|
1116
|
+
type: "NAVIGATION_RESULT",
|
|
1117
|
+
payload: { direction: "back", success, currentIndex: getCurrentIndex() }
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
function handleGoForward() {
|
|
1121
|
+
const success = goForward();
|
|
1122
|
+
sendToPanel({
|
|
1123
|
+
type: "NAVIGATION_RESULT",
|
|
1124
|
+
payload: { direction: "forward", success, currentIndex: getCurrentIndex() }
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
function handleGoToStart() {
|
|
1128
|
+
const success = goToStart();
|
|
1129
|
+
sendToPanel({
|
|
1130
|
+
type: "NAVIGATION_RESULT",
|
|
1131
|
+
payload: { direction: "start", success, currentIndex: getCurrentIndex() }
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
function handleGoToEnd() {
|
|
1135
|
+
const success = goToEnd();
|
|
1136
|
+
sendToPanel({
|
|
1137
|
+
type: "NAVIGATION_RESULT",
|
|
1138
|
+
payload: { direction: "end", success, currentIndex: getCurrentIndex() }
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
function handleExportHistory() {
|
|
1142
|
+
const data = exportHistory();
|
|
1143
|
+
sendToPanel({
|
|
1144
|
+
type: "HISTORY_EXPORTED",
|
|
1145
|
+
payload: { json: data }
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
function handleImportHistory(data) {
|
|
1149
|
+
if (data?.json) {
|
|
1150
|
+
const success = importHistory(data.json);
|
|
1151
|
+
sendToPanel({
|
|
1152
|
+
type: "HISTORY_IMPORT_RESULT",
|
|
1153
|
+
payload: { success }
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
function handleGetStateDiff(data) {
|
|
1158
|
+
if (data) {
|
|
1159
|
+
const diffs = getStateDiffForEntry(data.index);
|
|
1160
|
+
sendToPanel({
|
|
1161
|
+
type: "STATE_DIFF",
|
|
1162
|
+
payload: { index: data.index, diffs }
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
// src/panel/performance.ts
|
|
1168
|
+
var performanceConfig = {
|
|
1169
|
+
maxRenderHistory: 50,
|
|
1170
|
+
slowRenderThreshold: 16,
|
|
1171
|
+
// 60fps = 16.67ms per frame
|
|
1172
|
+
timelineMaxSize: 100,
|
|
1173
|
+
updateInterval: 1e3
|
|
1174
|
+
};
|
|
1175
|
+
var componentPerformanceMap = /* @__PURE__ */ new Map();
|
|
1176
|
+
var performanceTimeline = [];
|
|
1177
|
+
var isMonitoring = false;
|
|
1178
|
+
var updateIntervalId = null;
|
|
1179
|
+
var frameCount = 0;
|
|
1180
|
+
var lastFpsUpdate = 0;
|
|
1181
|
+
var currentFps = 0;
|
|
1182
|
+
function recordComponentRender(componentId, componentName, renderTime) {
|
|
1183
|
+
if (!isMonitoring) return;
|
|
1184
|
+
const existing = componentPerformanceMap.get(componentId);
|
|
1185
|
+
const now = Date.now();
|
|
1186
|
+
if (existing) {
|
|
1187
|
+
existing.renderCount++;
|
|
1188
|
+
existing.totalRenderTime += renderTime;
|
|
1189
|
+
existing.averageRenderTime = existing.totalRenderTime / existing.renderCount;
|
|
1190
|
+
existing.lastRenderTime = renderTime;
|
|
1191
|
+
existing.minRenderTime = Math.min(existing.minRenderTime, renderTime);
|
|
1192
|
+
existing.maxRenderTime = Math.max(existing.maxRenderTime, renderTime);
|
|
1193
|
+
existing.lastRenderTimestamp = now;
|
|
1194
|
+
existing.renderTimes.push(renderTime);
|
|
1195
|
+
if (existing.renderTimes.length > performanceConfig.maxRenderHistory) {
|
|
1196
|
+
existing.renderTimes.shift();
|
|
1197
|
+
}
|
|
1198
|
+
existing.updateFrequency = calculateUpdateFrequency(existing);
|
|
1199
|
+
} else {
|
|
1200
|
+
const performance2 = {
|
|
1201
|
+
componentId,
|
|
1202
|
+
componentName,
|
|
1203
|
+
renderCount: 1,
|
|
1204
|
+
totalRenderTime: renderTime,
|
|
1205
|
+
averageRenderTime: renderTime,
|
|
1206
|
+
lastRenderTime: renderTime,
|
|
1207
|
+
minRenderTime: renderTime,
|
|
1208
|
+
maxRenderTime: renderTime,
|
|
1209
|
+
renderTimes: [renderTime],
|
|
1210
|
+
lastRenderTimestamp: now,
|
|
1211
|
+
updateFrequency: "low"
|
|
1212
|
+
};
|
|
1213
|
+
componentPerformanceMap.set(componentId, performance2);
|
|
1214
|
+
}
|
|
1215
|
+
if (renderTime > performanceConfig.slowRenderThreshold) {
|
|
1216
|
+
recordEvent("error:captured", {
|
|
1217
|
+
type: "slow-render",
|
|
1218
|
+
componentId,
|
|
1219
|
+
componentName,
|
|
1220
|
+
renderTime
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
function calculateUpdateFrequency(performance2) {
|
|
1225
|
+
const recentRenders = performance2.renderTimes.length;
|
|
1226
|
+
const avgTime = performance2.averageRenderTime;
|
|
1227
|
+
if (recentRenders > 30 || avgTime > 50) return "extreme";
|
|
1228
|
+
if (recentRenders > 15 || avgTime > 30) return "high";
|
|
1229
|
+
if (recentRenders > 5 || avgTime > 16) return "medium";
|
|
1230
|
+
return "low";
|
|
1231
|
+
}
|
|
1232
|
+
function getComponentPerformance(componentId) {
|
|
1233
|
+
return componentPerformanceMap.get(componentId);
|
|
1234
|
+
}
|
|
1235
|
+
function getAllComponentPerformance() {
|
|
1236
|
+
return Array.from(componentPerformanceMap.values());
|
|
1237
|
+
}
|
|
1238
|
+
function clearComponentPerformance() {
|
|
1239
|
+
componentPerformanceMap.clear();
|
|
1240
|
+
}
|
|
1241
|
+
function startPerformanceMonitoring() {
|
|
1242
|
+
if (isMonitoring) return;
|
|
1243
|
+
isMonitoring = true;
|
|
1244
|
+
lastFpsUpdate = performance.now();
|
|
1245
|
+
frameCount = 0;
|
|
1246
|
+
if (typeof requestAnimationFrame !== "undefined") {
|
|
1247
|
+
requestAnimationFrame(updateFps);
|
|
1248
|
+
}
|
|
1249
|
+
updateIntervalId = setInterval(() => {
|
|
1250
|
+
updatePerformanceMetrics();
|
|
1251
|
+
}, performanceConfig.updateInterval);
|
|
1252
|
+
sendToPanel({
|
|
1253
|
+
type: "PERFORMANCE_MONITORING_STATUS",
|
|
1254
|
+
payload: { isMonitoring: true }
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
function stopPerformanceMonitoring() {
|
|
1258
|
+
if (!isMonitoring) return;
|
|
1259
|
+
isMonitoring = false;
|
|
1260
|
+
if (updateIntervalId) {
|
|
1261
|
+
clearInterval(updateIntervalId);
|
|
1262
|
+
updateIntervalId = null;
|
|
1263
|
+
}
|
|
1264
|
+
sendToPanel({
|
|
1265
|
+
type: "PERFORMANCE_MONITORING_STATUS",
|
|
1266
|
+
payload: { isMonitoring: false }
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
function isPerformanceMonitoring() {
|
|
1270
|
+
return isMonitoring;
|
|
1271
|
+
}
|
|
1272
|
+
function updateFps() {
|
|
1273
|
+
if (!isMonitoring) return;
|
|
1274
|
+
frameCount++;
|
|
1275
|
+
const now = performance.now();
|
|
1276
|
+
if (now - lastFpsUpdate >= 1e3) {
|
|
1277
|
+
currentFps = Math.round(frameCount * 1e3 / (now - lastFpsUpdate));
|
|
1278
|
+
frameCount = 0;
|
|
1279
|
+
lastFpsUpdate = now;
|
|
1280
|
+
}
|
|
1281
|
+
if (typeof requestAnimationFrame !== "undefined") {
|
|
1282
|
+
requestAnimationFrame(updateFps);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
function updatePerformanceMetrics() {
|
|
1286
|
+
if (!isMonitoring) return;
|
|
1287
|
+
const metrics = collectPerformanceMetrics();
|
|
1288
|
+
const slowRenders = findSlowRenders();
|
|
1289
|
+
const entry = {
|
|
1290
|
+
timestamp: Date.now(),
|
|
1291
|
+
metrics,
|
|
1292
|
+
slowRenders
|
|
1293
|
+
};
|
|
1294
|
+
performanceTimeline.push(entry);
|
|
1295
|
+
if (performanceTimeline.length > performanceConfig.timelineMaxSize) {
|
|
1296
|
+
performanceTimeline.shift();
|
|
1297
|
+
}
|
|
1298
|
+
sendToPanel({
|
|
1299
|
+
type: "PERFORMANCE_METRICS",
|
|
1300
|
+
payload: {
|
|
1301
|
+
metrics,
|
|
1302
|
+
slowRenders,
|
|
1303
|
+
timeline: getPerformanceTimelineSummary()
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
function collectPerformanceMetrics() {
|
|
1308
|
+
const components2 = getAllComponentPerformance();
|
|
1309
|
+
const totalRenders = components2.reduce((sum, c) => sum + c.renderCount, 0);
|
|
1310
|
+
const avgRenderTime = components2.length > 0 ? components2.reduce((sum, c) => sum + c.averageRenderTime, 0) / components2.length : 0;
|
|
1311
|
+
return {
|
|
1312
|
+
timestamp: Date.now(),
|
|
1313
|
+
totalComponents: components2.length,
|
|
1314
|
+
totalRenders,
|
|
1315
|
+
averageRenderTime: Math.round(avgRenderTime * 100) / 100,
|
|
1316
|
+
memoryUsage: getMemoryInfo(),
|
|
1317
|
+
fps: currentFps
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
function getMemoryInfo() {
|
|
1321
|
+
const perf = performance;
|
|
1322
|
+
if (typeof performance !== "undefined" && perf.memory) {
|
|
1323
|
+
const mem = perf.memory;
|
|
1324
|
+
return {
|
|
1325
|
+
usedJSHeapSize: mem.usedJSHeapSize,
|
|
1326
|
+
totalJSHeapSize: mem.totalJSHeapSize,
|
|
1327
|
+
jsHeapSizeLimit: mem.jsHeapSizeLimit
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
return void 0;
|
|
1331
|
+
}
|
|
1332
|
+
function findSlowRenders() {
|
|
1333
|
+
const slowRenders = [];
|
|
1334
|
+
for (const perf of componentPerformanceMap.values()) {
|
|
1335
|
+
if (perf.lastRenderTime > performanceConfig.slowRenderThreshold) {
|
|
1336
|
+
slowRenders.push({
|
|
1337
|
+
componentId: perf.componentId,
|
|
1338
|
+
componentName: perf.componentName,
|
|
1339
|
+
renderTime: perf.lastRenderTime,
|
|
1340
|
+
timestamp: perf.lastRenderTimestamp
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
return slowRenders.sort((a, b) => b.renderTime - a.renderTime).slice(0, 10);
|
|
1345
|
+
}
|
|
1346
|
+
function getRenderHeatmap() {
|
|
1347
|
+
const components2 = getAllComponentPerformance();
|
|
1348
|
+
if (components2.length === 0) return [];
|
|
1349
|
+
const maxRenders = Math.max(...components2.map((c) => c.renderCount), 1);
|
|
1350
|
+
const maxAvgTime = Math.max(...components2.map((c) => c.averageRenderTime), 1);
|
|
1351
|
+
return components2.map((c) => {
|
|
1352
|
+
const countIntensity = c.renderCount / maxRenders;
|
|
1353
|
+
const timeIntensity = Math.min(c.averageRenderTime / maxAvgTime, 1);
|
|
1354
|
+
const intensity = countIntensity * 0.5 + timeIntensity * 0.5;
|
|
1355
|
+
return {
|
|
1356
|
+
componentId: c.componentId,
|
|
1357
|
+
componentName: c.componentName,
|
|
1358
|
+
intensity: Math.round(intensity * 100) / 100,
|
|
1359
|
+
renderCount: c.renderCount,
|
|
1360
|
+
frequency: c.updateFrequency
|
|
1361
|
+
};
|
|
1362
|
+
}).sort((a, b) => b.intensity - a.intensity);
|
|
1363
|
+
}
|
|
1364
|
+
function getPerformanceTimeline() {
|
|
1365
|
+
return [...performanceTimeline];
|
|
1366
|
+
}
|
|
1367
|
+
function getPerformanceTimelineSummary() {
|
|
1368
|
+
return {
|
|
1369
|
+
timestamps: performanceTimeline.map((e) => e.timestamp),
|
|
1370
|
+
fps: performanceTimeline.map((e) => e.metrics.fps || 0),
|
|
1371
|
+
memory: performanceTimeline.map((e) => e.metrics.memoryUsage?.usedJSHeapSize || 0),
|
|
1372
|
+
renderCounts: performanceTimeline.map((e) => e.metrics.totalRenders)
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
function clearPerformanceTimeline() {
|
|
1376
|
+
performanceTimeline.length = 0;
|
|
1377
|
+
}
|
|
1378
|
+
function getMemoryTrend() {
|
|
1379
|
+
const entries = performanceTimeline.filter((e) => e.metrics.memoryUsage);
|
|
1380
|
+
return {
|
|
1381
|
+
timestamps: entries.map((e) => e.timestamp),
|
|
1382
|
+
used: entries.map((e) => e.metrics.memoryUsage.usedJSHeapSize / 1024 / 1024),
|
|
1383
|
+
// MB
|
|
1384
|
+
total: entries.map((e) => e.metrics.memoryUsage.totalJSHeapSize / 1024 / 1024),
|
|
1385
|
+
// MB
|
|
1386
|
+
limit: entries.map((e) => e.metrics.memoryUsage.jsHeapSizeLimit / 1024 / 1024)
|
|
1387
|
+
// MB
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
function suggestGarbageCollection() {
|
|
1391
|
+
const globalWithGC = globalThis;
|
|
1392
|
+
if (typeof globalWithGC.gc === "function") {
|
|
1393
|
+
try {
|
|
1394
|
+
globalWithGC.gc();
|
|
1395
|
+
sendToPanel({
|
|
1396
|
+
type: "GC_SUGGESTED",
|
|
1397
|
+
payload: { success: true }
|
|
1398
|
+
});
|
|
1399
|
+
} catch (e) {
|
|
1400
|
+
sendToPanel({
|
|
1401
|
+
type: "GC_SUGGESTED",
|
|
1402
|
+
payload: { success: false, error: String(e) }
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
} else {
|
|
1406
|
+
sendToPanel({
|
|
1407
|
+
type: "GC_SUGGESTED",
|
|
1408
|
+
payload: { success: false, error: "GC not available" }
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
function updatePerformanceConfig(config) {
|
|
1413
|
+
Object.assign(performanceConfig, config);
|
|
1414
|
+
sendToPanel({
|
|
1415
|
+
type: "PERFORMANCE_CONFIG_UPDATED",
|
|
1416
|
+
payload: performanceConfig
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
function getPerformanceConfig() {
|
|
1420
|
+
return { ...performanceConfig };
|
|
1421
|
+
}
|
|
1422
|
+
function initPerformancePanel() {
|
|
1423
|
+
const unsubscribe = onPanelMessage((message) => {
|
|
1424
|
+
const msg = message;
|
|
1425
|
+
switch (msg.type) {
|
|
1426
|
+
case "START_PERFORMANCE_MONITORING":
|
|
1427
|
+
startPerformanceMonitoring();
|
|
1428
|
+
break;
|
|
1429
|
+
case "STOP_PERFORMANCE_MONITORING":
|
|
1430
|
+
stopPerformanceMonitoring();
|
|
1431
|
+
break;
|
|
1432
|
+
case "GET_PERFORMANCE_METRICS":
|
|
1433
|
+
handleGetPerformanceMetrics();
|
|
1434
|
+
break;
|
|
1435
|
+
case "GET_RENDER_HEATMAP":
|
|
1436
|
+
handleGetRenderHeatmap();
|
|
1437
|
+
break;
|
|
1438
|
+
case "GET_COMPONENT_PERFORMANCE":
|
|
1439
|
+
handleGetComponentPerformance(msg.data);
|
|
1440
|
+
break;
|
|
1441
|
+
case "GET_PERFORMANCE_TIMELINE":
|
|
1442
|
+
handleGetPerformanceTimeline();
|
|
1443
|
+
break;
|
|
1444
|
+
case "GET_MEMORY_TREND":
|
|
1445
|
+
handleGetMemoryTrend();
|
|
1446
|
+
break;
|
|
1447
|
+
case "CLEAR_PERFORMANCE_DATA":
|
|
1448
|
+
clearComponentPerformance();
|
|
1449
|
+
clearPerformanceTimeline();
|
|
1450
|
+
sendToPanel({ type: "PERFORMANCE_DATA_CLEARED", payload: {} });
|
|
1451
|
+
break;
|
|
1452
|
+
case "SUGGEST_GC":
|
|
1453
|
+
suggestGarbageCollection();
|
|
1454
|
+
break;
|
|
1455
|
+
case "UPDATE_PERFORMANCE_CONFIG":
|
|
1456
|
+
if (msg.data) {
|
|
1457
|
+
updatePerformanceConfig(msg.data);
|
|
1458
|
+
}
|
|
1459
|
+
break;
|
|
1460
|
+
case "GET_PERFORMANCE_CONFIG":
|
|
1461
|
+
sendToPanel({
|
|
1462
|
+
type: "PERFORMANCE_CONFIG",
|
|
1463
|
+
payload: getPerformanceConfig()
|
|
1464
|
+
});
|
|
1465
|
+
break;
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1468
|
+
return unsubscribe;
|
|
1469
|
+
}
|
|
1470
|
+
function handleGetPerformanceMetrics() {
|
|
1471
|
+
const metrics = collectPerformanceMetrics();
|
|
1472
|
+
const slowRenders = findSlowRenders();
|
|
1473
|
+
sendToPanel({
|
|
1474
|
+
type: "PERFORMANCE_METRICS",
|
|
1475
|
+
payload: {
|
|
1476
|
+
metrics,
|
|
1477
|
+
slowRenders,
|
|
1478
|
+
isMonitoring
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
function handleGetRenderHeatmap() {
|
|
1483
|
+
const heatmap = getRenderHeatmap();
|
|
1484
|
+
sendToPanel({
|
|
1485
|
+
type: "RENDER_HEATMAP",
|
|
1486
|
+
payload: heatmap
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1489
|
+
function handleGetComponentPerformance(data) {
|
|
1490
|
+
if (!data?.componentId) return;
|
|
1491
|
+
const performance2 = getComponentPerformance(data.componentId);
|
|
1492
|
+
sendToPanel({
|
|
1493
|
+
type: "COMPONENT_PERFORMANCE",
|
|
1494
|
+
payload: performance2
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1497
|
+
function handleGetPerformanceTimeline() {
|
|
1498
|
+
sendToPanel({
|
|
1499
|
+
type: "PERFORMANCE_TIMELINE",
|
|
1500
|
+
payload: getPerformanceTimelineSummary()
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
function handleGetMemoryTrend() {
|
|
1504
|
+
sendToPanel({
|
|
1505
|
+
type: "MEMORY_TREND",
|
|
1506
|
+
payload: getMemoryTrend()
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
// src/panel/index.ts
|
|
1511
|
+
var panelState = {
|
|
1512
|
+
isInitialized: false,
|
|
1513
|
+
activeTab: "components",
|
|
1514
|
+
selectedComponentId: null,
|
|
1515
|
+
isRecording: false
|
|
1516
|
+
};
|
|
1517
|
+
var cleanupFunctions = [];
|
|
1518
|
+
function initDevToolsPanel() {
|
|
1519
|
+
if (panelState.isInitialized) return;
|
|
1520
|
+
enable();
|
|
1521
|
+
setConnected(true);
|
|
1522
|
+
cleanupFunctions.push(initStateEditor());
|
|
1523
|
+
cleanupFunctions.push(initTimeTravel());
|
|
1524
|
+
cleanupFunctions.push(initPerformancePanel());
|
|
1525
|
+
cleanupFunctions.push(initPanelMessageHandler());
|
|
1526
|
+
panelState.isInitialized = true;
|
|
1527
|
+
sendInitialData();
|
|
1528
|
+
}
|
|
1529
|
+
function cleanupDevToolsPanel() {
|
|
1530
|
+
if (!panelState.isInitialized) return;
|
|
1531
|
+
cleanupFunctions.forEach((cleanup) => cleanup());
|
|
1532
|
+
cleanupFunctions.length = 0;
|
|
1533
|
+
setConnected(false);
|
|
1534
|
+
panelState.isInitialized = false;
|
|
1535
|
+
}
|
|
1536
|
+
function initPanelMessageHandler() {
|
|
1537
|
+
return onPanelMessage((message) => {
|
|
1538
|
+
const msg = message;
|
|
1539
|
+
switch (msg.type) {
|
|
1540
|
+
case "SWITCH_TAB":
|
|
1541
|
+
if (msg.data && typeof msg.data === "object") {
|
|
1542
|
+
panelState.activeTab = msg.data.tab;
|
|
1543
|
+
}
|
|
1544
|
+
break;
|
|
1545
|
+
case "SELECT_COMPONENT":
|
|
1546
|
+
if (msg.data && typeof msg.data === "object") {
|
|
1547
|
+
panelState.selectedComponentId = msg.data.componentId;
|
|
1548
|
+
}
|
|
1549
|
+
break;
|
|
1550
|
+
case "START_RECORDING":
|
|
1551
|
+
panelState.isRecording = true;
|
|
1552
|
+
startRecording2();
|
|
1553
|
+
break;
|
|
1554
|
+
case "STOP_RECORDING":
|
|
1555
|
+
panelState.isRecording = false;
|
|
1556
|
+
stopRecording2();
|
|
1557
|
+
break;
|
|
1558
|
+
case "REFRESH_DATA":
|
|
1559
|
+
case "GET_ALL_DATA":
|
|
1560
|
+
sendInitialData();
|
|
1561
|
+
break;
|
|
1562
|
+
}
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
function sendInitialData() {
|
|
1566
|
+
sendToPanel({
|
|
1567
|
+
type: "INITIAL_DATA",
|
|
1568
|
+
payload: {
|
|
1569
|
+
state: getState(),
|
|
1570
|
+
componentTree: getComponentTree(),
|
|
1571
|
+
signals: getSignals(),
|
|
1572
|
+
snapshots: getSnapshots(),
|
|
1573
|
+
events: getEvents()
|
|
1574
|
+
}
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
function getPanelState() {
|
|
1578
|
+
return { ...panelState };
|
|
1579
|
+
}
|
|
1580
|
+
function isPanelInitialized() {
|
|
1581
|
+
return panelState.isInitialized;
|
|
1582
|
+
}
|
|
1583
|
+
function setActiveTab(tab) {
|
|
1584
|
+
panelState.activeTab = tab;
|
|
1585
|
+
}
|
|
1586
|
+
function getActiveTab() {
|
|
1587
|
+
return panelState.activeTab;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
exports.activateBridge = activateBridge;
|
|
1591
|
+
exports.applyStateEdit = applyStateEdit;
|
|
1592
|
+
exports.autoRegisterFromInstance = autoRegisterFromInstance;
|
|
1593
|
+
exports.broadcastToPanel = broadcastToPanel;
|
|
1594
|
+
exports.buildComponentTree = buildComponentTree;
|
|
1595
|
+
exports.cleanupDevToolsPanel = cleanupDevToolsPanel;
|
|
1596
|
+
exports.clearComponentPerformance = clearComponentPerformance;
|
|
1597
|
+
exports.clearComponentRegistry = clearComponentRegistry;
|
|
1598
|
+
exports.clearComponents = clearComponents;
|
|
1599
|
+
exports.clearEditHistory = clearEditHistory;
|
|
1600
|
+
exports.clearEvents = clearEvents;
|
|
1601
|
+
exports.clearHandlers = clearHandlers;
|
|
1602
|
+
exports.clearHistory = clearHistory;
|
|
1603
|
+
exports.clearPerformanceTimeline = clearPerformanceTimeline;
|
|
1604
|
+
exports.clearSignalRegistry = clearSignalRegistry;
|
|
1605
|
+
exports.clearSignals = clearSignals;
|
|
1606
|
+
exports.clearSnapshots = clearSnapshots;
|
|
1607
|
+
exports.clearStateSubscribers = clearStateSubscribers;
|
|
1608
|
+
exports.compareSnapshots = compareSnapshots;
|
|
1609
|
+
exports.createDevToolsAPI = createDevToolsAPI;
|
|
1610
|
+
exports.createSnapshot = createSnapshot;
|
|
1611
|
+
exports.deactivateBridge = deactivateBridge;
|
|
1612
|
+
exports.deleteSnapshot = deleteSnapshot;
|
|
1613
|
+
exports.disable = disable;
|
|
1614
|
+
exports.downloadHistory = downloadHistory;
|
|
1615
|
+
exports.enable = enable;
|
|
1616
|
+
exports.exportHistory = exportHistory;
|
|
1617
|
+
exports.exportSnapshots = exportSnapshots;
|
|
1618
|
+
exports.extractComponentState = extractComponentState;
|
|
1619
|
+
exports.formatValue = formatValue;
|
|
1620
|
+
exports.generateComponentId = generateComponentId;
|
|
1621
|
+
exports.generateSignalId = generateSignalId;
|
|
1622
|
+
exports.getActiveTab = getActiveTab;
|
|
1623
|
+
exports.getAllComponentPerformance = getAllComponentPerformance;
|
|
1624
|
+
exports.getAllComponents = getAllComponents;
|
|
1625
|
+
exports.getAllSnapshots = getAllSnapshots;
|
|
1626
|
+
exports.getComponentById = getComponentById2;
|
|
1627
|
+
exports.getComponentCount = getComponentCount;
|
|
1628
|
+
exports.getComponentPerformance = getComponentPerformance;
|
|
1629
|
+
exports.getComponentTree = getComponentTree;
|
|
1630
|
+
exports.getCurrentIndex = getCurrentIndex;
|
|
1631
|
+
exports.getEditHistory = getEditHistory;
|
|
1632
|
+
exports.getEventCount = getEventCount;
|
|
1633
|
+
exports.getEventStats = getEventStats;
|
|
1634
|
+
exports.getEvents = getEvents;
|
|
1635
|
+
exports.getEventsByComponent = getEventsByComponent;
|
|
1636
|
+
exports.getEventsByType = getEventsByType;
|
|
1637
|
+
exports.getHistory = getHistory;
|
|
1638
|
+
exports.getMemoryTrend = getMemoryTrend;
|
|
1639
|
+
exports.getNestedValue = getNestedValue;
|
|
1640
|
+
exports.getPanelState = getPanelState;
|
|
1641
|
+
exports.getPerformanceConfig = getPerformanceConfig;
|
|
1642
|
+
exports.getPerformanceTimeline = getPerformanceTimeline;
|
|
1643
|
+
exports.getRenderHeatmap = getRenderHeatmap;
|
|
1644
|
+
exports.getRootComponents = getRootComponents;
|
|
1645
|
+
exports.getSignalById = getSignalById;
|
|
1646
|
+
exports.getSignalValue = getSignalValue;
|
|
1647
|
+
exports.getSignals = getSignals;
|
|
1648
|
+
exports.getSignalsByComponent = getSignalsByComponent;
|
|
1649
|
+
exports.getSnapshot = getSnapshot;
|
|
1650
|
+
exports.getSnapshotById = getSnapshotById;
|
|
1651
|
+
exports.getSnapshots = getSnapshots;
|
|
1652
|
+
exports.getState = getState;
|
|
1653
|
+
exports.getStateDiffForEntry = getStateDiffForEntry;
|
|
1654
|
+
exports.goBack = goBack;
|
|
1655
|
+
exports.goForward = goForward;
|
|
1656
|
+
exports.goToEnd = goToEnd;
|
|
1657
|
+
exports.goToStart = goToStart;
|
|
1658
|
+
exports.importHistory = importHistory;
|
|
1659
|
+
exports.importSnapshots = importSnapshots;
|
|
1660
|
+
exports.initDevToolsPanel = initDevToolsPanel;
|
|
1661
|
+
exports.initPerformancePanel = initPerformancePanel;
|
|
1662
|
+
exports.initStateEditor = initStateEditor;
|
|
1663
|
+
exports.initTimeTravel = initTimeTravel;
|
|
1664
|
+
exports.isBridgeActive = isBridgeActive;
|
|
1665
|
+
exports.isEventRecording = isEventRecording;
|
|
1666
|
+
exports.isPanelInitialized = isPanelInitialized;
|
|
1667
|
+
exports.isPerformanceMonitoring = isPerformanceMonitoring;
|
|
1668
|
+
exports.jumpToHistory = jumpToHistory;
|
|
1669
|
+
exports.onPanelMessage = onPanelMessage;
|
|
1670
|
+
exports.parseValue = parseValue;
|
|
1671
|
+
exports.recordComponentRender = recordComponentRender;
|
|
1672
|
+
exports.recordEvent = recordEvent;
|
|
1673
|
+
exports.registerComponent = registerComponent;
|
|
1674
|
+
exports.registerSignal = registerSignal;
|
|
1675
|
+
exports.registerStoreSignals = registerStoreSignals;
|
|
1676
|
+
exports.restoreSnapshot = restoreSnapshot;
|
|
1677
|
+
exports.sendToPanel = sendToPanel;
|
|
1678
|
+
exports.setActiveTab = setActiveTab;
|
|
1679
|
+
exports.setConnected = setConnected;
|
|
1680
|
+
exports.setMaxEvents = setMaxEvents;
|
|
1681
|
+
exports.setNestedValue = setNestedValue;
|
|
1682
|
+
exports.setSignalValue = setSignalValue;
|
|
1683
|
+
exports.startEventRecording = startRecording2;
|
|
1684
|
+
exports.startHistoryRecording = startHistoryRecording;
|
|
1685
|
+
exports.startPerformanceMonitoring = startPerformanceMonitoring;
|
|
1686
|
+
exports.startStateRecording = startRecording;
|
|
1687
|
+
exports.stopEventRecording = stopRecording2;
|
|
1688
|
+
exports.stopHistoryRecording = stopHistoryRecording;
|
|
1689
|
+
exports.stopPerformanceMonitoring = stopPerformanceMonitoring;
|
|
1690
|
+
exports.stopStateRecording = stopRecording;
|
|
1691
|
+
exports.subscribeEvents = subscribeEvents;
|
|
1692
|
+
exports.subscribeState = subscribeState;
|
|
1693
|
+
exports.suggestGarbageCollection = suggestGarbageCollection;
|
|
1694
|
+
exports.takeSnapshot = takeSnapshot;
|
|
1695
|
+
exports.trackRouterNavigation = trackRouterNavigation;
|
|
1696
|
+
exports.trackStoreMutation = trackStoreMutation;
|
|
1697
|
+
exports.undoLastEdit = undoLastEdit;
|
|
1698
|
+
exports.unregisterComponent = unregisterComponent;
|
|
1699
|
+
exports.unregisterSignal = unregisterSignal;
|
|
1700
|
+
exports.unregisterStoreSignals = unregisterStoreSignals;
|
|
1701
|
+
exports.updatePerformanceConfig = updatePerformanceConfig;
|
|
1702
|
+
//# sourceMappingURL=index.cjs.map
|
|
1703
|
+
//# sourceMappingURL=index.cjs.map
|