@streetui/devtools 1.0.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/LICENSE +21 -0
- package/README.md +26 -0
- package/dist/index.cjs +422 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +396 -0
- package/dist/index.d.ts +396 -0
- package/dist/index.js +385 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 StreetUI contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @streetui/devtools
|
|
2
|
+
|
|
3
|
+
StreetUI devtools — graph inspection, serialization, debug helpers
|
|
4
|
+
|
|
5
|
+
Part of [StreetUI](https://github.com/streetui/streetui) — a semantic,
|
|
6
|
+
signal-based UI framework with its own reactivity and keyed DOM reconciler
|
|
7
|
+
(no virtual DOM).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @streetui/devtools
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import * as pkg from '@streetui/devtools';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Both ESM (`import`) and CommonJS (`require`) entry points are shipped, with
|
|
22
|
+
matching TypeScript declarations.
|
|
23
|
+
|
|
24
|
+
## License
|
|
25
|
+
|
|
26
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
DEFAULT_PERF_THRESHOLDS: () => DEFAULT_PERF_THRESHOLDS,
|
|
24
|
+
createDevTools: () => createDevTools,
|
|
25
|
+
diagnosePerformance: () => diagnosePerformance,
|
|
26
|
+
inspectApplication: () => inspectApplication,
|
|
27
|
+
inspectContext: () => inspectContext,
|
|
28
|
+
inspectForm: () => inspectForm,
|
|
29
|
+
inspectGraph: () => inspectGraph,
|
|
30
|
+
inspectI18n: () => inspectI18n,
|
|
31
|
+
inspectResource: () => inspectResource,
|
|
32
|
+
inspectRouter: () => inspectRouter,
|
|
33
|
+
inspectSignal: () => inspectSignal,
|
|
34
|
+
nodeTypeStats: () => nodeTypeStats,
|
|
35
|
+
printDiagnostics: () => printDiagnostics,
|
|
36
|
+
printGraph: () => printGraph
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
|
|
40
|
+
// src/inspector.ts
|
|
41
|
+
var import_core = require("@streetui/core");
|
|
42
|
+
function inspectGraph(graph) {
|
|
43
|
+
return inspectNode(graph.root, 0);
|
|
44
|
+
}
|
|
45
|
+
function inspectNode(node, depth) {
|
|
46
|
+
return {
|
|
47
|
+
id: node.id,
|
|
48
|
+
type: node.type,
|
|
49
|
+
key: node.key,
|
|
50
|
+
props: { ...node.props },
|
|
51
|
+
eventTypes: node.events.map((e) => e.type),
|
|
52
|
+
stateBindings: node.stateRefs.map((r) => `${r.propKey}\u2192${r.signalId}`),
|
|
53
|
+
depth,
|
|
54
|
+
children: node.children.map((c) => inspectNode(c, depth + 1))
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function printGraph(graph) {
|
|
58
|
+
const lines = [];
|
|
59
|
+
graph.walk((node, depth) => {
|
|
60
|
+
const indent = " ".repeat(depth);
|
|
61
|
+
const props = Object.entries(node.props).filter(([k]) => !k.startsWith("_")).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(", ");
|
|
62
|
+
const events = node.events.length > 0 ? ` [events: ${node.events.map((e) => e.type).join(", ")}]` : "";
|
|
63
|
+
const stateRefs = node.stateRefs.length > 0 ? ` [signals: ${node.stateRefs.map((r) => r.propKey).join(", ")}]` : "";
|
|
64
|
+
lines.push(`${indent}<${node.type}${props ? ` ${props}` : ""}${events}${stateRefs}>`);
|
|
65
|
+
});
|
|
66
|
+
return lines.join("\n");
|
|
67
|
+
}
|
|
68
|
+
function printDiagnostics(compiled) {
|
|
69
|
+
if (compiled.diagnostics.diagnostics.length === 0) {
|
|
70
|
+
return "(no diagnostics)";
|
|
71
|
+
}
|
|
72
|
+
return compiled.diagnostics.diagnostics.map(import_core.formatDiagnostic).join("\n");
|
|
73
|
+
}
|
|
74
|
+
function nodeTypeStats(graph) {
|
|
75
|
+
const counts = {};
|
|
76
|
+
graph.walk((node) => {
|
|
77
|
+
counts[node.type] = (counts[node.type] ?? 0) + 1;
|
|
78
|
+
});
|
|
79
|
+
return counts;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/application.ts
|
|
83
|
+
var import_core2 = require("@streetui/core");
|
|
84
|
+
function collectPerf(node, distinctSignals, acc) {
|
|
85
|
+
acc.totalNodes += 1;
|
|
86
|
+
if (node.depth > acc.maxDepth) acc.maxDepth = node.depth;
|
|
87
|
+
acc.eventHandlers += node.eventTypes.length;
|
|
88
|
+
acc.stateBindings += node.stateBindings.length;
|
|
89
|
+
if (node.children.length > acc.largestChildCount) acc.largestChildCount = node.children.length;
|
|
90
|
+
for (const child of node.children) collectPerf(child, distinctSignals, acc);
|
|
91
|
+
}
|
|
92
|
+
function collectSignals(node, into) {
|
|
93
|
+
for (const binding of node.stateBindings) {
|
|
94
|
+
const arrow = binding.indexOf("\u2192");
|
|
95
|
+
const signalId = arrow >= 0 ? binding.slice(arrow + 1) : binding;
|
|
96
|
+
if (signalId.length > 0) into.add(signalId);
|
|
97
|
+
}
|
|
98
|
+
for (const child of node.children) collectSignals(child, into);
|
|
99
|
+
}
|
|
100
|
+
function inspectApplication(compiled) {
|
|
101
|
+
const graph = inspectGraph(compiled.graph);
|
|
102
|
+
const signals = /* @__PURE__ */ new Set();
|
|
103
|
+
collectSignals(graph, signals);
|
|
104
|
+
const pages = graph.children.filter((child) => child.type === "page").map((child) => ({ id: child.id, key: child.key }));
|
|
105
|
+
const diags = compiled.diagnostics.diagnostics;
|
|
106
|
+
const errors = diags.filter((d) => d.severity === "error").length;
|
|
107
|
+
const perfAcc = { totalNodes: 0, maxDepth: 0, eventHandlers: 0, stateBindings: 0, largestChildCount: 0 };
|
|
108
|
+
collectPerf(graph, signals.size, perfAcc);
|
|
109
|
+
return {
|
|
110
|
+
identity: {
|
|
111
|
+
name: compiled.name,
|
|
112
|
+
version: compiled.version,
|
|
113
|
+
compiledAt: compiled.compiledAt
|
|
114
|
+
},
|
|
115
|
+
graph,
|
|
116
|
+
nodeStats: nodeTypeStats(compiled.graph),
|
|
117
|
+
signals: [...signals].sort(),
|
|
118
|
+
pages,
|
|
119
|
+
diagnostics: {
|
|
120
|
+
errors,
|
|
121
|
+
warnings: diags.length - errors,
|
|
122
|
+
messages: diags.map(import_core2.formatDiagnostic)
|
|
123
|
+
},
|
|
124
|
+
perf: {
|
|
125
|
+
totalNodes: perfAcc.totalNodes,
|
|
126
|
+
maxDepth: perfAcc.maxDepth,
|
|
127
|
+
eventHandlers: perfAcc.eventHandlers,
|
|
128
|
+
stateBindings: perfAcc.stateBindings,
|
|
129
|
+
distinctSignals: signals.size,
|
|
130
|
+
largestChildCount: perfAcc.largestChildCount
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/diagnostics.ts
|
|
136
|
+
var DEFAULT_PERF_THRESHOLDS = {
|
|
137
|
+
maxNodes: 5e3,
|
|
138
|
+
maxDepth: 32,
|
|
139
|
+
maxChildCount: 1e3,
|
|
140
|
+
maxSignals: 1e3
|
|
141
|
+
};
|
|
142
|
+
function diagnosePerformance(compiled, thresholds = {}) {
|
|
143
|
+
const t = { ...DEFAULT_PERF_THRESHOLDS, ...thresholds };
|
|
144
|
+
const { perf } = inspectApplication(compiled);
|
|
145
|
+
const out = [];
|
|
146
|
+
if (perf.totalNodes > t.maxNodes) {
|
|
147
|
+
out.push({
|
|
148
|
+
code: "large-graph",
|
|
149
|
+
message: `Graph has ${perf.totalNodes} nodes (> ${t.maxNodes}); consider splitting the view or paginating.`,
|
|
150
|
+
observed: perf.totalNodes,
|
|
151
|
+
threshold: t.maxNodes
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (perf.maxDepth > t.maxDepth) {
|
|
155
|
+
out.push({
|
|
156
|
+
code: "deep-tree",
|
|
157
|
+
message: `Graph nests ${perf.maxDepth} levels deep (> ${t.maxDepth}); deep trees slow mount and reconciliation.`,
|
|
158
|
+
observed: perf.maxDepth,
|
|
159
|
+
threshold: t.maxDepth
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (perf.largestChildCount > t.maxChildCount) {
|
|
163
|
+
out.push({
|
|
164
|
+
code: "large-list",
|
|
165
|
+
message: `A single node has ${perf.largestChildCount} children (> ${t.maxChildCount}); large un-windowed lists dominate DOM cost.`,
|
|
166
|
+
observed: perf.largestChildCount,
|
|
167
|
+
threshold: t.maxChildCount
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
if (perf.distinctSignals > t.maxSignals) {
|
|
171
|
+
out.push({
|
|
172
|
+
code: "high-signal-fanout",
|
|
173
|
+
message: `${perf.distinctSignals} distinct signals are bound (> ${t.maxSignals}); heavy reactive fan-out increases update overhead.`,
|
|
174
|
+
observed: perf.distinctSignals,
|
|
175
|
+
threshold: t.maxSignals
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/inspect-reactive.ts
|
|
182
|
+
var import_state = require("@streetui/state");
|
|
183
|
+
function inspectSignal(source, options = {}) {
|
|
184
|
+
const raw = source.peek();
|
|
185
|
+
let value = raw;
|
|
186
|
+
if (options.redact === true) value = "[redacted]";
|
|
187
|
+
else if (typeof options.redact === "function") value = options.redact(raw);
|
|
188
|
+
return {
|
|
189
|
+
kind: (0, import_state.signalKind)(source),
|
|
190
|
+
value,
|
|
191
|
+
observerCount: (0, import_state.observerCount)(source)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function inspectResource(resource, options = {}) {
|
|
195
|
+
const error = resource.error.peek();
|
|
196
|
+
const hasError = error !== void 0 && error !== null;
|
|
197
|
+
const base = {
|
|
198
|
+
status: resource.status.peek(),
|
|
199
|
+
loading: resource.loading.peek(),
|
|
200
|
+
isRefetching: resource.isRefetching.peek(),
|
|
201
|
+
hasData: resource.data.peek() !== void 0,
|
|
202
|
+
hasError,
|
|
203
|
+
errorName: hasError ? errorConstructorName(error) : void 0
|
|
204
|
+
};
|
|
205
|
+
if (options.includeData !== true) return base;
|
|
206
|
+
return {
|
|
207
|
+
...base,
|
|
208
|
+
data: resource.data.peek(),
|
|
209
|
+
...hasError ? { errorMessage: errorMessageOf(error) } : {}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function errorConstructorName(error) {
|
|
213
|
+
if (error instanceof Error) return error.name;
|
|
214
|
+
return typeof error;
|
|
215
|
+
}
|
|
216
|
+
function errorMessageOf(error) {
|
|
217
|
+
if (error instanceof Error) return error.message;
|
|
218
|
+
return String(error);
|
|
219
|
+
}
|
|
220
|
+
function inspectRouter(router) {
|
|
221
|
+
const match = router.currentRoute.peek();
|
|
222
|
+
const query = {};
|
|
223
|
+
for (const [k, v] of match.query.entries()) query[k] = v;
|
|
224
|
+
return {
|
|
225
|
+
path: match.path,
|
|
226
|
+
pattern: match.pattern,
|
|
227
|
+
params: { ...match.params },
|
|
228
|
+
query,
|
|
229
|
+
isFallback: match.isFallback === true
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function inspectForm(form, options = {}) {
|
|
233
|
+
const values = form.values.peek();
|
|
234
|
+
const errorsRaw = form.errors.peek();
|
|
235
|
+
const touchedRaw = form.touched.peek();
|
|
236
|
+
const errors = {};
|
|
237
|
+
for (const [k, v] of Object.entries(errorsRaw)) if (v !== void 0) errors[k] = v;
|
|
238
|
+
const touched = {};
|
|
239
|
+
for (const [k, v] of Object.entries(touchedRaw)) touched[k] = v === true;
|
|
240
|
+
const base = {
|
|
241
|
+
fields: Object.keys(values),
|
|
242
|
+
errors,
|
|
243
|
+
touched,
|
|
244
|
+
dirty: form.dirty.peek(),
|
|
245
|
+
valid: form.valid.peek(),
|
|
246
|
+
status: form.status.peek()
|
|
247
|
+
};
|
|
248
|
+
if (options.includeValues !== true) return base;
|
|
249
|
+
return { ...base, values: { ...values } };
|
|
250
|
+
}
|
|
251
|
+
function inspectContext(context) {
|
|
252
|
+
return {
|
|
253
|
+
description: context.id.description ?? "streetui.context",
|
|
254
|
+
hasProvider: context.hasProvider()
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function inspectI18n(i18n, options = {}) {
|
|
258
|
+
const base = {
|
|
259
|
+
locale: i18n.locale.peek(),
|
|
260
|
+
locales: [...i18n.locales]
|
|
261
|
+
};
|
|
262
|
+
if (options.checkKeys === void 0) return base;
|
|
263
|
+
const missingKeys = options.checkKeys.filter((k) => !i18n.has(k));
|
|
264
|
+
return { ...base, missingKeys };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/panels.ts
|
|
268
|
+
function createDevTools(compiled, sources = {}, options = {}) {
|
|
269
|
+
let current = capture(compiled, sources, options);
|
|
270
|
+
return {
|
|
271
|
+
get snapshot() {
|
|
272
|
+
return current;
|
|
273
|
+
},
|
|
274
|
+
refresh() {
|
|
275
|
+
current = capture(compiled, sources, options);
|
|
276
|
+
return current;
|
|
277
|
+
},
|
|
278
|
+
selectNode(id) {
|
|
279
|
+
return findNode(current.graph, id);
|
|
280
|
+
},
|
|
281
|
+
format() {
|
|
282
|
+
return formatSnapshot(current);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function capture(compiled, sources, options) {
|
|
287
|
+
const app = inspectApplication(compiled);
|
|
288
|
+
const application = {
|
|
289
|
+
identity: app.identity,
|
|
290
|
+
nodeCount: app.perf.totalNodes,
|
|
291
|
+
maxDepth: app.perf.maxDepth,
|
|
292
|
+
pages: app.pages,
|
|
293
|
+
signalCount: app.signals.length,
|
|
294
|
+
eventHandlers: app.perf.eventHandlers,
|
|
295
|
+
stateBindings: app.perf.stateBindings,
|
|
296
|
+
errors: app.diagnostics.errors,
|
|
297
|
+
warnings: app.diagnostics.warnings
|
|
298
|
+
};
|
|
299
|
+
const live = {};
|
|
300
|
+
if (sources.signals !== void 0) {
|
|
301
|
+
for (const [label, sig] of Object.entries(sources.signals)) {
|
|
302
|
+
live[label] = inspectSignal(
|
|
303
|
+
sig,
|
|
304
|
+
options.redactSignals !== void 0 ? { redact: options.redactSignals } : {}
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const signals = { boundSignalIds: app.signals, live };
|
|
309
|
+
const performance = {
|
|
310
|
+
snapshot: app.perf,
|
|
311
|
+
diagnostics: diagnosePerformance(compiled, options.perfThresholds)
|
|
312
|
+
};
|
|
313
|
+
const snapshot = {
|
|
314
|
+
application,
|
|
315
|
+
graph: app.graph,
|
|
316
|
+
signals,
|
|
317
|
+
performance,
|
|
318
|
+
...sources.router !== void 0 ? { router: inspectRouter(sources.router) } : {},
|
|
319
|
+
...sources.resources !== void 0 ? { resources: mapInspect(sources.resources, (r) => inspectResource(r)) } : {},
|
|
320
|
+
...sources.forms !== void 0 ? { forms: mapInspect(sources.forms, (f) => inspectForm(f)) } : {},
|
|
321
|
+
...sources.contexts !== void 0 ? { contexts: mapInspect(sources.contexts, (c) => inspectContext(c)) } : {},
|
|
322
|
+
...sources.i18n !== void 0 ? {
|
|
323
|
+
i18n: inspectI18n(
|
|
324
|
+
sources.i18n,
|
|
325
|
+
options.i18nCheckKeys !== void 0 ? { checkKeys: options.i18nCheckKeys } : {}
|
|
326
|
+
)
|
|
327
|
+
} : {}
|
|
328
|
+
};
|
|
329
|
+
return snapshot;
|
|
330
|
+
}
|
|
331
|
+
function mapInspect(source, inspect) {
|
|
332
|
+
const out = {};
|
|
333
|
+
for (const [label, value] of Object.entries(source)) out[label] = inspect(value);
|
|
334
|
+
return out;
|
|
335
|
+
}
|
|
336
|
+
function findNode(node, id) {
|
|
337
|
+
if (node.id === id) return node;
|
|
338
|
+
for (const child of node.children) {
|
|
339
|
+
const found = findNode(child, id);
|
|
340
|
+
if (found !== void 0) return found;
|
|
341
|
+
}
|
|
342
|
+
return void 0;
|
|
343
|
+
}
|
|
344
|
+
function formatSnapshot(s) {
|
|
345
|
+
const lines = [];
|
|
346
|
+
const app = s.application;
|
|
347
|
+
lines.push(`StreetUI DevTools \u2014 ${app.identity.name} v${app.identity.version}`);
|
|
348
|
+
lines.push(
|
|
349
|
+
`Application: ${app.nodeCount} nodes, depth ${app.maxDepth}, ${app.pages.length} page(s)`
|
|
350
|
+
);
|
|
351
|
+
lines.push(
|
|
352
|
+
` signals ${app.signalCount} \xB7 handlers ${app.eventHandlers} \xB7 bindings ${app.stateBindings} \xB7 errors ${app.errors} \xB7 warnings ${app.warnings}`
|
|
353
|
+
);
|
|
354
|
+
lines.push(`Signals: ${s.signals.boundSignalIds.length} bound in graph`);
|
|
355
|
+
for (const [label, sig] of Object.entries(s.signals.live)) {
|
|
356
|
+
lines.push(` ${label} [${sig.kind}] = ${format(sig.value)} \xB7 observers ${sig.observerCount ?? "?"}`);
|
|
357
|
+
}
|
|
358
|
+
if (s.router !== void 0) {
|
|
359
|
+
lines.push(`Router: ${s.router.path} (${s.router.pattern})${s.router.isFallback ? " [fallback]" : ""}`);
|
|
360
|
+
}
|
|
361
|
+
if (s.resources !== void 0) {
|
|
362
|
+
lines.push("Resources:");
|
|
363
|
+
for (const [label, r] of Object.entries(s.resources)) {
|
|
364
|
+
lines.push(` ${label}: ${r.status}${r.loading ? " (loading)" : ""}${r.hasError ? ` !${r.errorName}` : ""}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (s.forms !== void 0) {
|
|
368
|
+
lines.push("Forms:");
|
|
369
|
+
for (const [label, f] of Object.entries(s.forms)) {
|
|
370
|
+
lines.push(` ${label}: ${f.valid ? "valid" : "invalid"} \xB7 ${f.status} \xB7 fields ${f.fields.length}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (s.contexts !== void 0) {
|
|
374
|
+
lines.push("Contexts:");
|
|
375
|
+
for (const [label, c] of Object.entries(s.contexts)) {
|
|
376
|
+
lines.push(` ${label} (${c.description}): ${c.hasProvider ? "provided" : "no provider"}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (s.i18n !== void 0) {
|
|
380
|
+
const missing = s.i18n.missingKeys;
|
|
381
|
+
lines.push(
|
|
382
|
+
`i18n: ${s.i18n.locale} of [${s.i18n.locales.join(", ")}]${missing !== void 0 ? ` \xB7 missing ${missing.length}` : ""}`
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
lines.push(
|
|
386
|
+
`Performance: ${s.performance.diagnostics.length} diagnostic(s), ${s.performance.snapshot.totalNodes} nodes`
|
|
387
|
+
);
|
|
388
|
+
for (const d of s.performance.diagnostics) {
|
|
389
|
+
lines.push(` ${d.code}: ${d.message}`);
|
|
390
|
+
}
|
|
391
|
+
return lines.join("\n");
|
|
392
|
+
}
|
|
393
|
+
function format(value) {
|
|
394
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
395
|
+
if (value === null || value === void 0) return String(value);
|
|
396
|
+
if (typeof value === "object") {
|
|
397
|
+
try {
|
|
398
|
+
return JSON.stringify(value);
|
|
399
|
+
} catch {
|
|
400
|
+
return "[object]";
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return String(value);
|
|
404
|
+
}
|
|
405
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
406
|
+
0 && (module.exports = {
|
|
407
|
+
DEFAULT_PERF_THRESHOLDS,
|
|
408
|
+
createDevTools,
|
|
409
|
+
diagnosePerformance,
|
|
410
|
+
inspectApplication,
|
|
411
|
+
inspectContext,
|
|
412
|
+
inspectForm,
|
|
413
|
+
inspectGraph,
|
|
414
|
+
inspectI18n,
|
|
415
|
+
inspectResource,
|
|
416
|
+
inspectRouter,
|
|
417
|
+
inspectSignal,
|
|
418
|
+
nodeTypeStats,
|
|
419
|
+
printDiagnostics,
|
|
420
|
+
printGraph
|
|
421
|
+
});
|
|
422
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/inspector.ts","../src/application.ts","../src/diagnostics.ts","../src/inspect-reactive.ts","../src/panels.ts"],"sourcesContent":["export * from './inspector.js';\nexport * from './application.js';\nexport * from './diagnostics.js';\nexport * from './inspect-reactive.js';\nexport * from './panels.js';\n","/**\n * StreetUI DevTools — graph inspector and debug utilities.\n */\n\nimport { formatDiagnostic } from '@streetui/core';\nimport type { ApplicationGraph, GraphNode } from '@streetui/graph';\nimport type { CompiledApplication } from '@streetui/compiler';\n\nexport interface InspectedNode {\n id: string;\n type: string;\n key: string | undefined;\n props: Record<string, unknown>;\n eventTypes: string[];\n stateBindings: string[];\n children: InspectedNode[];\n depth: number;\n}\n\nexport function inspectGraph(graph: ApplicationGraph): InspectedNode {\n return inspectNode(graph.root, 0);\n}\n\nfunction inspectNode(node: GraphNode, depth: number): InspectedNode {\n return {\n id: node.id,\n type: node.type,\n key: node.key,\n props: { ...node.props },\n eventTypes: node.events.map(e => e.type),\n stateBindings: node.stateRefs.map(r => `${r.propKey}→${r.signalId}`),\n depth,\n children: node.children.map(c => inspectNode(c, depth + 1)),\n };\n}\n\n/** Print a human-readable tree of the graph to a string. */\nexport function printGraph(graph: ApplicationGraph): string {\n const lines: string[] = [];\n graph.walk((node, depth) => {\n const indent = ' '.repeat(depth);\n const props = Object.entries(node.props)\n .filter(([k]) => !k.startsWith('_'))\n .map(([k, v]) => `${k}=${JSON.stringify(v)}`)\n .join(', ');\n const events = node.events.length > 0\n ? ` [events: ${node.events.map(e => e.type).join(', ')}]`\n : '';\n const stateRefs = node.stateRefs.length > 0\n ? ` [signals: ${node.stateRefs.map(r => r.propKey).join(', ')}]`\n : '';\n lines.push(`${indent}<${node.type}${props ? ` ${props}` : ''}${events}${stateRefs}>`);\n });\n return lines.join('\\n');\n}\n\n/** Print compilation diagnostics to a string. */\nexport function printDiagnostics(compiled: CompiledApplication): string {\n if (compiled.diagnostics.diagnostics.length === 0) {\n return '(no diagnostics)';\n }\n return compiled.diagnostics.diagnostics.map(formatDiagnostic).join('\\n');\n}\n\n/** Returns node counts per type. */\nexport function nodeTypeStats(graph: ApplicationGraph): Record<string, number> {\n const counts: Record<string, number> = {};\n graph.walk(node => {\n counts[node.type] = (counts[node.type] ?? 0) + 1;\n });\n return counts;\n}\n","/**\n * DevTools foundation (v0.6, Phase 18). A single read-only entry point that\n * aggregates everything an eventual DevTools UI would need — application\n * identity, the graph tree, signal bindings, page/route surface, node\n * statistics, and diagnostics — WITHOUT introducing a second representation of\n * the graph. It reuses `inspectGraph`/`nodeTypeStats` from the inspector and\n * reads `CompiledApplication` metadata directly. This is a foundation, not a\n * UI: it returns plain data so a UI (or a test, or a CLI command) can render it.\n */\n\nimport type { CompiledApplication } from '@streetui/compiler';\nimport { formatDiagnostic } from '@streetui/core';\nimport { inspectGraph, nodeTypeStats, type InspectedNode } from './inspector.js';\n\n/** Stable identity of a compiled application. */\nexport interface ApplicationIdentity {\n readonly name: string;\n readonly version: string;\n /** Epoch millis the application was compiled. */\n readonly compiledAt: number;\n}\n\n/** A page node reachable as a direct child of the application root. */\nexport interface InspectedPage {\n readonly id: string;\n /** The page key when one was supplied in the DSL. */\n readonly key: string | undefined;\n}\n\n/** Compilation diagnostics summarised for display. */\nexport interface DiagnosticsSummary {\n readonly errors: number;\n readonly warnings: number;\n readonly messages: string[];\n}\n\n/**\n * Cheap, count-only performance snapshot (v0.7 §20). These are structural\n * counts derived from a single graph walk — NOT timings and NOT a profiler.\n * They let a DevTools panel or a CI check spot the shapes that correlate with\n * slow apps (very large graphs, deep trees, big lists, many subscriptions)\n * without measuring anything at runtime.\n */\nexport interface PerfSnapshot {\n /** Total GraphNodes in the tree (root included). */\n readonly totalNodes: number;\n /** Maximum nesting depth (root = 0). */\n readonly maxDepth: number;\n /** Total event handler registrations across all nodes. */\n readonly eventHandlers: number;\n /** Total signal→prop bindings across all nodes. */\n readonly stateBindings: number;\n /** Distinct signals referenced anywhere in the graph. */\n readonly distinctSignals: number;\n /** Largest single-node child count (a proxy for the biggest list/section). */\n readonly largestChildCount: number;\n}\n\n/**\n * The complete read-only snapshot of a compiled application. Everything here is\n * derived from the single `CompiledApplication` graph — no state is duplicated.\n */\nexport interface ApplicationInspection {\n readonly identity: ApplicationIdentity;\n readonly graph: InspectedNode;\n /** Count of nodes per DSL type (e.g. `{ section: 2, button: 3 }`). */\n readonly nodeStats: Record<string, number>;\n /** Unique signal ids bound anywhere in the graph, sorted. */\n readonly signals: string[];\n /** Page nodes directly under the root — the app's top-level route surface. */\n readonly pages: InspectedPage[];\n readonly diagnostics: DiagnosticsSummary;\n /** Cheap structural performance counters (v0.7 §20). */\n readonly perf: PerfSnapshot;\n}\n\n/** Walk the inspected tree once, accumulating the count-only perf snapshot. */\nfunction collectPerf(\n node: InspectedNode,\n distinctSignals: number,\n acc: { totalNodes: number; maxDepth: number; eventHandlers: number; stateBindings: number; largestChildCount: number },\n): void {\n acc.totalNodes += 1;\n if (node.depth > acc.maxDepth) acc.maxDepth = node.depth;\n acc.eventHandlers += node.eventTypes.length;\n acc.stateBindings += node.stateBindings.length;\n if (node.children.length > acc.largestChildCount) acc.largestChildCount = node.children.length;\n for (const child of node.children) collectPerf(child, distinctSignals, acc);\n}\n\n/** Collect every distinct signal id referenced by any node in the tree. */\nfunction collectSignals(node: InspectedNode, into: Set<string>): void {\n for (const binding of node.stateBindings) {\n // Bindings are formatted `propKey→signalId` by the inspector.\n const arrow = binding.indexOf('→');\n const signalId = arrow >= 0 ? binding.slice(arrow + 1) : binding;\n if (signalId.length > 0) into.add(signalId);\n }\n for (const child of node.children) collectSignals(child, into);\n}\n\n/**\n * Build the full inspection snapshot for a compiled application. Pure and\n * side-effect free — safe to call in a server, a test, or a DevTools panel.\n */\nexport function inspectApplication(compiled: CompiledApplication): ApplicationInspection {\n const graph = inspectGraph(compiled.graph);\n\n const signals = new Set<string>();\n collectSignals(graph, signals);\n\n const pages: InspectedPage[] = graph.children\n .filter((child) => child.type === 'page')\n .map((child) => ({ id: child.id, key: child.key }));\n\n const diags = compiled.diagnostics.diagnostics;\n const errors = diags.filter((d) => d.severity === 'error').length;\n\n const perfAcc = { totalNodes: 0, maxDepth: 0, eventHandlers: 0, stateBindings: 0, largestChildCount: 0 };\n collectPerf(graph, signals.size, perfAcc);\n\n return {\n identity: {\n name: compiled.name,\n version: compiled.version,\n compiledAt: compiled.compiledAt,\n },\n graph,\n nodeStats: nodeTypeStats(compiled.graph),\n signals: [...signals].sort(),\n pages,\n diagnostics: {\n errors,\n warnings: diags.length - errors,\n messages: diags.map(formatDiagnostic),\n },\n perf: {\n totalNodes: perfAcc.totalNodes,\n maxDepth: perfAcc.maxDepth,\n eventHandlers: perfAcc.eventHandlers,\n stateBindings: perfAcc.stateBindings,\n distinctSignals: signals.size,\n largestChildCount: perfAcc.largestChildCount,\n },\n };\n}\n","/**\n * Dev-only performance diagnostics (v0.7 §21).\n *\n * A pure, cheap, count-based check that flags graph *shapes* known to correlate\n * with slow apps — very large graphs, deep trees, oversized lists/sections, and\n * heavy reactive fan-out. It is NOT wired into mount/render and adds ZERO cost\n * to the runtime hot path; a developer (or a CLI command, or a test) calls it\n * explicitly. Thresholds are advisory and overridable.\n *\n * This intentionally reuses the counts already produced by `inspectApplication`\n * — it introduces no second graph walk of its own beyond reading that snapshot.\n */\n\nimport type { CompiledApplication } from '@streetui/compiler';\nimport { inspectApplication } from './application.js';\n\nexport interface PerfThresholds {\n /** Warn when the graph exceeds this many nodes. */\n readonly maxNodes: number;\n /** Warn when nesting depth exceeds this. */\n readonly maxDepth: number;\n /** Warn when any single node has more than this many children (big list). */\n readonly maxChildCount: number;\n /** Warn when distinct signals exceed this (reactive fan-out). */\n readonly maxSignals: number;\n}\n\nexport const DEFAULT_PERF_THRESHOLDS: PerfThresholds = {\n maxNodes: 5000,\n maxDepth: 32,\n maxChildCount: 1000,\n maxSignals: 1000,\n};\n\nexport type PerfDiagnosticCode =\n | 'large-graph'\n | 'deep-tree'\n | 'large-list'\n | 'high-signal-fanout';\n\nexport interface PerfDiagnostic {\n readonly code: PerfDiagnosticCode;\n readonly message: string;\n /** The observed count that tripped the threshold. */\n readonly observed: number;\n /** The threshold it exceeded. */\n readonly threshold: number;\n}\n\n/**\n * Return advisory performance diagnostics for a compiled application. An empty\n * array means nothing tripped a threshold. Never throws; never mutates.\n */\nexport function diagnosePerformance(\n compiled: CompiledApplication,\n thresholds: Partial<PerfThresholds> = {},\n): PerfDiagnostic[] {\n const t = { ...DEFAULT_PERF_THRESHOLDS, ...thresholds };\n const { perf } = inspectApplication(compiled);\n const out: PerfDiagnostic[] = [];\n\n if (perf.totalNodes > t.maxNodes) {\n out.push({\n code: 'large-graph',\n message: `Graph has ${perf.totalNodes} nodes (> ${t.maxNodes}); consider splitting the view or paginating.`,\n observed: perf.totalNodes,\n threshold: t.maxNodes,\n });\n }\n if (perf.maxDepth > t.maxDepth) {\n out.push({\n code: 'deep-tree',\n message: `Graph nests ${perf.maxDepth} levels deep (> ${t.maxDepth}); deep trees slow mount and reconciliation.`,\n observed: perf.maxDepth,\n threshold: t.maxDepth,\n });\n }\n if (perf.largestChildCount > t.maxChildCount) {\n out.push({\n code: 'large-list',\n message: `A single node has ${perf.largestChildCount} children (> ${t.maxChildCount}); large un-windowed lists dominate DOM cost.`,\n observed: perf.largestChildCount,\n threshold: t.maxChildCount,\n });\n }\n if (perf.distinctSignals > t.maxSignals) {\n out.push({\n code: 'high-signal-fanout',\n message: `${perf.distinctSignals} distinct signals are bound (> ${t.maxSignals}); heavy reactive fan-out increases update overhead.`,\n observed: perf.distinctSignals,\n threshold: t.maxSignals,\n });\n }\n\n return out;\n}\n","/**\n * Reactive-surface inspection for DevTools.\n *\n * These functions turn the framework's live objects — signals, resources,\n * router, forms, context, i18n — into plain, read-only snapshots suitable for a\n * DevTools panel. They never mutate anything and never subscribe; each call is a\n * one-shot `peek`. Sensitive-by-default surfaces (resource payloads, form field\n * values) are omitted unless the caller explicitly opts in, so a panel cannot\n * accidentally display tokens, passwords, or private data.\n *\n * Router/forms/context/i18n are described by *structural* interfaces rather than\n * imported types, so DevTools stays decoupled from those packages (no extra\n * dependencies) while still inspecting them when present.\n */\n\nimport {\n type ReadonlySignal,\n type ResourceStatus,\n type SignalKind,\n signalKind,\n observerCount,\n} from '@streetui/state';\n\n// ── Signals ─────────────────────────────────────────────────────────────────\n\nexport interface SignalInspection {\n /** Whether the signal is writable or a derived computation. */\n readonly kind: SignalKind;\n /** The current value (redacted if requested). */\n readonly value: unknown;\n /** Live observer count when the signal exposes it, else undefined. */\n readonly observerCount: number | undefined;\n}\n\nexport interface InspectSignalOptions {\n /**\n * Redact the value: `true` replaces it with `'[redacted]'`; a function maps\n * the raw value to whatever should be shown. Use for signals that may hold\n * sensitive data. Omitted → the value is shown as-is.\n */\n readonly redact?: boolean | ((value: unknown) => unknown);\n}\n\n/** Snapshot a signal's kind, current value, and observer count. Read-only. */\nexport function inspectSignal(\n source: ReadonlySignal<unknown>,\n options: InspectSignalOptions = {},\n): SignalInspection {\n const raw = source.peek();\n let value: unknown = raw;\n if (options.redact === true) value = '[redacted]';\n else if (typeof options.redact === 'function') value = options.redact(raw);\n\n return {\n kind: signalKind(source),\n value,\n observerCount: observerCount(source),\n };\n}\n\n// ── Resources ─────────────────────────────────────────────────────────────\n\n/** The read-only slice of a resource this module needs. */\nexport interface ResourceLike {\n readonly status: ReadonlySignal<ResourceStatus>;\n readonly data: ReadonlySignal<unknown>;\n readonly error: ReadonlySignal<unknown>;\n readonly loading: ReadonlySignal<boolean>;\n readonly isRefetching: ReadonlySignal<boolean>;\n}\n\nexport interface ResourceInspection {\n readonly status: ResourceStatus;\n readonly loading: boolean;\n readonly isRefetching: boolean;\n readonly hasData: boolean;\n readonly hasError: boolean;\n /** The error's constructor name (safe — no message/payload). */\n readonly errorName: string | undefined;\n /** The error message — only present when `includeData` is set. */\n readonly errorMessage?: string;\n /** The loaded value — only present when `includeData` is set. */\n readonly data?: unknown;\n}\n\nexport interface InspectResourceOptions {\n /**\n * Include the loaded `data` and the error `message`. Off by default because a\n * resource payload commonly carries user or secret data.\n */\n readonly includeData?: boolean;\n}\n\n/** Snapshot a resource's lifecycle. Payload/message hidden unless opted in. */\nexport function inspectResource(\n resource: ResourceLike,\n options: InspectResourceOptions = {},\n): ResourceInspection {\n const error = resource.error.peek();\n const hasError = error !== undefined && error !== null;\n const base: ResourceInspection = {\n status: resource.status.peek(),\n loading: resource.loading.peek(),\n isRefetching: resource.isRefetching.peek(),\n hasData: resource.data.peek() !== undefined,\n hasError,\n errorName: hasError ? errorConstructorName(error) : undefined,\n };\n if (options.includeData !== true) return base;\n\n return {\n ...base,\n data: resource.data.peek(),\n ...(hasError ? { errorMessage: errorMessageOf(error) } : {}),\n };\n}\n\nfunction errorConstructorName(error: unknown): string {\n if (error instanceof Error) return error.name;\n return typeof error;\n}\n\nfunction errorMessageOf(error: unknown): string {\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\n// ── Router ──────────────────────────────────────────────────────────────────\n\nexport interface RouteMatchLike {\n readonly path: string;\n readonly pattern: string;\n readonly params: Readonly<Record<string, string>>;\n readonly query: URLSearchParams;\n readonly isFallback?: boolean;\n}\n\nexport interface RouterLike {\n readonly currentRoute: ReadonlySignal<RouteMatchLike>;\n}\n\nexport interface RouterInspection {\n readonly path: string;\n readonly pattern: string;\n readonly params: Record<string, string>;\n readonly query: Record<string, string>;\n readonly isFallback: boolean;\n}\n\n/** Snapshot the router's current route. Read-only. */\nexport function inspectRouter(router: RouterLike): RouterInspection {\n const match = router.currentRoute.peek();\n const query: Record<string, string> = {};\n for (const [k, v] of match.query.entries()) query[k] = v;\n return {\n path: match.path,\n pattern: match.pattern,\n params: { ...match.params },\n query,\n isFallback: match.isFallback === true,\n };\n}\n\n// ── Forms ─────────────────────────────────────────────────────────────────\n\nexport interface FormLike {\n readonly values: ReadonlySignal<Record<string, unknown>>;\n readonly errors: ReadonlySignal<Record<string, string | undefined>>;\n readonly touched: ReadonlySignal<Record<string, boolean | undefined>>;\n readonly dirty: ReadonlySignal<boolean>;\n readonly valid: ReadonlySignal<boolean>;\n readonly status: ReadonlySignal<string>;\n}\n\nexport interface FormInspection {\n readonly fields: string[];\n /** Per-field validation messages (safe — not the entered values). */\n readonly errors: Record<string, string>;\n readonly touched: Record<string, boolean>;\n readonly dirty: boolean;\n readonly valid: boolean;\n readonly status: string;\n /** Entered field values — only present when `includeValues` is set. */\n readonly values?: Record<string, unknown>;\n}\n\nexport interface InspectFormOptions {\n /**\n * Include the entered field `values`. Off by default because form fields\n * frequently hold passwords or other secrets.\n */\n readonly includeValues?: boolean;\n}\n\n/** Snapshot form validation state. Entered values hidden unless opted in. */\nexport function inspectForm(form: FormLike, options: InspectFormOptions = {}): FormInspection {\n const values = form.values.peek();\n const errorsRaw = form.errors.peek();\n const touchedRaw = form.touched.peek();\n\n const errors: Record<string, string> = {};\n for (const [k, v] of Object.entries(errorsRaw)) if (v !== undefined) errors[k] = v;\n const touched: Record<string, boolean> = {};\n for (const [k, v] of Object.entries(touchedRaw)) touched[k] = v === true;\n\n const base: FormInspection = {\n fields: Object.keys(values),\n errors,\n touched,\n dirty: form.dirty.peek(),\n valid: form.valid.peek(),\n status: form.status.peek(),\n };\n if (options.includeValues !== true) return base;\n return { ...base, values: { ...values } };\n}\n\n// ── Context ─────────────────────────────────────────────────────────────────\n\nexport interface ContextLike {\n readonly id: symbol;\n hasProvider(): boolean;\n}\n\nexport interface ContextInspection {\n /** The context's descriptive label (from its Symbol). */\n readonly description: string;\n /** Whether a provider is currently active. */\n readonly hasProvider: boolean;\n}\n\n/** Snapshot a context's identity and provider presence. No value dumped. */\nexport function inspectContext(context: ContextLike): ContextInspection {\n return {\n description: context.id.description ?? 'streetui.context',\n hasProvider: context.hasProvider(),\n };\n}\n\n// ── i18n ──────────────────────────────────────────────────────────────────\n\nexport interface I18nLike {\n readonly locale: ReadonlySignal<string>;\n readonly locales: ReadonlyArray<string>;\n has(key: string): boolean;\n}\n\nexport interface I18nInspection {\n readonly locale: string;\n readonly locales: string[];\n /** Of the probed keys, those with no translation in the active/fallback locale. */\n readonly missingKeys?: string[];\n}\n\nexport interface InspectI18nOptions {\n /** Keys to probe for presence; any absent ones are reported as missing. */\n readonly checkKeys?: readonly string[];\n}\n\n/** Snapshot i18n locale state and (optionally) missing translation keys. */\nexport function inspectI18n(i18n: I18nLike, options: InspectI18nOptions = {}): I18nInspection {\n const base: I18nInspection = {\n locale: i18n.locale.peek(),\n locales: [...i18n.locales],\n };\n if (options.checkKeys === undefined) return base;\n const missingKeys = options.checkKeys.filter((k) => !i18n.has(k));\n return { ...base, missingKeys };\n}\n","/**\n * DevTools session & panels — the first real StreetUI DevTools surface.\n *\n * This is a *headless* DevTools layer: it composes the existing read-only\n * inspection functions (`inspectApplication`, `diagnosePerformance`, and the\n * reactive inspectors) into the panels a DevTools UI shows — Application, Graph,\n * Signals, Router, Resources, Forms, Context, i18n, and Performance — and\n * returns them as plain data plus a text formatter. Any host (a browser panel, a\n * CLI command, a test) can render that data.\n *\n * Design constraints honoured here:\n * - No second graph and no second reactive system — everything is derived from\n * the one `CompiledApplication` and the app's own live signals.\n * - Explicit activation: nothing in the runtime imports this. A session only\n * exists once dev code calls `createDevTools`, so production pays no cost.\n * - Live updates use a simple explicit `refresh()` — DevTools never subscribes\n * to or instruments the reactive graph.\n * - Sensitive surfaces (resource payloads, form values) stay hidden unless the\n * caller opts in per the underlying inspectors.\n */\n\nimport type { CompiledApplication } from '@streetui/compiler';\nimport type { ReadonlySignal } from '@streetui/state';\nimport {\n inspectApplication,\n type ApplicationInspection,\n type ApplicationIdentity,\n type InspectedPage,\n} from './application.js';\nimport type { InspectedNode } from './inspector.js';\nimport { diagnosePerformance, type PerfDiagnostic, type PerfThresholds } from './diagnostics.js';\nimport {\n inspectSignal,\n inspectResource,\n inspectRouter,\n inspectForm,\n inspectContext,\n inspectI18n,\n type SignalInspection,\n type ResourceInspection,\n type RouterInspection,\n type FormInspection,\n type ContextInspection,\n type I18nInspection,\n type ResourceLike,\n type RouterLike,\n type FormLike,\n type ContextLike,\n type I18nLike,\n} from './inspect-reactive.js';\n\n// ── Panel shapes ────────────────────────────────────────────────────────────\n\nexport interface ApplicationPanel {\n readonly identity: ApplicationIdentity;\n readonly nodeCount: number;\n readonly maxDepth: number;\n readonly pages: readonly InspectedPage[];\n readonly signalCount: number;\n readonly eventHandlers: number;\n readonly stateBindings: number;\n readonly errors: number;\n readonly warnings: number;\n}\n\nexport interface SignalsPanel {\n /** Distinct signal ids referenced anywhere in the graph (structural). */\n readonly boundSignalIds: readonly string[];\n /** Live inspections for signals the app registered with DevTools, by label. */\n readonly live: Readonly<Record<string, SignalInspection>>;\n}\n\nexport interface PerformancePanel {\n readonly snapshot: ApplicationInspection['perf'];\n readonly diagnostics: readonly PerfDiagnostic[];\n}\n\n/** All panels captured at one `refresh()`. */\nexport interface DevToolsSnapshot {\n readonly application: ApplicationPanel;\n readonly graph: InspectedNode;\n readonly signals: SignalsPanel;\n readonly performance: PerformancePanel;\n readonly router?: RouterInspection;\n readonly resources?: Readonly<Record<string, ResourceInspection>>;\n readonly forms?: Readonly<Record<string, FormInspection>>;\n readonly contexts?: Readonly<Record<string, ContextInspection>>;\n readonly i18n?: I18nInspection;\n}\n\n// ── Live sources ──────────────────────────────────────────────────────────\n\n/**\n * The app's own live reactive objects, handed to DevTools explicitly so it can\n * inspect them. The compiled graph knows signal *ids* but not the live `Signal`\n * instances, so the app registers whichever surfaces it wants visible. Every\n * field is optional — a session works with none of them (structure-only).\n */\nexport interface DevToolsSources {\n /** Live signals to inspect, keyed by a human label shown in the panel. */\n readonly signals?: Readonly<Record<string, ReadonlySignal<unknown>>>;\n /** Live resources to inspect, keyed by label. */\n readonly resources?: Readonly<Record<string, ResourceLike>>;\n /** The app router, if any. */\n readonly router?: RouterLike;\n /** Live forms to inspect, keyed by label. */\n readonly forms?: Readonly<Record<string, FormLike>>;\n /** Live contexts to inspect, keyed by label. */\n readonly contexts?: Readonly<Record<string, ContextLike>>;\n /** The app i18n instance, if any. */\n readonly i18n?: I18nLike;\n}\n\nexport interface DevToolsOptions {\n /** Thresholds forwarded to `diagnosePerformance`. */\n readonly perfThresholds?: PerfThresholds;\n /**\n * Redact live signal values by default (passed to `inspectSignal`). Use in\n * shared or recorded sessions so values never reach the panel. Off by default.\n */\n readonly redactSignals?: boolean | ((value: unknown) => unknown);\n /** i18n keys to probe for missing translations, forwarded to `inspectI18n`. */\n readonly i18nCheckKeys?: readonly string[];\n}\n\n// ── Session ─────────────────────────────────────────────────────────────────\n\n/**\n * A headless DevTools session over one compiled application.\n *\n * The session holds the compiled app plus the app's registered live sources and\n * produces an immutable {@link DevToolsSnapshot} on demand. Live values are read\n * only when `refresh()` is called (explicit-refresh protocol, §7): the session\n * never subscribes to signals or instruments the reactive graph, so it adds no\n * cost to the running app between refreshes.\n */\nexport interface DevToolsSession {\n /** The most recent snapshot. Recomputed by `refresh()`. */\n readonly snapshot: DevToolsSnapshot;\n /**\n * Recompute every panel from the current live state and return the new\n * snapshot. This is the only way values change — DevTools pulls, it never\n * gets pushed to.\n */\n refresh(): DevToolsSnapshot;\n /**\n * Find a node in the graph by id and return that subtree, or `undefined`.\n * Backs a UI tree inspector's node-selection (§8) without a second graph.\n */\n selectNode(id: string): InspectedNode | undefined;\n /** Render the current snapshot as a plain-text report (for CLI/tests/logs). */\n format(): string;\n}\n\n/**\n * Create a DevTools session. Nothing in the runtime calls this — a session only\n * exists once dev code opts in, so production never pays for it.\n */\nexport function createDevTools(\n compiled: CompiledApplication,\n sources: DevToolsSources = {},\n options: DevToolsOptions = {},\n): DevToolsSession {\n let current = capture(compiled, sources, options);\n\n return {\n get snapshot() {\n return current;\n },\n refresh() {\n current = capture(compiled, sources, options);\n return current;\n },\n selectNode(id: string) {\n return findNode(current.graph, id);\n },\n format() {\n return formatSnapshot(current);\n },\n };\n}\n\n// ── Capture ───────────────────────────────────────────────────────────────\n\nfunction capture(\n compiled: CompiledApplication,\n sources: DevToolsSources,\n options: DevToolsOptions,\n): DevToolsSnapshot {\n const app: ApplicationInspection = inspectApplication(compiled);\n\n const application: ApplicationPanel = {\n identity: app.identity,\n nodeCount: app.perf.totalNodes,\n maxDepth: app.perf.maxDepth,\n pages: app.pages,\n signalCount: app.signals.length,\n eventHandlers: app.perf.eventHandlers,\n stateBindings: app.perf.stateBindings,\n errors: app.diagnostics.errors,\n warnings: app.diagnostics.warnings,\n };\n\n const live: Record<string, SignalInspection> = {};\n if (sources.signals !== undefined) {\n for (const [label, sig] of Object.entries(sources.signals)) {\n live[label] = inspectSignal(\n sig,\n options.redactSignals !== undefined ? { redact: options.redactSignals } : {},\n );\n }\n }\n const signals: SignalsPanel = { boundSignalIds: app.signals, live };\n\n const performance: PerformancePanel = {\n snapshot: app.perf,\n diagnostics: diagnosePerformance(compiled, options.perfThresholds),\n };\n\n const snapshot: DevToolsSnapshot = {\n application,\n graph: app.graph,\n signals,\n performance,\n ...(sources.router !== undefined ? { router: inspectRouter(sources.router) } : {}),\n ...(sources.resources !== undefined\n ? { resources: mapInspect(sources.resources, (r) => inspectResource(r)) }\n : {}),\n ...(sources.forms !== undefined\n ? { forms: mapInspect(sources.forms, (f) => inspectForm(f)) }\n : {}),\n ...(sources.contexts !== undefined\n ? { contexts: mapInspect(sources.contexts, (c) => inspectContext(c)) }\n : {}),\n ...(sources.i18n !== undefined\n ? {\n i18n: inspectI18n(\n sources.i18n,\n options.i18nCheckKeys !== undefined ? { checkKeys: options.i18nCheckKeys } : {},\n ),\n }\n : {}),\n };\n return snapshot;\n}\n\nfunction mapInspect<T, R>(\n source: Readonly<Record<string, T>>,\n inspect: (value: T) => R,\n): Record<string, R> {\n const out: Record<string, R> = {};\n for (const [label, value] of Object.entries(source)) out[label] = inspect(value);\n return out;\n}\n\n// ── Graph node lookup (§8) ──────────────────────────────────────────────────\n\nfunction findNode(node: InspectedNode, id: string): InspectedNode | undefined {\n if (node.id === id) return node;\n for (const child of node.children) {\n const found = findNode(child, id);\n if (found !== undefined) return found;\n }\n return undefined;\n}\n\n// ── Text formatter ────────────────────────────────────────────────────────\n\nfunction formatSnapshot(s: DevToolsSnapshot): string {\n const lines: string[] = [];\n const app = s.application;\n lines.push(`StreetUI DevTools — ${app.identity.name} v${app.identity.version}`);\n lines.push(\n `Application: ${app.nodeCount} nodes, depth ${app.maxDepth}, ${app.pages.length} page(s)`,\n );\n lines.push(\n ` signals ${app.signalCount} · handlers ${app.eventHandlers} · bindings ${app.stateBindings} · errors ${app.errors} · warnings ${app.warnings}`,\n );\n\n lines.push(`Signals: ${s.signals.boundSignalIds.length} bound in graph`);\n for (const [label, sig] of Object.entries(s.signals.live)) {\n lines.push(` ${label} [${sig.kind}] = ${format(sig.value)} · observers ${sig.observerCount ?? '?'}`);\n }\n\n if (s.router !== undefined) {\n lines.push(`Router: ${s.router.path} (${s.router.pattern})${s.router.isFallback ? ' [fallback]' : ''}`);\n }\n\n if (s.resources !== undefined) {\n lines.push('Resources:');\n for (const [label, r] of Object.entries(s.resources)) {\n lines.push(` ${label}: ${r.status}${r.loading ? ' (loading)' : ''}${r.hasError ? ` !${r.errorName}` : ''}`);\n }\n }\n\n if (s.forms !== undefined) {\n lines.push('Forms:');\n for (const [label, f] of Object.entries(s.forms)) {\n lines.push(` ${label}: ${f.valid ? 'valid' : 'invalid'} · ${f.status} · fields ${f.fields.length}`);\n }\n }\n\n if (s.contexts !== undefined) {\n lines.push('Contexts:');\n for (const [label, c] of Object.entries(s.contexts)) {\n lines.push(` ${label} (${c.description}): ${c.hasProvider ? 'provided' : 'no provider'}`);\n }\n }\n\n if (s.i18n !== undefined) {\n const missing = s.i18n.missingKeys;\n lines.push(\n `i18n: ${s.i18n.locale} of [${s.i18n.locales.join(', ')}]${missing !== undefined ? ` · missing ${missing.length}` : ''}`,\n );\n }\n\n lines.push(\n `Performance: ${s.performance.diagnostics.length} diagnostic(s), ${s.performance.snapshot.totalNodes} nodes`,\n );\n for (const d of s.performance.diagnostics) {\n lines.push(` ${d.code}: ${d.message}`);\n }\n\n return lines.join('\\n');\n}\n\nfunction format(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value);\n if (value === null || value === undefined) return String(value);\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value);\n } catch {\n return '[object]';\n }\n }\n return String(value);\n}\n"],"mappings":"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","names":["import_core"]}
|