@lightworkai.official/debug-capture 0.6.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 +241 -0
- package/dist/budget.d.ts +22 -0
- package/dist/bundle.d.ts +20 -0
- package/dist/capture/actionTrail.d.ts +7 -0
- package/dist/capture/cause.d.ts +3 -0
- package/dist/capture/consoleBuffer.d.ts +4 -0
- package/dist/capture/crashWatcher.d.ts +1 -0
- package/dist/capture/networkBuffer.d.ts +4 -0
- package/dist/capture/redact.d.ts +9 -0
- package/dist/capture/stepCorrelation.d.ts +41 -0
- package/dist/config.d.ts +217 -0
- package/dist/context.d.ts +2 -0
- package/dist/debug-capture.js +116 -0
- package/dist/embed.d.ts +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.mjs +129 -0
- package/dist/install.d.ts +5 -0
- package/dist/mytickets/api.d.ts +115 -0
- package/dist/mytickets/format.d.ts +84 -0
- package/dist/mytickets/sanitize.d.ts +66 -0
- package/dist/mytickets/strings.d.ts +74 -0
- package/dist/mytickets/toolbar.d.ts +17 -0
- package/dist/reporter.d.ts +27 -0
- package/dist/screenshot.d.ts +7 -0
- package/dist/signature.d.ts +18 -0
- package/dist/submit.d.ts +8 -0
- package/dist/types.d.ts +175 -0
- package/dist/ui/annotator.d.ts +34 -0
- package/dist/ui/arrow.d.ts +25 -0
- package/dist/ui/element.d.ts +9 -0
- package/dist/ui/strings.d.ts +42 -0
- package/dist/ui/styles.d.ts +13 -0
- package/dist/ui/toast.d.ts +11 -0
- package/package.json +53 -0
- package/src/budget.ts +62 -0
- package/src/bundle.ts +274 -0
- package/src/capture/actionTrail.ts +693 -0
- package/src/capture/cause.ts +49 -0
- package/src/capture/consoleBuffer.ts +80 -0
- package/src/capture/crashWatcher.ts +61 -0
- package/src/capture/networkBuffer.ts +315 -0
- package/src/capture/redact.ts +117 -0
- package/src/capture/stepCorrelation.ts +160 -0
- package/src/config.ts +299 -0
- package/src/context.ts +81 -0
- package/src/embed.ts +35 -0
- package/src/index.ts +109 -0
- package/src/install.ts +59 -0
- package/src/mytickets/api.ts +226 -0
- package/src/mytickets/format.ts +191 -0
- package/src/mytickets/sanitize.ts +221 -0
- package/src/mytickets/strings.ts +217 -0
- package/src/mytickets/toolbar.ts +48 -0
- package/src/reporter.ts +53 -0
- package/src/screenshot.ts +238 -0
- package/src/signature.ts +40 -0
- package/src/styles.css +400 -0
- package/src/submit.ts +143 -0
- package/src/types.ts +169 -0
- package/src/ui/annotator.ts +698 -0
- package/src/ui/arrow.ts +62 -0
- package/src/ui/element.ts +362 -0
- package/src/ui/strings.ts +113 -0
- package/src/ui/styles.ts +96 -0
- package/src/ui/toast.ts +138 -0
package/src/ui/toast.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A toast the library owns.
|
|
3
|
+
*
|
|
4
|
+
* The reporter closes on success, so anything it says in its own footer goes
|
|
5
|
+
* with it — a ticket was filed and the screen showed nothing. The original
|
|
6
|
+
* hands this to `sonner`; we cannot, because a host app may use sonner, or
|
|
7
|
+
* react-toastify, or nothing at all, and a package that picks one imposes it on
|
|
8
|
+
* everybody.
|
|
9
|
+
*
|
|
10
|
+
* So: our own, in its own shadow root, with its own styles. Same reasoning as
|
|
11
|
+
* the dialog — it drops into pages we do not control, and neither side's CSS
|
|
12
|
+
* should reach the other.
|
|
13
|
+
*
|
|
14
|
+
* A host that already has a toast system suppresses this by calling
|
|
15
|
+
* `preventDefault()` on the `lw-report-submitted` event and showing its own.
|
|
16
|
+
*/
|
|
17
|
+
const HOST_TAG = "lw-debug-toasts";
|
|
18
|
+
const VISIBLE_MS = 6000;
|
|
19
|
+
|
|
20
|
+
const CSS = `
|
|
21
|
+
:host { all: initial; }
|
|
22
|
+
.stack {
|
|
23
|
+
position: fixed; top: 16px; right: 16px; z-index: 2147483001;
|
|
24
|
+
display: flex; flex-direction: column; gap: 8px; pointer-events: none;
|
|
25
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans Thai", sans-serif;
|
|
26
|
+
}
|
|
27
|
+
.toast {
|
|
28
|
+
pointer-events: auto; display: flex; align-items: center; gap: 8px;
|
|
29
|
+
max-width: 380px; padding: 12px 14px; border-radius: 10px;
|
|
30
|
+
font-size: 14px; line-height: 1.5; color: #0f172a;
|
|
31
|
+
background: #fff; border: 1px solid #e2e8f0;
|
|
32
|
+
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.16);
|
|
33
|
+
animation: in 160ms ease-out;
|
|
34
|
+
}
|
|
35
|
+
.toast[data-tone="success"] { border-left: 3px solid #10b981; }
|
|
36
|
+
.toast[data-tone="error"] { border-left: 3px solid #e11d48; }
|
|
37
|
+
.dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
|
|
38
|
+
.toast[data-tone="success"] .dot { background: #10b981; }
|
|
39
|
+
.toast[data-tone="error"] .dot { background: #e11d48; }
|
|
40
|
+
.action {
|
|
41
|
+
flex: none; cursor: pointer; padding: 5px 10px; margin-left: auto;
|
|
42
|
+
font: inherit; font-size: 13px; font-weight: 600;
|
|
43
|
+
color: #fff; background: #0f172a; border: none; border-radius: 7px;
|
|
44
|
+
}
|
|
45
|
+
.action + .close { margin-left: 4px; }
|
|
46
|
+
.close {
|
|
47
|
+
margin-left: auto; flex: none; cursor: pointer; border: none; background: none;
|
|
48
|
+
padding: 0 2px; font: inherit; font-size: 16px; line-height: 1; color: #94a3b8;
|
|
49
|
+
}
|
|
50
|
+
@keyframes in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
|
|
51
|
+
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
let stack: HTMLElement | null = null;
|
|
55
|
+
|
|
56
|
+
function ensureStack(): HTMLElement | null {
|
|
57
|
+
if (typeof document === "undefined") return null;
|
|
58
|
+
if (stack?.isConnected) return stack;
|
|
59
|
+
|
|
60
|
+
const host = document.createElement(HOST_TAG);
|
|
61
|
+
// Excluded from the DOM screenshot fallback, like the dialog — a report
|
|
62
|
+
// should not photograph the confirmation of the previous report.
|
|
63
|
+
host.dataset.debugReporter = "true";
|
|
64
|
+
const root = host.attachShadow({ mode: "open" });
|
|
65
|
+
const style = document.createElement("style");
|
|
66
|
+
style.textContent = CSS;
|
|
67
|
+
const el = document.createElement("div");
|
|
68
|
+
el.className = "stack";
|
|
69
|
+
el.setAttribute("role", "status");
|
|
70
|
+
// Polite, not assertive: this announces a success, and interrupting a screen
|
|
71
|
+
// reader mid-sentence to do that is rude.
|
|
72
|
+
el.setAttribute("aria-live", "polite");
|
|
73
|
+
root.append(style, el);
|
|
74
|
+
document.body.append(host);
|
|
75
|
+
stack = el;
|
|
76
|
+
return el;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ToastAction {
|
|
80
|
+
label: string;
|
|
81
|
+
/**
|
|
82
|
+
* Runs inside the click, so it can open screen capture. That is the whole
|
|
83
|
+
* point of offering a crash as a toast with a button rather than opening the
|
|
84
|
+
* reporter on its own: a browser grants capture to a real click and nothing
|
|
85
|
+
* else.
|
|
86
|
+
*/
|
|
87
|
+
onClick: () => void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function showToast(
|
|
91
|
+
message: string,
|
|
92
|
+
tone: "success" | "error" = "success",
|
|
93
|
+
action?: ToastAction,
|
|
94
|
+
): void {
|
|
95
|
+
const parent = ensureStack();
|
|
96
|
+
if (!parent) return;
|
|
97
|
+
|
|
98
|
+
const toast = document.createElement("div");
|
|
99
|
+
toast.className = "toast";
|
|
100
|
+
toast.dataset.tone = tone;
|
|
101
|
+
|
|
102
|
+
const dot = document.createElement("span");
|
|
103
|
+
dot.className = "dot";
|
|
104
|
+
const text = document.createElement("span");
|
|
105
|
+
// textContent: the message can carry a server's error string.
|
|
106
|
+
text.textContent = message;
|
|
107
|
+
|
|
108
|
+
const close = document.createElement("button");
|
|
109
|
+
close.type = "button";
|
|
110
|
+
close.className = "close";
|
|
111
|
+
close.textContent = "✕";
|
|
112
|
+
close.setAttribute("aria-label", "ปิด");
|
|
113
|
+
|
|
114
|
+
const dismiss = () => {
|
|
115
|
+
window.clearTimeout(timer);
|
|
116
|
+
toast.remove();
|
|
117
|
+
};
|
|
118
|
+
close.addEventListener("click", dismiss);
|
|
119
|
+
// An error stays until it is read, and so does anything with an action —
|
|
120
|
+
// a crash invitation that vanishes before it is noticed is a report nobody
|
|
121
|
+
// ever files.
|
|
122
|
+
const timer = tone === "error" || action ? 0 : window.setTimeout(dismiss, VISIBLE_MS);
|
|
123
|
+
|
|
124
|
+
toast.append(dot, text);
|
|
125
|
+
if (action) {
|
|
126
|
+
const button = document.createElement("button");
|
|
127
|
+
button.type = "button";
|
|
128
|
+
button.className = "action";
|
|
129
|
+
button.textContent = action.label;
|
|
130
|
+
button.addEventListener("click", () => {
|
|
131
|
+
dismiss();
|
|
132
|
+
action.onClick();
|
|
133
|
+
});
|
|
134
|
+
toast.append(button);
|
|
135
|
+
}
|
|
136
|
+
toast.append(close);
|
|
137
|
+
parent.append(toast);
|
|
138
|
+
}
|