dev-inspector 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/lib/logger/consoleLogger.js +10 -1
- package/lib/logger/networkLogger.js +39 -25
- package/lib/ui/jsonViewer.d.ts +16 -0
- package/lib/ui/jsonViewer.js +156 -0
- package/lib/ui/logList.js +41 -4
- package/lib/ui/panelStyles.d.ts +1 -1
- package/lib/ui/panelStyles.js +63 -0
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -28,6 +28,26 @@ initDevInspector({
|
|
|
28
28
|
});
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
## Important: Browser-only (SSR)
|
|
32
|
+
|
|
33
|
+
Dev Inspector’s UI (`createPanel()` and the default `initDevInspector()` flow) requires a **browser environment** (it needs `document`).
|
|
34
|
+
|
|
35
|
+
If your app uses **SSR** (Next.js, Remix, Nuxt, SvelteKit, etc.), do not call `initDevInspector()` at module scope on the server. Initialize it **client-side only** (e.g. in an effect, lifecycle hook, or a client-only component).
|
|
36
|
+
|
|
37
|
+
Example (client-only init with dynamic import):
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
async function initInBrowser() {
|
|
41
|
+
if (typeof window === "undefined") return;
|
|
42
|
+
const { initDevInspector } = await import("dev-inspector");
|
|
43
|
+
initDevInspector({
|
|
44
|
+
panelOptions: { initiallyOpen: true, title: "Dev Inspector" },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
initInBrowser();
|
|
49
|
+
```
|
|
50
|
+
|
|
31
51
|
If you want manual control, you can keep the returned handles:
|
|
32
52
|
|
|
33
53
|
```ts
|
|
@@ -34,7 +34,16 @@ function getCircularReplacer() {
|
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
function formatArgs(args) {
|
|
37
|
-
|
|
37
|
+
const parts = args
|
|
38
|
+
.map((a) => {
|
|
39
|
+
if (a instanceof Error)
|
|
40
|
+
return `${a.name}: ${a.message}`;
|
|
41
|
+
if (typeof a === "object" && a !== null)
|
|
42
|
+
return null;
|
|
43
|
+
return safeStringify(a);
|
|
44
|
+
})
|
|
45
|
+
.filter((x) => typeof x === "string" && x.length > 0);
|
|
46
|
+
return parts.join(" ");
|
|
38
47
|
}
|
|
39
48
|
function installConsoleLogger(options) {
|
|
40
49
|
var _a;
|
|
@@ -6,9 +6,6 @@ function createId() {
|
|
|
6
6
|
seq += 1;
|
|
7
7
|
return `${Date.now()}-${seq}`;
|
|
8
8
|
}
|
|
9
|
-
function now() {
|
|
10
|
-
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
11
|
-
}
|
|
12
9
|
function safeToString(value) {
|
|
13
10
|
try {
|
|
14
11
|
return String(value);
|
|
@@ -24,6 +21,34 @@ function truncateString(value, maxLen) {
|
|
|
24
21
|
return value;
|
|
25
22
|
return value.slice(0, maxLen);
|
|
26
23
|
}
|
|
24
|
+
function coerceUrl(input) {
|
|
25
|
+
if (typeof input === "string")
|
|
26
|
+
return input;
|
|
27
|
+
if (!input)
|
|
28
|
+
return undefined;
|
|
29
|
+
if (typeof input.href === "string")
|
|
30
|
+
return input.href;
|
|
31
|
+
if (typeof input.url === "string")
|
|
32
|
+
return input.url;
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
function formatUrlForMessage(raw) {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
if (!raw)
|
|
38
|
+
return "";
|
|
39
|
+
try {
|
|
40
|
+
const loc = globalThis;
|
|
41
|
+
const base = typeof ((_a = loc.location) === null || _a === void 0 ? void 0 : _a.href) === "string" ? loc.location.href : undefined;
|
|
42
|
+
const u = new URL(raw, base);
|
|
43
|
+
const origin = typeof ((_b = loc.location) === null || _b === void 0 ? void 0 : _b.origin) === "string" ? loc.location.origin : undefined;
|
|
44
|
+
if (origin && u.origin === origin)
|
|
45
|
+
return `${u.pathname}${u.search}${u.hash}`;
|
|
46
|
+
return u.href;
|
|
47
|
+
}
|
|
48
|
+
catch (_c) {
|
|
49
|
+
return raw;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
27
52
|
async function readResponseBody(response, maxLen) {
|
|
28
53
|
try {
|
|
29
54
|
const text = await response.text();
|
|
@@ -34,12 +59,11 @@ async function readResponseBody(response, maxLen) {
|
|
|
34
59
|
}
|
|
35
60
|
}
|
|
36
61
|
function makeMessage(entry) {
|
|
37
|
-
var _a
|
|
62
|
+
var _a;
|
|
38
63
|
const m = (_a = entry.method) !== null && _a !== void 0 ? _a : "";
|
|
39
|
-
const u = (
|
|
64
|
+
const u = formatUrlForMessage(entry.url);
|
|
40
65
|
const s = typeof entry.status === "number" ? ` ${entry.status}` : "";
|
|
41
|
-
|
|
42
|
-
return `${m} ${u}${s}${d}`.trim();
|
|
66
|
+
return `${m} ${u}${s}`.trim();
|
|
43
67
|
}
|
|
44
68
|
const xhrMeta = new WeakMap();
|
|
45
69
|
function installNetworkLogger(options) {
|
|
@@ -56,17 +80,13 @@ function installNetworkLogger(options) {
|
|
|
56
80
|
if (canFetch) {
|
|
57
81
|
g.fetch = (async (...args) => {
|
|
58
82
|
var _a;
|
|
59
|
-
const start = now();
|
|
60
83
|
const id = createId();
|
|
61
84
|
let method;
|
|
62
85
|
let url;
|
|
63
86
|
let requestBody;
|
|
64
87
|
try {
|
|
65
88
|
const [input, init] = args;
|
|
66
|
-
|
|
67
|
-
url = input;
|
|
68
|
-
else if (input && typeof input.url === "string")
|
|
69
|
-
url = input.url;
|
|
89
|
+
url = coerceUrl(input);
|
|
70
90
|
const reqMethodFromInit = init === null || init === void 0 ? void 0 : init.method;
|
|
71
91
|
const reqMethodFromInput = input && typeof input.method === "string" ? input.method : undefined;
|
|
72
92
|
method = ((_a = reqMethodFromInit !== null && reqMethodFromInit !== void 0 ? reqMethodFromInit : reqMethodFromInput) !== null && _a !== void 0 ? _a : "GET").toUpperCase();
|
|
@@ -77,8 +97,7 @@ function installNetworkLogger(options) {
|
|
|
77
97
|
void 0;
|
|
78
98
|
}
|
|
79
99
|
try {
|
|
80
|
-
const res = await originalFetch
|
|
81
|
-
const durationMs = now() - start;
|
|
100
|
+
const res = await Reflect.apply(originalFetch, globalThis, args);
|
|
82
101
|
const status = res.status;
|
|
83
102
|
let responseBody;
|
|
84
103
|
if (includeBodies) {
|
|
@@ -93,17 +112,15 @@ function installNetworkLogger(options) {
|
|
|
93
112
|
method,
|
|
94
113
|
url,
|
|
95
114
|
status,
|
|
96
|
-
durationMs,
|
|
97
115
|
requestBody: includeBodies ? requestBody : undefined,
|
|
98
116
|
responseBody: includeBodies ? responseBody : undefined,
|
|
99
|
-
message: makeMessage({ method, url, status
|
|
117
|
+
message: makeMessage({ method, url, status }),
|
|
100
118
|
};
|
|
101
119
|
options.emit(entry);
|
|
102
120
|
}
|
|
103
121
|
return res;
|
|
104
122
|
}
|
|
105
123
|
catch (err) {
|
|
106
|
-
const durationMs = now() - start;
|
|
107
124
|
if (active) {
|
|
108
125
|
const entry = {
|
|
109
126
|
id,
|
|
@@ -112,10 +129,9 @@ function installNetworkLogger(options) {
|
|
|
112
129
|
method,
|
|
113
130
|
url,
|
|
114
131
|
status: undefined,
|
|
115
|
-
durationMs,
|
|
116
132
|
requestBody: includeBodies ? requestBody : undefined,
|
|
117
133
|
responseBody: includeBodies ? safeToString(err) : undefined,
|
|
118
|
-
message: makeMessage({ method, url, status: undefined
|
|
134
|
+
message: makeMessage({ method, url, status: undefined }),
|
|
119
135
|
};
|
|
120
136
|
options.emit(entry);
|
|
121
137
|
}
|
|
@@ -130,16 +146,16 @@ function installNetworkLogger(options) {
|
|
|
130
146
|
proto.open = function (...args) {
|
|
131
147
|
try {
|
|
132
148
|
const [method, url] = args;
|
|
133
|
-
xhrMeta.set(this, { id: createId(),
|
|
149
|
+
xhrMeta.set(this, { id: createId(), method: safeToString(method).toUpperCase(), url: safeToString(url) });
|
|
134
150
|
}
|
|
135
151
|
catch (_a) {
|
|
136
|
-
xhrMeta.set(this, { id: createId()
|
|
152
|
+
xhrMeta.set(this, { id: createId() });
|
|
137
153
|
}
|
|
138
154
|
return originalOpen.apply(this, args);
|
|
139
155
|
};
|
|
140
156
|
proto.send = function (...args) {
|
|
141
157
|
var _a;
|
|
142
|
-
const meta = (_a = xhrMeta.get(this)) !== null && _a !== void 0 ? _a : { id: createId()
|
|
158
|
+
const meta = (_a = xhrMeta.get(this)) !== null && _a !== void 0 ? _a : { id: createId() };
|
|
143
159
|
if (includeBodies) {
|
|
144
160
|
try {
|
|
145
161
|
meta.requestBody = args[0];
|
|
@@ -150,7 +166,6 @@ function installNetworkLogger(options) {
|
|
|
150
166
|
}
|
|
151
167
|
xhrMeta.set(this, meta);
|
|
152
168
|
const onLoadEnd = () => {
|
|
153
|
-
const durationMs = now() - meta.start;
|
|
154
169
|
const status = typeof this.status === "number" ? this.status : undefined;
|
|
155
170
|
let responseBody;
|
|
156
171
|
if (includeBodies) {
|
|
@@ -172,10 +187,9 @@ function installNetworkLogger(options) {
|
|
|
172
187
|
method: meta.method,
|
|
173
188
|
url: meta.url,
|
|
174
189
|
status,
|
|
175
|
-
durationMs,
|
|
176
190
|
requestBody: includeBodies ? meta.requestBody : undefined,
|
|
177
191
|
responseBody: includeBodies ? responseBody : undefined,
|
|
178
|
-
message: makeMessage({ method: meta.method, url: meta.url, status
|
|
192
|
+
message: makeMessage({ method: meta.method, url: meta.url, status }),
|
|
179
193
|
};
|
|
180
194
|
options.emit(entry);
|
|
181
195
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type JsonViewerOptions = {
|
|
2
|
+
maxDepth?: number;
|
|
3
|
+
maxKeys?: number;
|
|
4
|
+
maxNodes?: number;
|
|
5
|
+
};
|
|
6
|
+
type Ctx = {
|
|
7
|
+
doc: Document;
|
|
8
|
+
seen: WeakSet<object>;
|
|
9
|
+
nodes: number;
|
|
10
|
+
maxDepth: number;
|
|
11
|
+
maxKeys: number;
|
|
12
|
+
maxNodes: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function renderAny(ctx: Ctx, value: unknown, depth: number): HTMLElement;
|
|
15
|
+
export declare function createJsonViewer(doc: Document, value: unknown, options?: JsonViewerOptions): HTMLElement;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderAny = renderAny;
|
|
4
|
+
exports.createJsonViewer = createJsonViewer;
|
|
5
|
+
function isObject(value) {
|
|
6
|
+
return typeof value === "object" && value !== null;
|
|
7
|
+
}
|
|
8
|
+
function typeLabel(value) {
|
|
9
|
+
if (value === null)
|
|
10
|
+
return "null";
|
|
11
|
+
const t = typeof value;
|
|
12
|
+
if (t !== "object")
|
|
13
|
+
return t;
|
|
14
|
+
if (Array.isArray(value))
|
|
15
|
+
return `Array(${value.length})`;
|
|
16
|
+
const tag = Object.prototype.toString.call(value);
|
|
17
|
+
return tag.slice(8, -1) || "Object";
|
|
18
|
+
}
|
|
19
|
+
function shortPreview(value) {
|
|
20
|
+
if (value === null)
|
|
21
|
+
return "null";
|
|
22
|
+
if (typeof value === "string") {
|
|
23
|
+
const s = value.length > 120 ? `${value.slice(0, 120)}…` : value;
|
|
24
|
+
return JSON.stringify(s);
|
|
25
|
+
}
|
|
26
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint")
|
|
27
|
+
return String(value);
|
|
28
|
+
if (typeof value === "undefined")
|
|
29
|
+
return "undefined";
|
|
30
|
+
if (typeof value === "function")
|
|
31
|
+
return "function";
|
|
32
|
+
if (typeof value === "symbol")
|
|
33
|
+
return "symbol";
|
|
34
|
+
if (typeof value === "object") {
|
|
35
|
+
if (Array.isArray(value))
|
|
36
|
+
return `Array(${value.length})`;
|
|
37
|
+
return "Object";
|
|
38
|
+
}
|
|
39
|
+
return String(value);
|
|
40
|
+
}
|
|
41
|
+
function canExpand(value) {
|
|
42
|
+
if (!isObject(value))
|
|
43
|
+
return false;
|
|
44
|
+
if (value instanceof Date)
|
|
45
|
+
return false;
|
|
46
|
+
if (value instanceof RegExp)
|
|
47
|
+
return false;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
function row(doc, key, valueEl) {
|
|
51
|
+
const el = doc.createElement("div");
|
|
52
|
+
el.className = "di-jsonRow";
|
|
53
|
+
const k = doc.createElement("span");
|
|
54
|
+
k.className = "di-jsonKey";
|
|
55
|
+
k.textContent = key;
|
|
56
|
+
el.append(k, valueEl);
|
|
57
|
+
return el;
|
|
58
|
+
}
|
|
59
|
+
function leaf(ctx, value) {
|
|
60
|
+
const el = ctx.doc.createElement("span");
|
|
61
|
+
el.className = "di-jsonValue";
|
|
62
|
+
el.textContent = shortPreview(value);
|
|
63
|
+
return el;
|
|
64
|
+
}
|
|
65
|
+
function renderObject(ctx, value, depth) {
|
|
66
|
+
if (!isObject(value))
|
|
67
|
+
return leaf(ctx, value);
|
|
68
|
+
if (!canExpand(value))
|
|
69
|
+
return leaf(ctx, value);
|
|
70
|
+
if (ctx.nodes >= ctx.maxNodes) {
|
|
71
|
+
const el = ctx.doc.createElement("span");
|
|
72
|
+
el.className = "di-jsonValue";
|
|
73
|
+
el.textContent = "[truncated]";
|
|
74
|
+
return el;
|
|
75
|
+
}
|
|
76
|
+
const obj = value;
|
|
77
|
+
if (ctx.seen.has(obj)) {
|
|
78
|
+
const el = ctx.doc.createElement("span");
|
|
79
|
+
el.className = "di-jsonValue";
|
|
80
|
+
el.textContent = "[circular]";
|
|
81
|
+
return el;
|
|
82
|
+
}
|
|
83
|
+
ctx.seen.add(obj);
|
|
84
|
+
ctx.nodes += 1;
|
|
85
|
+
const details = ctx.doc.createElement("details");
|
|
86
|
+
details.className = "di-jsonNode";
|
|
87
|
+
details.open = depth === 0;
|
|
88
|
+
const summary = ctx.doc.createElement("summary");
|
|
89
|
+
summary.className = "di-jsonSummary";
|
|
90
|
+
summary.textContent = `${typeLabel(value)} ${shortPreview(value)}`;
|
|
91
|
+
details.append(summary);
|
|
92
|
+
if (depth >= ctx.maxDepth) {
|
|
93
|
+
const el = ctx.doc.createElement("div");
|
|
94
|
+
el.className = "di-jsonBody";
|
|
95
|
+
const msg = ctx.doc.createElement("div");
|
|
96
|
+
msg.className = "di-jsonTrunc";
|
|
97
|
+
msg.textContent = "Max depth reached";
|
|
98
|
+
el.append(msg);
|
|
99
|
+
details.append(el);
|
|
100
|
+
return details;
|
|
101
|
+
}
|
|
102
|
+
const body = ctx.doc.createElement("div");
|
|
103
|
+
body.className = "di-jsonBody";
|
|
104
|
+
if (Array.isArray(value)) {
|
|
105
|
+
const arr = value;
|
|
106
|
+
const limit = Math.min(arr.length, ctx.maxKeys);
|
|
107
|
+
for (let i = 0; i < limit; i += 1) {
|
|
108
|
+
const v = arr[i];
|
|
109
|
+
body.append(row(ctx.doc, String(i), renderAny(ctx, v, depth + 1)));
|
|
110
|
+
}
|
|
111
|
+
if (arr.length > limit) {
|
|
112
|
+
const more = ctx.doc.createElement("div");
|
|
113
|
+
more.className = "di-jsonMore";
|
|
114
|
+
more.textContent = `… +${arr.length - limit} more`;
|
|
115
|
+
body.append(more);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
const rec = value;
|
|
120
|
+
const keys = Object.keys(rec);
|
|
121
|
+
const limit = Math.min(keys.length, ctx.maxKeys);
|
|
122
|
+
for (let i = 0; i < limit; i += 1) {
|
|
123
|
+
const k = keys[i];
|
|
124
|
+
const v = rec[k];
|
|
125
|
+
body.append(row(ctx.doc, k, renderAny(ctx, v, depth + 1)));
|
|
126
|
+
}
|
|
127
|
+
if (keys.length > limit) {
|
|
128
|
+
const more = ctx.doc.createElement("div");
|
|
129
|
+
more.className = "di-jsonMore";
|
|
130
|
+
more.textContent = `… +${keys.length - limit} more`;
|
|
131
|
+
body.append(more);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
details.append(body);
|
|
135
|
+
return details;
|
|
136
|
+
}
|
|
137
|
+
function renderAny(ctx, value, depth) {
|
|
138
|
+
if (!canExpand(value))
|
|
139
|
+
return leaf(ctx, value);
|
|
140
|
+
return renderObject(ctx, value, depth);
|
|
141
|
+
}
|
|
142
|
+
function createJsonViewer(doc, value, options = {}) {
|
|
143
|
+
var _a, _b, _c;
|
|
144
|
+
const ctx = {
|
|
145
|
+
doc,
|
|
146
|
+
seen: new WeakSet(),
|
|
147
|
+
nodes: 0,
|
|
148
|
+
maxDepth: Math.max(1, (_a = options.maxDepth) !== null && _a !== void 0 ? _a : 6),
|
|
149
|
+
maxKeys: Math.max(10, (_b = options.maxKeys) !== null && _b !== void 0 ? _b : 200),
|
|
150
|
+
maxNodes: Math.max(50, (_c = options.maxNodes) !== null && _c !== void 0 ? _c : 2000),
|
|
151
|
+
};
|
|
152
|
+
const root = doc.createElement("div");
|
|
153
|
+
root.className = "di-jsonRoot";
|
|
154
|
+
root.append(renderAny(ctx, value, 0));
|
|
155
|
+
return root;
|
|
156
|
+
}
|
package/lib/ui/logList.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createLogList = createLogList;
|
|
4
|
+
const jsonViewer_1 = require("./jsonViewer");
|
|
4
5
|
function fmtTime(ts) {
|
|
5
6
|
const d = new Date(ts);
|
|
6
7
|
const hh = String(d.getHours()).padStart(2, "0");
|
|
@@ -39,6 +40,20 @@ function isNetworkFailure(entry) {
|
|
|
39
40
|
return false;
|
|
40
41
|
return typeof entry.status !== "number" || entry.status >= 400;
|
|
41
42
|
}
|
|
43
|
+
function isInspectableValue(value) {
|
|
44
|
+
if (typeof value !== "object" || value === null)
|
|
45
|
+
return false;
|
|
46
|
+
if (value instanceof Error)
|
|
47
|
+
return false;
|
|
48
|
+
if (value instanceof Date)
|
|
49
|
+
return false;
|
|
50
|
+
if (value instanceof RegExp)
|
|
51
|
+
return false;
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
function getInspectableArgs(args) {
|
|
55
|
+
return args.filter(isInspectableValue);
|
|
56
|
+
}
|
|
42
57
|
function createLogList(doc) {
|
|
43
58
|
const el = doc.createElement("ul");
|
|
44
59
|
el.className = "di-list";
|
|
@@ -61,10 +76,32 @@ function createLogList(doc) {
|
|
|
61
76
|
detail.textContent = typeof entry.status === "number" ? String(entry.status) : "ERR";
|
|
62
77
|
}
|
|
63
78
|
meta.append(time, source, detail);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
li.append(meta);
|
|
80
|
+
if (entry.message && entry.message.trim().length > 0) {
|
|
81
|
+
const msg = doc.createElement("div");
|
|
82
|
+
msg.className = "di-msg";
|
|
83
|
+
msg.textContent = entry.message;
|
|
84
|
+
li.append(msg);
|
|
85
|
+
}
|
|
86
|
+
if (entry.source === "console") {
|
|
87
|
+
const inspectable = getInspectableArgs(entry.args);
|
|
88
|
+
if (inspectable.length > 0) {
|
|
89
|
+
const details = doc.createElement("details");
|
|
90
|
+
details.className = "di-details";
|
|
91
|
+
const summary = doc.createElement("summary");
|
|
92
|
+
summary.className = "di-detailsSummary";
|
|
93
|
+
summary.textContent = "Inspect";
|
|
94
|
+
const viewerWrap = doc.createElement("div");
|
|
95
|
+
viewerWrap.className = "di-detailsBody";
|
|
96
|
+
viewerWrap.append((0, jsonViewer_1.createJsonViewer)(doc, inspectable.length === 1 ? inspectable[0] : inspectable, {
|
|
97
|
+
maxDepth: 6,
|
|
98
|
+
maxKeys: 200,
|
|
99
|
+
maxNodes: 2000,
|
|
100
|
+
}));
|
|
101
|
+
details.append(summary, viewerWrap);
|
|
102
|
+
li.append(details);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
68
105
|
el.append(li);
|
|
69
106
|
};
|
|
70
107
|
const clear = () => {
|
package/lib/ui/panelStyles.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PANEL_CSS = "\n.di-root, .di-root * {\n box-sizing: border-box;\n}\n\n.di-toggle {\n position: fixed;\n right: 12px;\n bottom: 12px;\n z-index: 2147483647;\n border: 1px solid rgba(255,255,255,0.18);\n background: rgba(20,20,20,0.92);\n color: #fff;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n padding: 8px 10px;\n border-radius: 10px;\n cursor: pointer;\n backdrop-filter: blur(8px);\n box-shadow: 0 10px 30px rgba(0,0,0,0.35);\n display: inline-flex;\n align-items: center;\n gap: 10px;\n}\n\n.di-toggleTitle {\n font-weight: 600;\n}\n\n.di-toggleMeta {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n\n.di-toggleBadge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n border-radius: 999px;\n border: 1px solid rgba(255,255,255,0.16);\n background: rgba(0,0,0,0.28);\n font-size: 11px;\n line-height: 1;\n}\n\n.di-toggleErr {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-left: 2px;\n padding: 2px 6px;\n border-radius: 999px;\n background: rgba(239, 68, 68, 0.95);\n color: #fff;\n font-size: 11px;\n line-height: 1;\n}\n\n.di-toggleErrIcon {\n font-weight: 700;\n transform: translateY(-0.5px);\n}\n\n.di-toggleIcon {\n width: 14px;\n height: 14px;\n display: inline-block;\n}\n\n.di-panel {\n position: fixed;\n right: 12px;\n bottom: 56px;\n width: min(520px, calc(100vw - 24px));\n height: min(380px, calc(100vh - 84px));\n z-index: 2147483647;\n border: 1px solid rgba(255,255,255,0.14);\n background: rgba(16,16,16,0.92);\n color: #eaeaea;\n border-radius: 12px;\n overflow: hidden;\n display: grid;\n grid-template-rows: auto 1fr;\n backdrop-filter: blur(8px);\n box-shadow: 0 10px 30px rgba(0,0,0,0.45);\n}\n\n.di-resizeHandle {\n width: 18px;\n height: 18px;\n flex: 0 0 18px;\n border-radius: 8px;\n cursor: nwse-resize;\n touch-action: none;\n opacity: 0.9;\n border: 1px solid rgba(255,255,255,0.14);\n background: rgba(255,255,255,0.06);\n position: relative;\n}\n\n.di-resizeHandle::before {\n content: \"\";\n position: absolute;\n inset: 4px;\n border-radius: 6px;\n background:\n linear-gradient(135deg, rgba(255,255,255,0.65) 0 2px, transparent 0) 0 0 / 6px 6px,\n linear-gradient(135deg, rgba(255,255,255,0.35) 0 2px, transparent 0) 3px 3px / 6px 6px;\n}\n\n.di-resizeHandle:hover {\n opacity: 1;\n border-color: rgba(255,255,255,0.24);\n background: rgba(255,255,255,0.10);\n}\n\n.di-hidden {\n display: none;\n}\n\n.di-header {\n display: grid;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid rgba(255,255,255,0.12);\n}\n\n.di-headerRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.di-title {\n font: 600 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n opacity: 0.95;\n}\n\n.di-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.di-btn {\n border: 1px solid rgba(255,255,255,0.14);\n background: rgba(255,255,255,0.06);\n color: #fff;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n padding: 6px 8px;\n border-radius: 10px;\n cursor: pointer;\n}\n\n.di-tabs {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.di-tab {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n border: 1px solid rgba(255,255,255,0.14);\n background: rgba(255,255,255,0.06);\n color: #fff;\n padding: 6px 10px;\n border-radius: 999px;\n cursor: pointer;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n opacity: 0.9;\n}\n\n.di-tab:hover {\n background: rgba(255,255,255,0.10);\n border-color: rgba(255,255,255,0.22);\n}\n\n.di-tabActive {\n opacity: 1;\n background: rgba(255,255,255,0.14);\n border-color: rgba(255,255,255,0.28);\n}\n\n.di-tabIcon {\n width: 14px;\n height: 14px;\n display: inline-block;\n}\n\n.di-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 6px;\n border-radius: 999px;\n border: 1px solid rgba(255,255,255,0.16);\n background: rgba(0,0,0,0.28);\n font-size: 11px;\n line-height: 1;\n}\n\n.di-body {\n overflow: auto;\n}\n\n.di-list {\n margin: 0;\n padding: 8px 10px;\n list-style: none;\n display: grid;\n gap: 6px;\n}\n\n.di-item {\n padding: 8px 10px;\n border: 1px solid rgba(255,255,255,0.10);\n border-radius: 10px;\n background: rgba(255,255,255,0.04);\n}\n\n.di-itemToneNeutral {\n border-color: rgba(255,255,255,0.10);\n background: rgba(255,255,255,0.04);\n}\n\n.di-itemToneSuccess {\n border-color: rgba(34, 197, 94, 0.35);\n background: rgba(34, 197, 94, 0.10);\n}\n\n.di-itemToneWarning {\n border-color: rgba(245, 158, 11, 0.42);\n background: rgba(245, 158, 11, 0.12);\n}\n\n.di-itemToneError {\n border-color: rgba(239, 68, 68, 0.45);\n background: rgba(239, 68, 68, 0.12);\n}\n\n.di-meta {\n display: flex;\n gap: 10px;\n font: 11px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n opacity: 0.85;\n margin-bottom: 4px;\n}\n\n.di-statusChip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 2px 8px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1;\n color: #fff;\n}\n\n.di-statusChipSuccess {\n background: rgba(34, 197, 94, 0.95);\n}\n\n.di-statusChipError {\n background: rgba(239, 68, 68, 0.95);\n}\n\n.di-msg {\n white-space: pre-wrap;\n word-break: break-word;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n";
|
|
1
|
+
export declare const PANEL_CSS = "\n.di-root, .di-root * {\n box-sizing: border-box;\n}\n\n.di-toggle {\n position: fixed;\n right: 12px;\n bottom: 12px;\n z-index: 2147483647;\n border: 1px solid rgba(255,255,255,0.18);\n background: rgba(20,20,20,0.92);\n color: #fff;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n padding: 8px 10px;\n border-radius: 10px;\n cursor: pointer;\n backdrop-filter: blur(8px);\n box-shadow: 0 10px 30px rgba(0,0,0,0.35);\n display: inline-flex;\n align-items: center;\n gap: 10px;\n}\n\n.di-toggleTitle {\n font-weight: 600;\n}\n\n.di-toggleMeta {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n\n.di-toggleBadge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n border-radius: 999px;\n border: 1px solid rgba(255,255,255,0.16);\n background: rgba(0,0,0,0.28);\n font-size: 11px;\n line-height: 1;\n}\n\n.di-toggleErr {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-left: 2px;\n padding: 2px 6px;\n border-radius: 999px;\n background: rgba(239, 68, 68, 0.95);\n color: #fff;\n font-size: 11px;\n line-height: 1;\n}\n\n.di-toggleErrIcon {\n font-weight: 700;\n transform: translateY(-0.5px);\n}\n\n.di-toggleIcon {\n width: 14px;\n height: 14px;\n display: inline-block;\n}\n\n.di-panel {\n position: fixed;\n right: 12px;\n bottom: 56px;\n width: min(520px, calc(100vw - 24px));\n height: min(380px, calc(100vh - 84px));\n z-index: 2147483647;\n border: 1px solid rgba(255,255,255,0.14);\n background: rgba(16,16,16,0.92);\n color: #eaeaea;\n border-radius: 12px;\n overflow: hidden;\n display: grid;\n grid-template-rows: auto 1fr;\n backdrop-filter: blur(8px);\n box-shadow: 0 10px 30px rgba(0,0,0,0.45);\n}\n\n.di-resizeHandle {\n width: 18px;\n height: 18px;\n flex: 0 0 18px;\n border-radius: 8px;\n cursor: nwse-resize;\n touch-action: none;\n opacity: 0.9;\n border: 1px solid rgba(255,255,255,0.14);\n background: rgba(255,255,255,0.06);\n position: relative;\n}\n\n.di-resizeHandle::before {\n content: \"\";\n position: absolute;\n inset: 4px;\n border-radius: 6px;\n background:\n linear-gradient(135deg, rgba(255,255,255,0.65) 0 2px, transparent 0) 0 0 / 6px 6px,\n linear-gradient(135deg, rgba(255,255,255,0.35) 0 2px, transparent 0) 3px 3px / 6px 6px;\n}\n\n.di-resizeHandle:hover {\n opacity: 1;\n border-color: rgba(255,255,255,0.24);\n background: rgba(255,255,255,0.10);\n}\n\n.di-hidden {\n display: none;\n}\n\n.di-header {\n display: grid;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid rgba(255,255,255,0.12);\n}\n\n.di-headerRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.di-title {\n font: 600 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n opacity: 0.95;\n}\n\n.di-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.di-btn {\n border: 1px solid rgba(255,255,255,0.14);\n background: rgba(255,255,255,0.06);\n color: #fff;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n padding: 6px 8px;\n border-radius: 10px;\n cursor: pointer;\n}\n\n.di-tabs {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.di-tab {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n border: 1px solid rgba(255,255,255,0.14);\n background: rgba(255,255,255,0.06);\n color: #fff;\n padding: 6px 10px;\n border-radius: 999px;\n cursor: pointer;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n opacity: 0.9;\n}\n\n.di-tab:hover {\n background: rgba(255,255,255,0.10);\n border-color: rgba(255,255,255,0.22);\n}\n\n.di-tabActive {\n opacity: 1;\n background: rgba(255,255,255,0.14);\n border-color: rgba(255,255,255,0.28);\n}\n\n.di-tabIcon {\n width: 14px;\n height: 14px;\n display: inline-block;\n}\n\n.di-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 6px;\n border-radius: 999px;\n border: 1px solid rgba(255,255,255,0.16);\n background: rgba(0,0,0,0.28);\n font-size: 11px;\n line-height: 1;\n}\n\n.di-body {\n overflow: auto;\n}\n\n.di-list {\n margin: 0;\n padding: 8px 10px;\n list-style: none;\n display: grid;\n gap: 6px;\n}\n\n.di-item {\n padding: 8px 10px;\n border: 1px solid rgba(255,255,255,0.10);\n border-radius: 10px;\n background: rgba(255,255,255,0.04);\n}\n\n.di-itemToneNeutral {\n border-color: rgba(255,255,255,0.10);\n background: rgba(255,255,255,0.04);\n}\n\n.di-itemToneSuccess {\n border-color: rgba(34, 197, 94, 0.35);\n background: rgba(34, 197, 94, 0.10);\n}\n\n.di-itemToneWarning {\n border-color: rgba(245, 158, 11, 0.42);\n background: rgba(245, 158, 11, 0.12);\n}\n\n.di-itemToneError {\n border-color: rgba(239, 68, 68, 0.45);\n background: rgba(239, 68, 68, 0.12);\n}\n\n.di-meta {\n display: flex;\n gap: 10px;\n font: 11px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n opacity: 0.85;\n margin-bottom: 4px;\n}\n\n.di-statusChip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 2px 8px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1;\n color: #fff;\n}\n\n.di-statusChipSuccess {\n background: rgba(34, 197, 94, 0.95);\n}\n\n.di-statusChipError {\n background: rgba(239, 68, 68, 0.95);\n}\n\n.di-msg {\n white-space: pre-wrap;\n word-break: break-word;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n.di-details {\n margin-top: 8px;\n}\n\n.di-detailsSummary {\n cursor: pointer;\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n opacity: 0.9;\n user-select: none;\n}\n\n.di-detailsBody {\n margin-top: 6px;\n padding: 8px 10px;\n border-radius: 10px;\n border: 1px solid rgba(255,255,255,0.10);\n background: rgba(0,0,0,0.22);\n}\n\n.di-jsonRoot {\n font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.di-jsonNode {\n margin-left: 0;\n}\n\n.di-jsonSummary {\n cursor: pointer;\n user-select: none;\n opacity: 0.95;\n}\n\n.di-jsonBody {\n margin-top: 6px;\n padding-left: 12px;\n display: grid;\n gap: 4px;\n}\n\n.di-jsonRow {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 10px;\n align-items: start;\n}\n\n.di-jsonKey {\n opacity: 0.85;\n color: rgba(255,255,255,0.78);\n}\n\n.di-jsonValue {\n opacity: 0.95;\n color: rgba(255,255,255,0.92);\n}\n\n.di-jsonMore, .di-jsonTrunc {\n opacity: 0.75;\n}\n";
|
package/lib/ui/panelStyles.js
CHANGED
|
@@ -279,4 +279,67 @@ exports.PANEL_CSS = `
|
|
|
279
279
|
word-break: break-word;
|
|
280
280
|
font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
281
281
|
}
|
|
282
|
+
|
|
283
|
+
.di-details {
|
|
284
|
+
margin-top: 8px;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.di-detailsSummary {
|
|
288
|
+
cursor: pointer;
|
|
289
|
+
font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
290
|
+
opacity: 0.9;
|
|
291
|
+
user-select: none;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.di-detailsBody {
|
|
295
|
+
margin-top: 6px;
|
|
296
|
+
padding: 8px 10px;
|
|
297
|
+
border-radius: 10px;
|
|
298
|
+
border: 1px solid rgba(255,255,255,0.10);
|
|
299
|
+
background: rgba(0,0,0,0.22);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.di-jsonRoot {
|
|
303
|
+
font: 12px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
304
|
+
white-space: pre-wrap;
|
|
305
|
+
word-break: break-word;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.di-jsonNode {
|
|
309
|
+
margin-left: 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.di-jsonSummary {
|
|
313
|
+
cursor: pointer;
|
|
314
|
+
user-select: none;
|
|
315
|
+
opacity: 0.95;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.di-jsonBody {
|
|
319
|
+
margin-top: 6px;
|
|
320
|
+
padding-left: 12px;
|
|
321
|
+
display: grid;
|
|
322
|
+
gap: 4px;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.di-jsonRow {
|
|
326
|
+
display: grid;
|
|
327
|
+
grid-template-columns: auto 1fr;
|
|
328
|
+
gap: 10px;
|
|
329
|
+
align-items: start;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.di-jsonKey {
|
|
333
|
+
opacity: 0.85;
|
|
334
|
+
color: rgba(255,255,255,0.78);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.di-jsonValue {
|
|
338
|
+
opacity: 0.95;
|
|
339
|
+
color: rgba(255,255,255,0.92);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.di-jsonMore, .di-jsonTrunc {
|
|
343
|
+
opacity: 0.75;
|
|
344
|
+
}
|
|
282
345
|
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dev-inspector",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "In-page devtools-style logger panel for web apps (console + network).",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
"files": [
|
|
40
40
|
"lib/**/*"
|
|
41
41
|
],
|
|
42
|
-
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"@eslint/js": "^9.39.2",
|
|
45
44
|
"eslint": "^9.39.2",
|