dev-inspector 1.0.4 → 1.1.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.
Files changed (86) hide show
  1. package/README.md +22 -1
  2. package/lib/init.d.ts +5 -2
  3. package/lib/init.js +5 -2
  4. package/lib/integrations/index.d.ts +2 -0
  5. package/lib/integrations/index.js +7 -0
  6. package/lib/integrations/jira/adf.d.ts +11 -0
  7. package/lib/integrations/jira/adf.js +17 -0
  8. package/lib/integrations/jira/client.d.ts +4 -0
  9. package/lib/integrations/jira/client.js +113 -0
  10. package/lib/integrations/jira/errors.d.ts +10 -0
  11. package/lib/integrations/jira/errors.js +13 -0
  12. package/lib/integrations/jira/index.d.ts +2 -0
  13. package/lib/integrations/jira/index.js +8 -0
  14. package/lib/integrations/types.d.ts +54 -0
  15. package/lib/integrations/types.js +2 -0
  16. package/lib/logger/networkLogger.js +41 -11
  17. package/lib/storage/localStorage.d.ts +30 -0
  18. package/lib/storage/localStorage.js +166 -0
  19. package/lib/ui/logList/createLogList.d.ts +2 -0
  20. package/lib/ui/logList/createLogList.js +67 -0
  21. package/lib/ui/logList/index.d.ts +2 -0
  22. package/lib/ui/logList/index.js +5 -0
  23. package/lib/ui/logList/networkDetails/copy.d.ts +2 -0
  24. package/lib/ui/logList/networkDetails/copy.js +101 -0
  25. package/lib/ui/logList/{networkDetails.d.ts → networkDetails/createNetworkDetails.d.ts} +1 -1
  26. package/lib/ui/logList/networkDetails/createNetworkDetails.js +61 -0
  27. package/lib/ui/logList/networkDetails/index.d.ts +1 -0
  28. package/lib/ui/logList/networkDetails/index.js +5 -0
  29. package/lib/ui/logList/networkDetails/renderValue.d.ts +2 -0
  30. package/lib/ui/logList/{networkDetails.js → networkDetails/renderValue.js} +32 -32
  31. package/lib/ui/logList/shared/consoleInspect.d.ts +1 -0
  32. package/lib/ui/logList/shared/consoleInspect.js +17 -0
  33. package/lib/ui/logList/shared/index.d.ts +3 -0
  34. package/lib/ui/logList/shared/index.js +11 -0
  35. package/lib/ui/logList/shared/time.d.ts +1 -0
  36. package/lib/ui/logList/shared/time.js +10 -0
  37. package/lib/ui/logList/shared/tone.d.ts +6 -0
  38. package/lib/ui/logList/shared/tone.js +36 -0
  39. package/lib/ui/logList/types.d.ts +6 -0
  40. package/lib/ui/logList/types.js +2 -0
  41. package/lib/ui/panel/behavior/setupPanelBehavior.d.ts +4 -1
  42. package/lib/ui/panel/behavior/setupPanelBehavior.js +48 -1
  43. package/lib/ui/panel/bindings/bindStorageToPanelView.d.ts +2 -0
  44. package/lib/ui/panel/bindings/bindStorageToPanelView.js +50 -6
  45. package/lib/ui/panel/bindings/matchesQuery.d.ts +2 -0
  46. package/lib/ui/panel/bindings/matchesQuery.js +54 -0
  47. package/lib/ui/panel/bindings/types.d.ts +2 -0
  48. package/lib/ui/panel/dom/buildPanelDOM.js +65 -6
  49. package/lib/ui/panel/dom/constants.d.ts +5 -1
  50. package/lib/ui/panel/dom/constants.js +35 -20
  51. package/lib/ui/panel/dom/types.d.ts +6 -0
  52. package/lib/ui/panel/index.d.ts +4 -0
  53. package/lib/ui/panel/index.js +8 -3
  54. package/lib/ui/panel/integrations/icons.d.ts +1 -0
  55. package/lib/ui/panel/integrations/icons.js +7 -0
  56. package/lib/ui/panel/integrations/index.d.ts +1 -0
  57. package/lib/ui/panel/integrations/index.js +5 -0
  58. package/lib/ui/panel/integrations/jiraDialog.d.ts +6 -0
  59. package/lib/ui/panel/integrations/jiraDialog.js +234 -0
  60. package/lib/ui/panel/integrations/screenshot.d.ts +4 -0
  61. package/lib/ui/panel/integrations/screenshot.js +51 -0
  62. package/lib/ui/panel/localStorage/createLocalStorageView.d.ts +4 -0
  63. package/lib/ui/panel/localStorage/createLocalStorageView.js +108 -0
  64. package/lib/ui/panel/localStorage/index.d.ts +3 -0
  65. package/lib/ui/panel/localStorage/index.js +7 -0
  66. package/lib/ui/panel/localStorage/setupLocalStorageSync.d.ts +9 -0
  67. package/lib/ui/panel/localStorage/setupLocalStorageSync.js +30 -0
  68. package/lib/ui/panel/localStorage/types.d.ts +6 -0
  69. package/lib/ui/panel/localStorage/types.js +2 -0
  70. package/lib/ui/panel/state/createPanelState.d.ts +2 -1
  71. package/lib/ui/panel/state/createPanelState.js +5 -1
  72. package/lib/ui/panel/state/types.d.ts +5 -0
  73. package/lib/ui/panel/theme/applyTheme.d.ts +2 -0
  74. package/lib/ui/panel/theme/applyTheme.js +6 -0
  75. package/lib/ui/panel/theme/index.d.ts +3 -0
  76. package/lib/ui/panel/theme/index.js +9 -0
  77. package/lib/ui/panel/theme/storage.d.ts +4 -0
  78. package/lib/ui/panel/theme/storage.js +45 -0
  79. package/lib/ui/panel/theme/types.d.ts +6 -0
  80. package/lib/ui/panel/theme/types.js +2 -0
  81. package/lib/ui/panelStyles.d.ts +1 -1
  82. package/lib/ui/panelStyles.js +557 -116
  83. package/lib/ui/shared/copy.d.ts +2 -0
  84. package/lib/ui/shared/copy.js +101 -0
  85. package/lib/utils/types.d.ts +3 -0
  86. package/package.json +1 -1
package/README.md CHANGED
@@ -19,6 +19,10 @@ In-page devtools-style logger panel for web apps. Capture **console** and **netw
19
19
  - Network interception: `fetch` + `XMLHttpRequest`
20
20
  - In-memory storage with events (`EventTarget`)
21
21
  - UI panel with tabs (Console / Network), counters, severity/status colors, and resize
22
+ - Search across console messages and network requests (URL, method, status, body)
23
+ - Auto-scroll lock with a "Latest" jump button that surfaces unread entries
24
+ - Light / dark theme with `localStorage` persistence (defaults to light)
25
+ - Configurable panel title (used in the header and the floating toggle)
22
26
  - Vite demo playground
23
27
 
24
28
  ## Installation
@@ -35,10 +39,27 @@ import { initDevInspector } from "dev-inspector";
35
39
  initDevInspector({
36
40
  maxSize: 500,
37
41
  networkOptions: { includeBodies: false },
38
- panelOptions: { initiallyOpen: true, title: "Dev Inspector" },
42
+ panelOptions: {
43
+ initiallyOpen: true,
44
+ title: "My App Inspector",
45
+ theme: "light",
46
+ persistTheme: true,
47
+ },
39
48
  });
40
49
  ```
41
50
 
51
+ ### Panel options
52
+
53
+ | Option | Type | Default | Description |
54
+ | ----------------- | ------------------- | ----------------------- | ------------------------------------------------------------------------------------ |
55
+ | `title` | `string` | `"Dev Inspector"` | Label shown in the panel header **and** the floating toggle pill in the bottom-right |
56
+ | `initiallyOpen` | `boolean` | `true` | Open the panel on mount |
57
+ | `theme` | `"light" \| "dark"` | `"light"` | Initial theme. Overridden by a stored value when `persistTheme` is `true` |
58
+ | `persistTheme` | `boolean` | `true` | Persist the user's theme choice in `localStorage` |
59
+ | `themeStorageKey` | `string` | `"dev-inspector:theme"` | Key used by `localStorage` to remember the theme |
60
+
61
+ The theme can also be toggled at runtime via the sun/moon button in the panel header. When `persistTheme` is `true`, the choice is stored under `themeStorageKey` and restored on the next load.
62
+
42
63
  ## Important: Browser-only (SSR)
43
64
 
44
65
  Dev Inspector’s UI (`createPanel()` and the default `initDevInspector()` flow) requires a **browser environment** (it needs `document`).
package/lib/init.d.ts CHANGED
@@ -1,8 +1,12 @@
1
- type InitOptions = {
1
+ export type Theme = "light" | "dark";
2
+ export type InitOptions = {
2
3
  maxSize?: number;
3
4
  panelOptions?: {
4
5
  title?: string;
5
6
  initiallyOpen?: boolean;
7
+ theme?: Theme;
8
+ persistTheme?: boolean;
9
+ themeStorageKey?: string;
6
10
  };
7
11
  networkOptions?: {
8
12
  includeBodies?: boolean;
@@ -10,4 +14,3 @@ type InitOptions = {
10
14
  };
11
15
  };
12
16
  export declare function initDevInspector(options?: InitOptions): void;
13
- export {};
package/lib/init.js CHANGED
@@ -12,7 +12,7 @@ function getGlobalBag() {
12
12
  return globalThis;
13
13
  }
14
14
  function initDevInspector(options = {}) {
15
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
15
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
16
16
  const key = getGlobalInstanceKey();
17
17
  const bag = getGlobalBag();
18
18
  const prev = bag[key];
@@ -20,7 +20,7 @@ function initDevInspector(options = {}) {
20
20
  try {
21
21
  prev.destroy();
22
22
  }
23
- catch (_k) {
23
+ catch (_o) {
24
24
  void 0;
25
25
  }
26
26
  }
@@ -35,6 +35,9 @@ function initDevInspector(options = {}) {
35
35
  storage,
36
36
  initiallyOpen: (_g = (_f = options.panelOptions) === null || _f === void 0 ? void 0 : _f.initiallyOpen) !== null && _g !== void 0 ? _g : true,
37
37
  title: (_j = (_h = options.panelOptions) === null || _h === void 0 ? void 0 : _h.title) !== null && _j !== void 0 ? _j : "Dev Inspector",
38
+ theme: (_k = options.panelOptions) === null || _k === void 0 ? void 0 : _k.theme,
39
+ persistTheme: (_l = options.panelOptions) === null || _l === void 0 ? void 0 : _l.persistTheme,
40
+ themeStorageKey: (_m = options.panelOptions) === null || _m === void 0 ? void 0 : _m.themeStorageKey,
38
41
  });
39
42
  const destroy = () => {
40
43
  try {
@@ -0,0 +1,2 @@
1
+ export type { CreateIssueInput, CreateIssueResult, IntegrationContext, IntegrationId, IntegrationsConfig, JiraIntegrationConfig } from "./types";
2
+ export { createJiraIssue, fetchJiraIssueTypes, JiraIntegrationError } from "./jira";
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JiraIntegrationError = exports.fetchJiraIssueTypes = exports.createJiraIssue = void 0;
4
+ var jira_1 = require("./jira");
5
+ Object.defineProperty(exports, "createJiraIssue", { enumerable: true, get: function () { return jira_1.createJiraIssue; } });
6
+ Object.defineProperty(exports, "fetchJiraIssueTypes", { enumerable: true, get: function () { return jira_1.fetchJiraIssueTypes; } });
7
+ Object.defineProperty(exports, "JiraIntegrationError", { enumerable: true, get: function () { return jira_1.JiraIntegrationError; } });
@@ -0,0 +1,11 @@
1
+ export declare function textToAdf(text: string): {
2
+ type: string;
3
+ version: number;
4
+ content: {
5
+ type: string;
6
+ content: {
7
+ type: string;
8
+ text: string;
9
+ }[];
10
+ }[];
11
+ };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.textToAdf = textToAdf;
4
+ function paragraph(text) {
5
+ return {
6
+ type: "paragraph",
7
+ content: text.length > 0 ? [{ type: "text", text }] : [],
8
+ };
9
+ }
10
+ function textToAdf(text) {
11
+ const lines = text.split(/\r?\n/);
12
+ return {
13
+ type: "doc",
14
+ version: 1,
15
+ content: lines.map((l) => paragraph(l)),
16
+ };
17
+ }
@@ -0,0 +1,4 @@
1
+ import type { CreateIssueInput, CreateIssueResult, JiraIntegrationConfig } from "../types";
2
+ import type { JiraIssueTypeOption } from "../types";
3
+ export declare function fetchJiraIssueTypes(config: JiraIntegrationConfig, projectKey?: string): Promise<JiraIssueTypeOption[]>;
4
+ export declare function createJiraIssue(input: CreateIssueInput, config: JiraIntegrationConfig): Promise<CreateIssueResult>;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchJiraIssueTypes = fetchJiraIssueTypes;
4
+ exports.createJiraIssue = createJiraIssue;
5
+ const adf_1 = require("./adf");
6
+ const errors_1 = require("./errors");
7
+ async function readJsonSafe(res) {
8
+ try {
9
+ return (await res.json());
10
+ }
11
+ catch (_a) {
12
+ return undefined;
13
+ }
14
+ }
15
+ function mapStatus(status) {
16
+ if (status === 400)
17
+ return { code: "bad_request", message: "Bad request. Check required fields and Jira configuration." };
18
+ if (status === 401)
19
+ return { code: "unauthorized", message: "Unauthorized. Check Jira credentials." };
20
+ if (status === 403)
21
+ return { code: "forbidden", message: "Forbidden. Check Jira permissions." };
22
+ if (status === 429)
23
+ return { code: "rate_limited", message: "Rate limited by Jira. Try again later." };
24
+ if (status >= 500)
25
+ return { code: "server_error", message: "Jira server error. Try again later." };
26
+ return { code: "unknown", message: "Unexpected Jira error." };
27
+ }
28
+ function isRecord(value) {
29
+ return typeof value === "object" && value !== null;
30
+ }
31
+ function toQuery(params) {
32
+ const sp = new URLSearchParams();
33
+ for (const [k, v] of Object.entries(params)) {
34
+ if (typeof v === "string" && v.length > 0)
35
+ sp.set(k, v);
36
+ }
37
+ const s = sp.toString();
38
+ return s.length > 0 ? `?${s}` : "";
39
+ }
40
+ async function fetchJiraIssueTypes(config, projectKey) {
41
+ var _a;
42
+ const proxyUrl = config.proxyUrl;
43
+ if (!proxyUrl)
44
+ throw new errors_1.JiraIntegrationError("Missing Jira proxyUrl.", "not_configured");
45
+ const url = `${proxyUrl}${toQuery({ op: "issueTypes", projectKey: (_a = projectKey !== null && projectKey !== void 0 ? projectKey : config.projectKey) !== null && _a !== void 0 ? _a : "" })}`;
46
+ let res;
47
+ try {
48
+ res = await fetch(url, { method: "GET", headers: { accept: "application/json" } });
49
+ }
50
+ catch (e) {
51
+ throw new errors_1.JiraIntegrationError("Network error while loading Jira issue types.", "network_error", { details: String(e) });
52
+ }
53
+ const data = await readJsonSafe(res);
54
+ if (!res.ok) {
55
+ const mapped = mapStatus(res.status);
56
+ throw new errors_1.JiraIntegrationError(mapped.message, mapped.code, { status: res.status, details: data });
57
+ }
58
+ if (!Array.isArray(data))
59
+ return [];
60
+ const out = [];
61
+ for (const it of data) {
62
+ if (!isRecord(it))
63
+ continue;
64
+ const id = typeof it.id === "string" ? it.id : undefined;
65
+ const name = typeof it.name === "string" ? it.name : undefined;
66
+ if (id && name)
67
+ out.push({ id, name });
68
+ }
69
+ return out;
70
+ }
71
+ async function createJiraIssue(input, config) {
72
+ var _a, _b, _c, _d, _e, _f;
73
+ const title = input.title.trim();
74
+ if (title.length === 0)
75
+ throw new errors_1.JiraIntegrationError("Title is required.", "bad_request");
76
+ const projectKey = (_b = (_a = input.jira) === null || _a === void 0 ? void 0 : _a.projectKey) !== null && _b !== void 0 ? _b : config.projectKey;
77
+ if (!projectKey)
78
+ throw new errors_1.JiraIntegrationError("Missing Jira project key.", "not_configured");
79
+ const issueType = (_e = (_d = (_c = input.jira) === null || _c === void 0 ? void 0 : _c.issueType) !== null && _d !== void 0 ? _d : config.issueType) !== null && _e !== void 0 ? _e : {};
80
+ if (!issueType.name && !issueType.id)
81
+ throw new errors_1.JiraIntegrationError("Missing Jira issue type (name or id).", "not_configured");
82
+ const descriptionText = (_f = input.description) !== null && _f !== void 0 ? _f : "";
83
+ const adf = (0, adf_1.textToAdf)(descriptionText);
84
+ const proxyUrl = config.proxyUrl;
85
+ if (!proxyUrl)
86
+ throw new errors_1.JiraIntegrationError("Missing Jira proxyUrl.", "not_configured");
87
+ const res = await fetch(proxyUrl, {
88
+ method: "POST",
89
+ headers: { "content-type": "application/json" },
90
+ body: JSON.stringify({
91
+ provider: "jira",
92
+ input: {
93
+ title,
94
+ descriptionAdf: adf,
95
+ context: input.context,
96
+ screenshot: input.screenshot,
97
+ projectKey,
98
+ issueType,
99
+ },
100
+ }),
101
+ });
102
+ const data = await readJsonSafe(res);
103
+ if (!res.ok) {
104
+ const mapped = mapStatus(res.status);
105
+ throw new errors_1.JiraIntegrationError(mapped.message, mapped.code, { status: res.status, details: data });
106
+ }
107
+ const rec = isRecord(data) ? data : {};
108
+ return {
109
+ id: typeof rec.id === "string" ? rec.id : undefined,
110
+ key: typeof rec.key === "string" ? rec.key : undefined,
111
+ url: typeof rec.url === "string" ? rec.url : undefined,
112
+ };
113
+ }
@@ -0,0 +1,10 @@
1
+ export type JiraErrorCode = "not_configured" | "bad_request" | "unauthorized" | "forbidden" | "rate_limited" | "server_error" | "network_error" | "unknown";
2
+ export declare class JiraIntegrationError extends Error {
3
+ code: JiraErrorCode;
4
+ status?: number;
5
+ details?: unknown;
6
+ constructor(message: string, code: JiraErrorCode, options?: {
7
+ status?: number;
8
+ details?: unknown;
9
+ });
10
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JiraIntegrationError = void 0;
4
+ class JiraIntegrationError extends Error {
5
+ constructor(message, code, options) {
6
+ super(message);
7
+ this.name = "JiraIntegrationError";
8
+ this.code = code;
9
+ this.status = options === null || options === void 0 ? void 0 : options.status;
10
+ this.details = options === null || options === void 0 ? void 0 : options.details;
11
+ }
12
+ }
13
+ exports.JiraIntegrationError = JiraIntegrationError;
@@ -0,0 +1,2 @@
1
+ export { createJiraIssue, fetchJiraIssueTypes } from "./client";
2
+ export { JiraIntegrationError } from "./errors";
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JiraIntegrationError = exports.fetchJiraIssueTypes = exports.createJiraIssue = void 0;
4
+ var client_1 = require("./client");
5
+ Object.defineProperty(exports, "createJiraIssue", { enumerable: true, get: function () { return client_1.createJiraIssue; } });
6
+ Object.defineProperty(exports, "fetchJiraIssueTypes", { enumerable: true, get: function () { return client_1.fetchJiraIssueTypes; } });
7
+ var errors_1 = require("./errors");
8
+ Object.defineProperty(exports, "JiraIntegrationError", { enumerable: true, get: function () { return errors_1.JiraIntegrationError; } });
@@ -0,0 +1,54 @@
1
+ export type IntegrationId = "jira";
2
+ export type JiraIssueType = {
3
+ name?: string;
4
+ id?: string;
5
+ };
6
+ export type JiraIssueTypeOption = {
7
+ id: string;
8
+ name: string;
9
+ };
10
+ export type JiraIntegrationConfig = {
11
+ proxyUrl?: string;
12
+ projectKey?: string;
13
+ issueType?: JiraIssueType;
14
+ screenshot?: {
15
+ enabled?: boolean;
16
+ mode?: "displayMedia" | "none";
17
+ };
18
+ user?: {
19
+ id?: string;
20
+ email?: string;
21
+ name?: string;
22
+ };
23
+ };
24
+ export type IntegrationsConfig = {
25
+ jira?: JiraIntegrationConfig;
26
+ };
27
+ export type IntegrationContext = {
28
+ url?: string;
29
+ userAgent?: string;
30
+ timestamp?: string;
31
+ user?: {
32
+ id?: string;
33
+ email?: string;
34
+ name?: string;
35
+ };
36
+ };
37
+ export type CreateIssueInput = {
38
+ title: string;
39
+ description?: string;
40
+ context?: IntegrationContext;
41
+ screenshot?: {
42
+ dataUrl: string;
43
+ filename: string;
44
+ };
45
+ jira?: {
46
+ projectKey?: string;
47
+ issueType?: JiraIssueType;
48
+ };
49
+ };
50
+ export type CreateIssueResult = {
51
+ id?: string;
52
+ key?: string;
53
+ url?: string;
54
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -14,12 +14,12 @@ function safeToString(value) {
14
14
  return "[unstringifiable]";
15
15
  }
16
16
  }
17
- function truncateString(value, maxLen) {
17
+ function truncateStringMeta(value, maxLen) {
18
18
  if (maxLen <= 0)
19
- return "";
19
+ return { value: "", truncated: value.length > 0 };
20
20
  if (value.length <= maxLen)
21
- return value;
22
- return value.slice(0, maxLen);
21
+ return { value, truncated: false };
22
+ return { value: value.slice(0, maxLen), truncated: true };
23
23
  }
24
24
  function coerceUrl(input) {
25
25
  if (typeof input === "string")
@@ -52,7 +52,8 @@ function formatUrlForMessage(raw) {
52
52
  async function readResponseBody(response, maxLen) {
53
53
  try {
54
54
  const text = await response.text();
55
- return truncateString(text, maxLen);
55
+ const t = truncateStringMeta(text, maxLen);
56
+ return { body: t.value, truncated: t.truncated };
56
57
  }
57
58
  catch (_a) {
58
59
  return undefined;
@@ -79,30 +80,40 @@ function installNetworkLogger(options) {
79
80
  const originalXhrSend = canXhr ? g.XMLHttpRequest.prototype.send : undefined;
80
81
  if (canFetch) {
81
82
  g.fetch = (async (...args) => {
82
- var _a;
83
+ var _a, _b;
83
84
  const id = createId();
84
85
  let method;
85
86
  let url;
86
87
  let requestBody;
88
+ let requestBodyTruncated = false;
87
89
  try {
88
90
  const [input, init] = args;
89
91
  url = coerceUrl(input);
90
92
  const reqMethodFromInit = init === null || init === void 0 ? void 0 : init.method;
91
93
  const reqMethodFromInput = input && typeof input.method === "string" ? input.method : undefined;
92
94
  method = ((_a = reqMethodFromInit !== null && reqMethodFromInit !== void 0 ? reqMethodFromInit : reqMethodFromInput) !== null && _a !== void 0 ? _a : "GET").toUpperCase();
93
- if (includeBodies && init && "body" in init)
95
+ if (includeBodies && init && "body" in init) {
94
96
  requestBody = init.body;
97
+ if (typeof requestBody === "string") {
98
+ const t = truncateStringMeta(requestBody, maxBodyLength);
99
+ requestBody = t.value;
100
+ requestBodyTruncated = t.truncated;
101
+ }
102
+ }
95
103
  }
96
- catch (_b) {
104
+ catch (_c) {
97
105
  void 0;
98
106
  }
99
107
  try {
100
108
  const res = await Reflect.apply(originalFetch, globalThis, args);
101
109
  const status = res.status;
102
110
  let responseBody;
111
+ let responseBodyTruncated = false;
103
112
  if (includeBodies) {
104
113
  const cloned = res.clone();
105
- responseBody = await readResponseBody(cloned, maxBodyLength);
114
+ const r = await readResponseBody(cloned, maxBodyLength);
115
+ responseBody = r === null || r === void 0 ? void 0 : r.body;
116
+ responseBodyTruncated = (_b = r === null || r === void 0 ? void 0 : r.truncated) !== null && _b !== void 0 ? _b : false;
106
117
  }
107
118
  if (active) {
108
119
  const entry = {
@@ -113,7 +124,10 @@ function installNetworkLogger(options) {
113
124
  url,
114
125
  status,
115
126
  requestBody: includeBodies ? requestBody : undefined,
127
+ requestBodyTruncated: includeBodies ? requestBodyTruncated : undefined,
116
128
  responseBody: includeBodies ? responseBody : undefined,
129
+ responseBodyTruncated: includeBodies ? responseBodyTruncated : undefined,
130
+ bodyMaxLength: includeBodies ? maxBodyLength : undefined,
117
131
  message: makeMessage({ method, url, status }),
118
132
  };
119
133
  options.emit(entry);
@@ -130,7 +144,10 @@ function installNetworkLogger(options) {
130
144
  url,
131
145
  status: undefined,
132
146
  requestBody: includeBodies ? requestBody : undefined,
147
+ requestBodyTruncated: includeBodies ? requestBodyTruncated : undefined,
133
148
  responseBody: includeBodies ? safeToString(err) : undefined,
149
+ responseBodyTruncated: undefined,
150
+ bodyMaxLength: includeBodies ? maxBodyLength : undefined,
134
151
  message: makeMessage({ method, url, status: undefined }),
135
152
  };
136
153
  options.emit(entry);
@@ -156,9 +173,15 @@ function installNetworkLogger(options) {
156
173
  proto.send = function (...args) {
157
174
  var _a;
158
175
  const meta = (_a = xhrMeta.get(this)) !== null && _a !== void 0 ? _a : { id: createId() };
176
+ let requestBodyTruncated = false;
159
177
  if (includeBodies) {
160
178
  try {
161
179
  meta.requestBody = args[0];
180
+ if (typeof meta.requestBody === "string") {
181
+ const t = truncateStringMeta(meta.requestBody, maxBodyLength);
182
+ meta.requestBody = t.value;
183
+ requestBodyTruncated = t.truncated;
184
+ }
162
185
  }
163
186
  catch (_b) {
164
187
  void 0;
@@ -168,10 +191,14 @@ function installNetworkLogger(options) {
168
191
  const onLoadEnd = () => {
169
192
  const status = typeof this.status === "number" ? this.status : undefined;
170
193
  let responseBody;
194
+ let responseBodyTruncated = false;
171
195
  if (includeBodies) {
172
196
  try {
173
- if (typeof this.responseText === "string")
174
- responseBody = truncateString(this.responseText, maxBodyLength);
197
+ if (typeof this.responseText === "string") {
198
+ const t = truncateStringMeta(this.responseText, maxBodyLength);
199
+ responseBody = t.value;
200
+ responseBodyTruncated = t.truncated;
201
+ }
175
202
  else
176
203
  responseBody = undefined;
177
204
  }
@@ -188,7 +215,10 @@ function installNetworkLogger(options) {
188
215
  url: meta.url,
189
216
  status,
190
217
  requestBody: includeBodies ? meta.requestBody : undefined,
218
+ requestBodyTruncated: includeBodies ? requestBodyTruncated : undefined,
191
219
  responseBody: includeBodies ? responseBody : undefined,
220
+ responseBodyTruncated: includeBodies ? responseBodyTruncated : undefined,
221
+ bodyMaxLength: includeBodies ? maxBodyLength : undefined,
192
222
  message: makeMessage({ method: meta.method, url: meta.url, status }),
193
223
  };
194
224
  options.emit(entry);
@@ -0,0 +1,30 @@
1
+ export type LocalStorageItem = {
2
+ key: string;
3
+ value: string;
4
+ preview: string;
5
+ valueLength: number;
6
+ approxBytes: number;
7
+ };
8
+ export type LocalStorageSnapshot = {
9
+ items: LocalStorageItem[];
10
+ totalApproxBytes: number;
11
+ };
12
+ export type LocalStorageAccess = {
13
+ ok: true;
14
+ storage: Storage;
15
+ } | {
16
+ ok: false;
17
+ message: string;
18
+ };
19
+ export declare function getLocalStorageAccess(): LocalStorageAccess;
20
+ export declare function readLocalStorageSnapshot(storage: Storage, opts: {
21
+ maxPreviewLength: number;
22
+ }): LocalStorageSnapshot;
23
+ export declare function createLocalStorageWatcher(args: {
24
+ storage: Storage;
25
+ pollIntervalMs: number;
26
+ onChange: () => void;
27
+ }): {
28
+ destroy: () => void;
29
+ trigger: () => void;
30
+ };