what-devtools 0.12.4 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -5
- package/src/DevPanel.d.ts +9 -0
- package/src/DevPanel.jsx +5 -6
- package/src/index.d.ts +114 -0
- package/src/index.js +4 -2
package/package.json
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "what-devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Dev tools for What Framework — signal inspector, component tree, effect graph",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"exports": {
|
|
8
|
-
".":
|
|
9
|
-
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./src/index.d.ts",
|
|
10
|
+
"default": "./src/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./panel": {
|
|
13
|
+
"types": "./src/DevPanel.d.ts",
|
|
14
|
+
"default": "./src/DevPanel.jsx"
|
|
15
|
+
}
|
|
10
16
|
},
|
|
11
17
|
"files": [
|
|
12
18
|
"src"
|
|
@@ -20,7 +26,7 @@
|
|
|
20
26
|
"inspector"
|
|
21
27
|
],
|
|
22
28
|
"peerDependencies": {
|
|
23
|
-
"what-core": "^0.
|
|
29
|
+
"what-core": "^0.13.1"
|
|
24
30
|
},
|
|
25
31
|
"author": "ZVN DEV (https://zvndev.com)",
|
|
26
32
|
"license": "MIT",
|
|
@@ -31,5 +37,6 @@
|
|
|
31
37
|
"bugs": {
|
|
32
38
|
"url": "https://github.com/CelsianJs/what-framework/issues"
|
|
33
39
|
},
|
|
34
|
-
"homepage": "https://whatfw.com"
|
|
40
|
+
"homepage": "https://whatfw.com",
|
|
41
|
+
"types": "./src/index.d.ts"
|
|
35
42
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Types for `what-devtools/panel`.
|
|
2
|
+
import type { VNode } from 'what-core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The in-page devtools panel. Mount it anywhere in a dev build; it reads from
|
|
6
|
+
* the same stores `installDevTools()` populates.
|
|
7
|
+
*/
|
|
8
|
+
export function DevPanel(): VNode<any> | null;
|
|
9
|
+
export default DevPanel;
|
package/src/DevPanel.jsx
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* Works WITHOUT MCP devtools connected.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { signal,
|
|
22
|
+
import { signal, onCleanup } from 'what-core';
|
|
23
23
|
import { subscribe, getSnapshot, getErrors, installDevTools, _suppressDevtools } from './index.js';
|
|
24
24
|
|
|
25
25
|
export function DevPanel() {
|
|
@@ -111,11 +111,10 @@ function DevPanelBody() {
|
|
|
111
111
|
|
|
112
112
|
// --- Tab: Overview ---
|
|
113
113
|
const renderOverview = () => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
// Everything below reads snapshot()/getHealth()/recentErrors() inside a
|
|
115
|
+
// thunk so it stays reactive. Four eager copies used to be taken here and
|
|
116
|
+
// then shadowed; had anything rendered them directly it would have frozen
|
|
117
|
+
// at first paint.
|
|
119
118
|
return (
|
|
120
119
|
<div style="padding:12px;">
|
|
121
120
|
{/* Health indicator */}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Hand-written to match src/index.js. `what-devtools` is imported
|
|
2
|
+
// programmatically (`installDevTools`, `getSnapshot`) and by the MCP bridge,
|
|
3
|
+
// so TypeScript consumers need these; the package shipped without any types
|
|
4
|
+
// until 0.13.1.
|
|
5
|
+
|
|
6
|
+
/** A tracked signal, as returned by {@link getSnapshot}. */
|
|
7
|
+
export interface DevToolsSignal {
|
|
8
|
+
id: number;
|
|
9
|
+
name: string;
|
|
10
|
+
/** Read with `peek()`, so taking a snapshot never creates a subscription. */
|
|
11
|
+
value: unknown;
|
|
12
|
+
componentId: number | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** A tracked effect, as returned by {@link getSnapshot}. */
|
|
16
|
+
export interface DevToolsEffect {
|
|
17
|
+
id: number;
|
|
18
|
+
name: string;
|
|
19
|
+
depSignalIds: number[];
|
|
20
|
+
runCount: number;
|
|
21
|
+
/** `Date.now()` of the last run, or null if it has not run yet. */
|
|
22
|
+
lastRunAt: number | null;
|
|
23
|
+
componentId: number | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** A mounted component, as returned by {@link getSnapshot}. */
|
|
27
|
+
export interface DevToolsComponent {
|
|
28
|
+
id: number;
|
|
29
|
+
name: string;
|
|
30
|
+
parentId: number | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** A captured error. The buffer holds the most recent 100. */
|
|
34
|
+
export interface DevToolsError {
|
|
35
|
+
message: string;
|
|
36
|
+
stack: string | null;
|
|
37
|
+
/** Where it came from, e.g. 'effect' or 'unknown'. */
|
|
38
|
+
type: string;
|
|
39
|
+
effectId: number | null;
|
|
40
|
+
timestamp: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface DevToolsSnapshot {
|
|
44
|
+
signals: DevToolsSignal[];
|
|
45
|
+
effects: DevToolsEffect[];
|
|
46
|
+
components: DevToolsComponent[];
|
|
47
|
+
errors: DevToolsError[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type DevToolsEvent =
|
|
51
|
+
| 'signal:created'
|
|
52
|
+
| 'signal:updated'
|
|
53
|
+
| 'signal:disposed'
|
|
54
|
+
| 'effect:created'
|
|
55
|
+
| 'effect:run'
|
|
56
|
+
| 'effect:disposed'
|
|
57
|
+
| 'component:mounted'
|
|
58
|
+
| 'component:unmounted'
|
|
59
|
+
| 'error:captured';
|
|
60
|
+
|
|
61
|
+
/** Minimal shape of a what-core signal accessor, as devtools sees it. */
|
|
62
|
+
export interface TrackedSignal<T = unknown> {
|
|
63
|
+
(): T;
|
|
64
|
+
peek(): T;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Run `fn` with devtools registration suppressed, so framework-internal
|
|
69
|
+
* signals and effects created inside it are not reported to the panel.
|
|
70
|
+
*/
|
|
71
|
+
export function _suppressDevtools<T>(fn: () => T): T;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Convert a value to something structured-cloneable and depth-limited, for
|
|
75
|
+
* sending over the MCP bridge.
|
|
76
|
+
*/
|
|
77
|
+
export function safeSerialize(value: unknown, depth?: number, seen?: WeakSet<object>): unknown;
|
|
78
|
+
|
|
79
|
+
export function registerSignal(sig: TrackedSignal, name?: string): number;
|
|
80
|
+
export function notifySignalUpdate(sig: TrackedSignal): void;
|
|
81
|
+
export function unregisterSignal(sig: TrackedSignal): void;
|
|
82
|
+
|
|
83
|
+
export function registerEffect(e: object, name?: string): number;
|
|
84
|
+
export function unregisterEffect(e: object): void;
|
|
85
|
+
|
|
86
|
+
export function registerComponent(
|
|
87
|
+
name: string,
|
|
88
|
+
element: Node | null,
|
|
89
|
+
parentDevId?: number | null,
|
|
90
|
+
): number;
|
|
91
|
+
export function unregisterComponent(id: number): void;
|
|
92
|
+
|
|
93
|
+
/** Subscribe to devtools events. Returns an unsubscribe function. */
|
|
94
|
+
export function subscribe(
|
|
95
|
+
fn: (event: DevToolsEvent, payload: unknown) => void,
|
|
96
|
+
): () => void;
|
|
97
|
+
|
|
98
|
+
export function getSnapshot(opts?: { includeInternal?: boolean }): DevToolsSnapshot;
|
|
99
|
+
|
|
100
|
+
/** Captured errors, optionally only those after a `Date.now()` timestamp. */
|
|
101
|
+
export function getErrors(opts?: { since?: number }): DevToolsError[];
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Install devtools. Call once at app startup. Wires into what-core's `__DEV__`
|
|
105
|
+
* hooks and exposes `window.__WHAT_DEVTOOLS__`. Idempotent.
|
|
106
|
+
*
|
|
107
|
+
* @param core Optional what-core module. Dynamically imported when omitted.
|
|
108
|
+
*/
|
|
109
|
+
export function installDevTools(core?: object): void;
|
|
110
|
+
|
|
111
|
+
export const signals: Map<number, { name: string; ref: TrackedSignal; createdAt: number; internal?: boolean }>;
|
|
112
|
+
export const effects: Map<number, { name: string; createdAt: number; depSignalIds: number[]; runCount: number; lastRunAt: number | null }>;
|
|
113
|
+
export const components: Map<number, { name: string; element: Node | null; mountedAt: number; parentId: number | null }>;
|
|
114
|
+
export const errors: DevToolsError[];
|
package/src/index.js
CHANGED
|
@@ -141,9 +141,11 @@ export function safeSerialize(value, depth = 0, seen) {
|
|
|
141
141
|
|
|
142
142
|
// DOM nodes
|
|
143
143
|
if (typeof Node !== 'undefined' && value instanceof Node) {
|
|
144
|
+
// id/className live on Element, not Node; a text or comment node has neither.
|
|
145
|
+
const el = /** @type {Element} */ (/** @type {unknown} */ (value));
|
|
144
146
|
const tag = value.nodeName?.toLowerCase() || 'node';
|
|
145
|
-
const id =
|
|
146
|
-
const cls =
|
|
147
|
+
const id = el.id ? `#${el.id}` : '';
|
|
148
|
+
const cls = el.className ? `.${String(el.className).split(' ')[0]}` : '';
|
|
147
149
|
return `[DOM: <${tag}${id}${cls}>]`;
|
|
148
150
|
}
|
|
149
151
|
|