dev-inspector 1.0.5 → 1.1.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/README.md +22 -1
- package/lib/init.d.ts +5 -2
- package/lib/init.js +5 -2
- package/lib/ui/panel/behavior/setupPanelBehavior.d.ts +4 -1
- package/lib/ui/panel/behavior/setupPanelBehavior.js +48 -1
- package/lib/ui/panel/bindings/bindStorageToPanelView.d.ts +2 -0
- package/lib/ui/panel/bindings/bindStorageToPanelView.js +50 -6
- package/lib/ui/panel/bindings/matchesQuery.d.ts +2 -0
- package/lib/ui/panel/bindings/matchesQuery.js +54 -0
- package/lib/ui/panel/bindings/types.d.ts +2 -0
- package/lib/ui/panel/dom/buildPanelDOM.js +65 -6
- package/lib/ui/panel/dom/constants.d.ts +5 -1
- package/lib/ui/panel/dom/constants.js +35 -20
- package/lib/ui/panel/dom/types.d.ts +6 -0
- package/lib/ui/panel/index.d.ts +4 -0
- package/lib/ui/panel/index.js +8 -3
- package/lib/ui/panel/state/createPanelState.d.ts +2 -1
- package/lib/ui/panel/state/createPanelState.js +5 -1
- package/lib/ui/panel/state/types.d.ts +5 -0
- package/lib/ui/panel/theme/applyTheme.d.ts +2 -0
- package/lib/ui/panel/theme/applyTheme.js +6 -0
- package/lib/ui/panel/theme/index.d.ts +3 -0
- package/lib/ui/panel/theme/index.js +9 -0
- package/lib/ui/panel/theme/storage.d.ts +4 -0
- package/lib/ui/panel/theme/storage.js +45 -0
- package/lib/ui/panel/theme/types.d.ts +6 -0
- package/lib/ui/panel/theme/types.js +2 -0
- package/lib/ui/panelStyles.d.ts +1 -1
- package/lib/ui/panelStyles.js +514 -125
- package/package.json +3 -2
- package/lib/ui/logList/networkDetails.d.ts +0 -2
- package/lib/ui/logList/networkDetails.js +0 -227
- package/lib/ui/logList.d.ts +0 -7
- package/lib/ui/logList.js +0 -117
- package/lib/ui/panel.d.ts +0 -15
- package/lib/ui/panel.js +0 -375
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dev-inspector",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "In-page devtools-style logger panel for web apps (console + network).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"lint-staged": "lint-staged",
|
|
17
17
|
"demo": "vite demo --open",
|
|
18
18
|
"demo:build": "vite build demo",
|
|
19
|
-
"
|
|
19
|
+
"clean": "rm -rf lib",
|
|
20
|
+
"build": "npm run clean && tsc -p tsconfig.json",
|
|
20
21
|
"lint": "eslint \"src/**/*.{ts,tsx,js}\"",
|
|
21
22
|
"prepublishOnly": "npm run build"
|
|
22
23
|
},
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createNetworkDetails = createNetworkDetails;
|
|
4
|
-
const jsonViewer_1 = require("../jsonViewer");
|
|
5
|
-
function tryParseJson(text) {
|
|
6
|
-
const t = text.trim();
|
|
7
|
-
if (t.length < 2)
|
|
8
|
-
return undefined;
|
|
9
|
-
const looksLikeObject = t.startsWith("{") && t.endsWith("}");
|
|
10
|
-
const looksLikeArray = t.startsWith("[") && t.endsWith("]");
|
|
11
|
-
if (!looksLikeObject && !looksLikeArray)
|
|
12
|
-
return undefined;
|
|
13
|
-
try {
|
|
14
|
-
return JSON.parse(t);
|
|
15
|
-
}
|
|
16
|
-
catch (_a) {
|
|
17
|
-
return undefined;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function safeStringify(value) {
|
|
21
|
-
const seen = new WeakSet();
|
|
22
|
-
const replacer = (_key, v) => {
|
|
23
|
-
if (typeof v === "object" && v !== null) {
|
|
24
|
-
const o = v;
|
|
25
|
-
if (seen.has(o))
|
|
26
|
-
return "[circular]";
|
|
27
|
-
seen.add(o);
|
|
28
|
-
}
|
|
29
|
-
return v;
|
|
30
|
-
};
|
|
31
|
-
try {
|
|
32
|
-
return JSON.stringify(value, replacer, 2);
|
|
33
|
-
}
|
|
34
|
-
catch (_a) {
|
|
35
|
-
try {
|
|
36
|
-
return String(value);
|
|
37
|
-
}
|
|
38
|
-
catch (_b) {
|
|
39
|
-
return "[unserializable]";
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
async function copyText(text) {
|
|
44
|
-
var _a, _b;
|
|
45
|
-
try {
|
|
46
|
-
const nav = globalThis;
|
|
47
|
-
const fn = (_b = (_a = nav.navigator) === null || _a === void 0 ? void 0 : _a.clipboard) === null || _b === void 0 ? void 0 : _b.writeText;
|
|
48
|
-
if (typeof fn === "function") {
|
|
49
|
-
await fn(text);
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
catch (_c) {
|
|
54
|
-
void 0;
|
|
55
|
-
}
|
|
56
|
-
try {
|
|
57
|
-
if (typeof document === "undefined")
|
|
58
|
-
return false;
|
|
59
|
-
const ta = document.createElement("textarea");
|
|
60
|
-
ta.value = text;
|
|
61
|
-
ta.setAttribute("readonly", "true");
|
|
62
|
-
ta.style.position = "fixed";
|
|
63
|
-
ta.style.left = "-9999px";
|
|
64
|
-
ta.style.top = "0";
|
|
65
|
-
document.body.append(ta);
|
|
66
|
-
ta.select();
|
|
67
|
-
const ok = document.execCommand("copy");
|
|
68
|
-
ta.remove();
|
|
69
|
-
return ok;
|
|
70
|
-
}
|
|
71
|
-
catch (_d) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function prefersReducedMotion() {
|
|
76
|
-
var _a, _b;
|
|
77
|
-
try {
|
|
78
|
-
const mm = globalThis;
|
|
79
|
-
return ((_b = (_a = mm.matchMedia) === null || _a === void 0 ? void 0 : _a.call(mm, "(prefers-reduced-motion: reduce)")) === null || _b === void 0 ? void 0 : _b.matches) === true;
|
|
80
|
-
}
|
|
81
|
-
catch (_c) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
function rand(min, max) {
|
|
86
|
-
return min + Math.random() * (max - min);
|
|
87
|
-
}
|
|
88
|
-
function launchMiniConfetti(anchor) {
|
|
89
|
-
if (prefersReducedMotion())
|
|
90
|
-
return;
|
|
91
|
-
if (typeof document === "undefined")
|
|
92
|
-
return;
|
|
93
|
-
const rect = anchor.getBoundingClientRect();
|
|
94
|
-
const cx = rect.left + rect.width / 2;
|
|
95
|
-
const cy = rect.top + rect.height / 2;
|
|
96
|
-
const root = document.createElement("div");
|
|
97
|
-
root.style.position = "fixed";
|
|
98
|
-
root.style.left = "0";
|
|
99
|
-
root.style.top = "0";
|
|
100
|
-
root.style.width = "0";
|
|
101
|
-
root.style.height = "0";
|
|
102
|
-
root.style.pointerEvents = "none";
|
|
103
|
-
root.style.zIndex = "2147483647";
|
|
104
|
-
document.body.append(root);
|
|
105
|
-
const colors = ["#a7ff00", "#7c5cff", "#00c4ff", "#ff9030", "#ef4444"];
|
|
106
|
-
const n = 14;
|
|
107
|
-
const duration = 520;
|
|
108
|
-
for (let i = 0; i < n; i += 1) {
|
|
109
|
-
const p = document.createElement("span");
|
|
110
|
-
const size = Math.round(rand(3, 6));
|
|
111
|
-
p.style.position = "fixed";
|
|
112
|
-
p.style.left = `${cx}px`;
|
|
113
|
-
p.style.top = `${cy}px`;
|
|
114
|
-
p.style.width = `${size}px`;
|
|
115
|
-
p.style.height = `${size}px`;
|
|
116
|
-
p.style.borderRadius = Math.random() < 0.35 ? "999px" : "2px";
|
|
117
|
-
p.style.background = colors[i % colors.length];
|
|
118
|
-
p.style.opacity = "1";
|
|
119
|
-
p.style.willChange = "transform, opacity";
|
|
120
|
-
root.append(p);
|
|
121
|
-
const angle = rand(0, Math.PI * 2);
|
|
122
|
-
const dist = rand(18, 46);
|
|
123
|
-
const dx = Math.cos(angle) * dist;
|
|
124
|
-
const dy = Math.sin(angle) * dist + rand(8, 16);
|
|
125
|
-
const rot = rand(-220, 220);
|
|
126
|
-
const delay = Math.round(rand(0, 60));
|
|
127
|
-
try {
|
|
128
|
-
const anim = p.animate([
|
|
129
|
-
{ transform: `translate(-50%, -50%) translate(0px, 0px) rotate(0deg) scale(1)`, opacity: 1 },
|
|
130
|
-
{ transform: `translate(-50%, -50%) translate(${dx}px, ${dy}px) rotate(${rot}deg) scale(0.9)`, opacity: 0 },
|
|
131
|
-
], { duration, delay, easing: "cubic-bezier(0.2, 0.7, 0.2, 1)", fill: "forwards" });
|
|
132
|
-
anim.addEventListener("finish", () => p.remove());
|
|
133
|
-
}
|
|
134
|
-
catch (_a) {
|
|
135
|
-
globalThis.setTimeout(() => p.remove(), duration + delay + 50);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
globalThis.setTimeout(() => root.remove(), duration + 120);
|
|
139
|
-
}
|
|
140
|
-
function valueToElement(doc, value) {
|
|
141
|
-
if (typeof value === "string") {
|
|
142
|
-
const parsed = tryParseJson(value);
|
|
143
|
-
if (parsed && typeof parsed === "object") {
|
|
144
|
-
return (0, jsonViewer_1.createJsonViewer)(doc, parsed, { maxDepth: 6, maxKeys: 200, maxNodes: 2000 });
|
|
145
|
-
}
|
|
146
|
-
const el = doc.createElement("div");
|
|
147
|
-
el.className = "di-netBodyText";
|
|
148
|
-
el.textContent = value;
|
|
149
|
-
return el;
|
|
150
|
-
}
|
|
151
|
-
if (value instanceof Error) {
|
|
152
|
-
const el = doc.createElement("div");
|
|
153
|
-
el.className = "di-netBodyText";
|
|
154
|
-
el.textContent = `${value.name}: ${value.message}`;
|
|
155
|
-
return el;
|
|
156
|
-
}
|
|
157
|
-
if (value === null || typeof value !== "object") {
|
|
158
|
-
const el = doc.createElement("div");
|
|
159
|
-
el.className = "di-netBodyText";
|
|
160
|
-
el.textContent = String(value);
|
|
161
|
-
return el;
|
|
162
|
-
}
|
|
163
|
-
return (0, jsonViewer_1.createJsonViewer)(doc, value, { maxDepth: 6, maxKeys: 200, maxNodes: 2000 });
|
|
164
|
-
}
|
|
165
|
-
function valueToCopyText(value) {
|
|
166
|
-
if (typeof value === "string")
|
|
167
|
-
return value;
|
|
168
|
-
if (value instanceof Error)
|
|
169
|
-
return `${value.name}: ${value.message}`;
|
|
170
|
-
return safeStringify(value);
|
|
171
|
-
}
|
|
172
|
-
function createBodyDetails(doc, title, value, truncated, maxLen) {
|
|
173
|
-
const details = doc.createElement("details");
|
|
174
|
-
details.className = "di-details di-netBodyDetails";
|
|
175
|
-
const summary = doc.createElement("summary");
|
|
176
|
-
summary.className = "di-detailsSummary di-netDetailsSummary";
|
|
177
|
-
const titleEl = doc.createElement("span");
|
|
178
|
-
titleEl.className = "di-netDetailsTitle";
|
|
179
|
-
titleEl.textContent = title;
|
|
180
|
-
const copyBtn = doc.createElement("button");
|
|
181
|
-
copyBtn.type = "button";
|
|
182
|
-
copyBtn.className = "di-copyBtn";
|
|
183
|
-
copyBtn.textContent = "Copy";
|
|
184
|
-
copyBtn.setAttribute("aria-label", `Copy ${title.toLowerCase()}`);
|
|
185
|
-
copyBtn.addEventListener("click", (ev) => {
|
|
186
|
-
ev.preventDefault();
|
|
187
|
-
ev.stopPropagation();
|
|
188
|
-
const txt = valueToCopyText(value);
|
|
189
|
-
void copyText(txt).then((ok) => {
|
|
190
|
-
if (!ok)
|
|
191
|
-
return;
|
|
192
|
-
launchMiniConfetti(copyBtn);
|
|
193
|
-
const prev = copyBtn.textContent;
|
|
194
|
-
copyBtn.textContent = "Copied";
|
|
195
|
-
globalThis.setTimeout(() => {
|
|
196
|
-
copyBtn.textContent = prev !== null && prev !== void 0 ? prev : "Copy";
|
|
197
|
-
}, 900);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
summary.append(titleEl, copyBtn);
|
|
201
|
-
const body = doc.createElement("div");
|
|
202
|
-
body.className = "di-detailsBody";
|
|
203
|
-
if (truncated) {
|
|
204
|
-
const warn = doc.createElement("div");
|
|
205
|
-
warn.className = "di-netTrunc";
|
|
206
|
-
warn.textContent = typeof maxLen === "number" ? `Truncated to first ${maxLen} characters.` : "Truncated.";
|
|
207
|
-
body.append(warn);
|
|
208
|
-
}
|
|
209
|
-
body.append(valueToElement(doc, value));
|
|
210
|
-
details.append(summary, body);
|
|
211
|
-
return details;
|
|
212
|
-
}
|
|
213
|
-
function createNetworkDetails(doc, entry) {
|
|
214
|
-
const hasReq = typeof entry.requestBody !== "undefined";
|
|
215
|
-
const hasRes = typeof entry.responseBody !== "undefined";
|
|
216
|
-
if (!hasReq && !hasRes)
|
|
217
|
-
return null;
|
|
218
|
-
const wrap = doc.createElement("div");
|
|
219
|
-
wrap.className = "di-netDetailsWrap";
|
|
220
|
-
if (hasReq) {
|
|
221
|
-
wrap.append(createBodyDetails(doc, "Request", entry.requestBody, entry.requestBodyTruncated === true, entry.bodyMaxLength));
|
|
222
|
-
}
|
|
223
|
-
if (hasRes) {
|
|
224
|
-
wrap.append(createBodyDetails(doc, "Response", entry.responseBody, entry.responseBodyTruncated === true, entry.bodyMaxLength));
|
|
225
|
-
}
|
|
226
|
-
return wrap;
|
|
227
|
-
}
|
package/lib/ui/logList.d.ts
DELETED
package/lib/ui/logList.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createLogList = createLogList;
|
|
4
|
-
const jsonViewer_1 = require("./jsonViewer");
|
|
5
|
-
const networkDetails_1 = require("./logList/networkDetails");
|
|
6
|
-
function fmtTime(ts) {
|
|
7
|
-
const d = new Date(ts);
|
|
8
|
-
const hh = String(d.getHours()).padStart(2, "0");
|
|
9
|
-
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
10
|
-
const ss = String(d.getSeconds()).padStart(2, "0");
|
|
11
|
-
return `${hh}:${mm}:${ss}`;
|
|
12
|
-
}
|
|
13
|
-
function toneForEntry(entry) {
|
|
14
|
-
if (entry.source === "console") {
|
|
15
|
-
if (entry.level === "error")
|
|
16
|
-
return "error";
|
|
17
|
-
if (entry.level === "warn")
|
|
18
|
-
return "warning";
|
|
19
|
-
return "neutral";
|
|
20
|
-
}
|
|
21
|
-
const s = entry.status;
|
|
22
|
-
if (typeof s !== "number")
|
|
23
|
-
return "error";
|
|
24
|
-
if (s >= 400)
|
|
25
|
-
return "error";
|
|
26
|
-
if (s >= 300)
|
|
27
|
-
return "warning";
|
|
28
|
-
return "success";
|
|
29
|
-
}
|
|
30
|
-
function classForTone(tone) {
|
|
31
|
-
if (tone === "error")
|
|
32
|
-
return "di-itemToneError";
|
|
33
|
-
if (tone === "warning")
|
|
34
|
-
return "di-itemToneWarning";
|
|
35
|
-
if (tone === "success")
|
|
36
|
-
return "di-itemToneSuccess";
|
|
37
|
-
return "di-itemToneNeutral";
|
|
38
|
-
}
|
|
39
|
-
function isNetworkFailure(entry) {
|
|
40
|
-
if (entry.source !== "network")
|
|
41
|
-
return false;
|
|
42
|
-
return typeof entry.status !== "number" || entry.status >= 400;
|
|
43
|
-
}
|
|
44
|
-
function isInspectableValue(value) {
|
|
45
|
-
if (typeof value !== "object" || value === null)
|
|
46
|
-
return false;
|
|
47
|
-
if (value instanceof Error)
|
|
48
|
-
return false;
|
|
49
|
-
if (value instanceof Date)
|
|
50
|
-
return false;
|
|
51
|
-
if (value instanceof RegExp)
|
|
52
|
-
return false;
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
function getInspectableArgs(args) {
|
|
56
|
-
return args.filter(isInspectableValue);
|
|
57
|
-
}
|
|
58
|
-
function createLogList(doc) {
|
|
59
|
-
const el = doc.createElement("ul");
|
|
60
|
-
el.className = "di-list";
|
|
61
|
-
const append = (entry) => {
|
|
62
|
-
const li = doc.createElement("li");
|
|
63
|
-
const tone = toneForEntry(entry);
|
|
64
|
-
li.className = `di-item ${classForTone(tone)}`;
|
|
65
|
-
const meta = doc.createElement("div");
|
|
66
|
-
meta.className = "di-meta";
|
|
67
|
-
const time = doc.createElement("span");
|
|
68
|
-
time.textContent = fmtTime(entry.timestamp);
|
|
69
|
-
const source = doc.createElement("span");
|
|
70
|
-
source.textContent = entry.source;
|
|
71
|
-
const detail = doc.createElement("span");
|
|
72
|
-
if (entry.source === "console") {
|
|
73
|
-
detail.textContent = entry.level;
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
detail.className = `di-statusChip ${isNetworkFailure(entry) ? "di-statusChipError" : "di-statusChipSuccess"}`;
|
|
77
|
-
detail.textContent = typeof entry.status === "number" ? String(entry.status) : "ERR";
|
|
78
|
-
}
|
|
79
|
-
meta.append(time, source, detail);
|
|
80
|
-
li.append(meta);
|
|
81
|
-
if (entry.message && entry.message.trim().length > 0) {
|
|
82
|
-
const msg = doc.createElement("div");
|
|
83
|
-
msg.className = "di-msg";
|
|
84
|
-
msg.textContent = entry.message;
|
|
85
|
-
li.append(msg);
|
|
86
|
-
}
|
|
87
|
-
if (entry.source === "console") {
|
|
88
|
-
const inspectable = getInspectableArgs(entry.args);
|
|
89
|
-
if (inspectable.length > 0) {
|
|
90
|
-
const details = doc.createElement("details");
|
|
91
|
-
details.className = "di-details";
|
|
92
|
-
const summary = doc.createElement("summary");
|
|
93
|
-
summary.className = "di-detailsSummary";
|
|
94
|
-
summary.textContent = "Inspect";
|
|
95
|
-
const viewerWrap = doc.createElement("div");
|
|
96
|
-
viewerWrap.className = "di-detailsBody";
|
|
97
|
-
viewerWrap.append((0, jsonViewer_1.createJsonViewer)(doc, inspectable.length === 1 ? inspectable[0] : inspectable, {
|
|
98
|
-
maxDepth: 6,
|
|
99
|
-
maxKeys: 200,
|
|
100
|
-
maxNodes: 2000,
|
|
101
|
-
}));
|
|
102
|
-
details.append(summary, viewerWrap);
|
|
103
|
-
li.append(details);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (entry.source === "network") {
|
|
107
|
-
const details = (0, networkDetails_1.createNetworkDetails)(doc, entry);
|
|
108
|
-
if (details)
|
|
109
|
-
li.append(details);
|
|
110
|
-
}
|
|
111
|
-
el.append(li);
|
|
112
|
-
};
|
|
113
|
-
const clear = () => {
|
|
114
|
-
el.replaceChildren();
|
|
115
|
-
};
|
|
116
|
-
return { el, append, clear };
|
|
117
|
-
}
|
package/lib/ui/panel.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { LogStorage } from "../storage/logStorage";
|
|
2
|
-
export type PanelOptions = {
|
|
3
|
-
storage: LogStorage;
|
|
4
|
-
title?: string;
|
|
5
|
-
initiallyOpen?: boolean;
|
|
6
|
-
mount?: HTMLElement;
|
|
7
|
-
};
|
|
8
|
-
export type PanelHandle = {
|
|
9
|
-
open: () => void;
|
|
10
|
-
close: () => void;
|
|
11
|
-
toggle: () => void;
|
|
12
|
-
destroy: () => void;
|
|
13
|
-
isOpen: () => boolean;
|
|
14
|
-
};
|
|
15
|
-
export declare function createPanel(options: PanelOptions): PanelHandle;
|