dev-inspector 1.0.0 → 1.0.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 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
@@ -24,6 +24,34 @@ function truncateString(value, maxLen) {
24
24
  return value;
25
25
  return value.slice(0, maxLen);
26
26
  }
27
+ function coerceUrl(input) {
28
+ if (typeof input === "string")
29
+ return input;
30
+ if (!input)
31
+ return undefined;
32
+ if (typeof input.href === "string")
33
+ return input.href;
34
+ if (typeof input.url === "string")
35
+ return input.url;
36
+ return undefined;
37
+ }
38
+ function formatUrlForMessage(raw) {
39
+ var _a, _b;
40
+ if (!raw)
41
+ return "";
42
+ try {
43
+ const loc = globalThis;
44
+ const base = typeof ((_a = loc.location) === null || _a === void 0 ? void 0 : _a.href) === "string" ? loc.location.href : undefined;
45
+ const u = new URL(raw, base);
46
+ const origin = typeof ((_b = loc.location) === null || _b === void 0 ? void 0 : _b.origin) === "string" ? loc.location.origin : undefined;
47
+ if (origin && u.origin === origin)
48
+ return `${u.pathname}${u.search}${u.hash}`;
49
+ return u.href;
50
+ }
51
+ catch (_c) {
52
+ return raw;
53
+ }
54
+ }
27
55
  async function readResponseBody(response, maxLen) {
28
56
  try {
29
57
  const text = await response.text();
@@ -34,13 +62,36 @@ async function readResponseBody(response, maxLen) {
34
62
  }
35
63
  }
36
64
  function makeMessage(entry) {
37
- var _a, _b;
65
+ var _a;
38
66
  const m = (_a = entry.method) !== null && _a !== void 0 ? _a : "";
39
- const u = (_b = entry.url) !== null && _b !== void 0 ? _b : "";
67
+ const u = formatUrlForMessage(entry.url);
40
68
  const s = typeof entry.status === "number" ? ` ${entry.status}` : "";
41
69
  const d = typeof entry.durationMs === "number" ? ` ${Math.round(entry.durationMs)}ms` : "";
42
70
  return `${m} ${u}${s}${d}`.trim();
43
71
  }
72
+ function getFetchTimingDurationMs(url, startPerf) {
73
+ if (!url)
74
+ return undefined;
75
+ if (typeof performance === "undefined")
76
+ return undefined;
77
+ if (typeof performance.getEntriesByName !== "function")
78
+ return undefined;
79
+ const entries = performance.getEntriesByName(url);
80
+ if (!entries || entries.length === 0)
81
+ return undefined;
82
+ const candidates = entries.filter((e) => {
83
+ const rt = e;
84
+ const initiatorOk = typeof rt.initiatorType === "string" ? rt.initiatorType === "fetch" : true;
85
+ const startOk = typeof rt.startTime === "number" ? Math.abs(rt.startTime - startPerf) < 1000 : true;
86
+ return initiatorOk && startOk;
87
+ });
88
+ const chosen = (candidates.length > 0 ? candidates : entries)[(candidates.length > 0 ? candidates : entries).length - 1];
89
+ if (typeof chosen.duration === "number" && chosen.duration > 0)
90
+ return chosen.duration;
91
+ if (typeof chosen.responseEnd === "number" && typeof chosen.startTime === "number" && chosen.responseEnd > 0)
92
+ return chosen.responseEnd - chosen.startTime;
93
+ return undefined;
94
+ }
44
95
  const xhrMeta = new WeakMap();
45
96
  function installNetworkLogger(options) {
46
97
  var _a, _b;
@@ -55,30 +106,28 @@ function installNetworkLogger(options) {
55
106
  const originalXhrSend = canXhr ? g.XMLHttpRequest.prototype.send : undefined;
56
107
  if (canFetch) {
57
108
  g.fetch = (async (...args) => {
58
- var _a;
109
+ var _a, _b, _c;
59
110
  const start = now();
111
+ const startPerf = typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : start;
60
112
  const id = createId();
61
113
  let method;
62
114
  let url;
63
115
  let requestBody;
64
116
  try {
65
117
  const [input, init] = args;
66
- if (typeof input === "string")
67
- url = input;
68
- else if (input && typeof input.url === "string")
69
- url = input.url;
118
+ url = coerceUrl(input);
70
119
  const reqMethodFromInit = init === null || init === void 0 ? void 0 : init.method;
71
120
  const reqMethodFromInput = input && typeof input.method === "string" ? input.method : undefined;
72
121
  method = ((_a = reqMethodFromInit !== null && reqMethodFromInit !== void 0 ? reqMethodFromInit : reqMethodFromInput) !== null && _a !== void 0 ? _a : "GET").toUpperCase();
73
122
  if (includeBodies && init && "body" in init)
74
123
  requestBody = init.body;
75
124
  }
76
- catch (_b) {
125
+ catch (_d) {
77
126
  void 0;
78
127
  }
79
128
  try {
80
- const res = await originalFetch(...args);
81
- const durationMs = now() - start;
129
+ const res = await Reflect.apply(originalFetch, globalThis, args);
130
+ const durationMs = (_b = getFetchTimingDurationMs(url, startPerf)) !== null && _b !== void 0 ? _b : (now() - start);
82
131
  const status = res.status;
83
132
  let responseBody;
84
133
  if (includeBodies) {
@@ -103,7 +152,7 @@ function installNetworkLogger(options) {
103
152
  return res;
104
153
  }
105
154
  catch (err) {
106
- const durationMs = now() - start;
155
+ const durationMs = (_c = getFetchTimingDurationMs(url, startPerf)) !== null && _c !== void 0 ? _c : (now() - start);
107
156
  if (active) {
108
157
  const entry = {
109
158
  id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dev-inspector",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
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",