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.
- package/README.md +22 -1
- package/lib/init.d.ts +5 -2
- package/lib/init.js +5 -2
- package/lib/integrations/index.d.ts +2 -0
- package/lib/integrations/index.js +7 -0
- package/lib/integrations/jira/adf.d.ts +11 -0
- package/lib/integrations/jira/adf.js +17 -0
- package/lib/integrations/jira/client.d.ts +4 -0
- package/lib/integrations/jira/client.js +113 -0
- package/lib/integrations/jira/errors.d.ts +10 -0
- package/lib/integrations/jira/errors.js +13 -0
- package/lib/integrations/jira/index.d.ts +2 -0
- package/lib/integrations/jira/index.js +8 -0
- package/lib/integrations/types.d.ts +54 -0
- package/lib/integrations/types.js +2 -0
- package/lib/logger/networkLogger.js +41 -11
- package/lib/storage/localStorage.d.ts +30 -0
- package/lib/storage/localStorage.js +166 -0
- package/lib/ui/logList/createLogList.d.ts +2 -0
- package/lib/ui/logList/createLogList.js +67 -0
- package/lib/ui/logList/index.d.ts +2 -0
- package/lib/ui/logList/index.js +5 -0
- package/lib/ui/logList/networkDetails/copy.d.ts +2 -0
- package/lib/ui/logList/networkDetails/copy.js +101 -0
- package/lib/ui/logList/{networkDetails.d.ts → networkDetails/createNetworkDetails.d.ts} +1 -1
- package/lib/ui/logList/networkDetails/createNetworkDetails.js +61 -0
- package/lib/ui/logList/networkDetails/index.d.ts +1 -0
- package/lib/ui/logList/networkDetails/index.js +5 -0
- package/lib/ui/logList/networkDetails/renderValue.d.ts +2 -0
- package/lib/ui/logList/{networkDetails.js → networkDetails/renderValue.js} +32 -32
- package/lib/ui/logList/shared/consoleInspect.d.ts +1 -0
- package/lib/ui/logList/shared/consoleInspect.js +17 -0
- package/lib/ui/logList/shared/index.d.ts +3 -0
- package/lib/ui/logList/shared/index.js +11 -0
- package/lib/ui/logList/shared/time.d.ts +1 -0
- package/lib/ui/logList/shared/time.js +10 -0
- package/lib/ui/logList/shared/tone.d.ts +6 -0
- package/lib/ui/logList/shared/tone.js +36 -0
- package/lib/ui/logList/types.d.ts +6 -0
- package/lib/ui/logList/types.js +2 -0
- 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/integrations/icons.d.ts +1 -0
- package/lib/ui/panel/integrations/icons.js +7 -0
- package/lib/ui/panel/integrations/index.d.ts +1 -0
- package/lib/ui/panel/integrations/index.js +5 -0
- package/lib/ui/panel/integrations/jiraDialog.d.ts +6 -0
- package/lib/ui/panel/integrations/jiraDialog.js +234 -0
- package/lib/ui/panel/integrations/screenshot.d.ts +4 -0
- package/lib/ui/panel/integrations/screenshot.js +51 -0
- package/lib/ui/panel/localStorage/createLocalStorageView.d.ts +4 -0
- package/lib/ui/panel/localStorage/createLocalStorageView.js +108 -0
- package/lib/ui/panel/localStorage/index.d.ts +3 -0
- package/lib/ui/panel/localStorage/index.js +7 -0
- package/lib/ui/panel/localStorage/setupLocalStorageSync.d.ts +9 -0
- package/lib/ui/panel/localStorage/setupLocalStorageSync.js +30 -0
- package/lib/ui/panel/localStorage/types.d.ts +6 -0
- package/lib/ui/panel/localStorage/types.js +2 -0
- 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 +557 -116
- package/lib/ui/shared/copy.d.ts +2 -0
- package/lib/ui/shared/copy.js +101 -0
- package/lib/utils/types.d.ts +3 -0
- 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: {
|
|
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
|
|
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 (
|
|
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,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,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,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
|
+
};
|
|
@@ -14,12 +14,12 @@ function safeToString(value) {
|
|
|
14
14
|
return "[unstringifiable]";
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
function
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
};
|