@limekex/bugreport-widget-sdk 0.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 +47 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/types/widget.types.d.ts +21 -0
- package/dist/types/widget.types.d.ts.map +1 -0
- package/dist/types/widget.types.js +2 -0
- package/dist/types/widget.types.js.map +1 -0
- package/dist/utils/apiClient.d.ts +10 -0
- package/dist/utils/apiClient.d.ts.map +1 -0
- package/dist/utils/apiClient.js +19 -0
- package/dist/utils/apiClient.js.map +1 -0
- package/dist/utils/consoleCapture.d.ts +34 -0
- package/dist/utils/consoleCapture.d.ts.map +1 -0
- package/dist/utils/consoleCapture.js +82 -0
- package/dist/utils/consoleCapture.js.map +1 -0
- package/dist/utils/networkCapture.d.ts +44 -0
- package/dist/utils/networkCapture.d.ts.map +1 -0
- package/dist/utils/networkCapture.js +138 -0
- package/dist/utils/networkCapture.js.map +1 -0
- package/dist/utils/payloadBuilder.d.ts +15 -0
- package/dist/utils/payloadBuilder.d.ts.map +1 -0
- package/dist/utils/payloadBuilder.js +51 -0
- package/dist/utils/payloadBuilder.js.map +1 -0
- package/dist/utils/screenshotCapture.d.ts +21 -0
- package/dist/utils/screenshotCapture.d.ts.map +1 -0
- package/dist/utils/screenshotCapture.js +85 -0
- package/dist/utils/screenshotCapture.js.map +1 -0
- package/dist/widget/button.d.ts +11 -0
- package/dist/widget/button.d.ts.map +1 -0
- package/dist/widget/button.js +33 -0
- package/dist/widget/button.js.map +1 -0
- package/dist/widget/init.d.ts +28 -0
- package/dist/widget/init.d.ts.map +1 -0
- package/dist/widget/init.js +102 -0
- package/dist/widget/init.js.map +1 -0
- package/dist/widget/modal.d.ts +20 -0
- package/dist/widget/modal.d.ts.map +1 -0
- package/dist/widget/modal.js +493 -0
- package/dist/widget/modal.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full-page screenshot capture utility.
|
|
3
|
+
*
|
|
4
|
+
* Uses html2canvas when available to capture a client-side screenshot of the
|
|
5
|
+
* current page. html2canvas is loaded lazically from a CDN to keep the SDK
|
|
6
|
+
* bundle size small — it is only fetched when the user clicks "Capture screen".
|
|
7
|
+
*
|
|
8
|
+
* If html2canvas is not available (blocked by CSP, network error, etc.) the
|
|
9
|
+
* capture silently fails and the user can still attach a manual screenshot.
|
|
10
|
+
*
|
|
11
|
+
* @see https://html2canvas.hertzen.com/
|
|
12
|
+
*/
|
|
13
|
+
const CDN_URL = 'https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js';
|
|
14
|
+
/** Subresource Integrity hash for html2canvas 1.4.1 from jsdelivr */
|
|
15
|
+
const CDN_INTEGRITY = 'sha256-6IAfMRH9C/fLcuGGwCmMWi4svMLOHR0/5QL8IBLuVJo=';
|
|
16
|
+
let cachedHtml2Canvas = null;
|
|
17
|
+
/**
|
|
18
|
+
* Lazily loads html2canvas from CDN.
|
|
19
|
+
*
|
|
20
|
+
* Returns `null` if the library cannot be loaded (CSP, offline, etc.).
|
|
21
|
+
*/
|
|
22
|
+
async function loadHtml2Canvas() {
|
|
23
|
+
if (cachedHtml2Canvas)
|
|
24
|
+
return cachedHtml2Canvas;
|
|
25
|
+
// Guard: not in a browser environment
|
|
26
|
+
if (typeof window === 'undefined')
|
|
27
|
+
return null;
|
|
28
|
+
// Check if it's already on the page (e.g. consumer bundled it)
|
|
29
|
+
const win = window;
|
|
30
|
+
if (typeof win.html2canvas === 'function') {
|
|
31
|
+
cachedHtml2Canvas = win.html2canvas;
|
|
32
|
+
return cachedHtml2Canvas;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
await new Promise((resolve, reject) => {
|
|
36
|
+
const script = document.createElement('script');
|
|
37
|
+
script.src = CDN_URL;
|
|
38
|
+
script.integrity = CDN_INTEGRITY;
|
|
39
|
+
script.crossOrigin = 'anonymous';
|
|
40
|
+
script.async = true;
|
|
41
|
+
const timeout = setTimeout(() => {
|
|
42
|
+
script.remove();
|
|
43
|
+
reject(new Error('html2canvas load timed out'));
|
|
44
|
+
}, 3000);
|
|
45
|
+
script.onload = () => { clearTimeout(timeout); resolve(); };
|
|
46
|
+
script.onerror = () => { clearTimeout(timeout); reject(new Error('Failed to load html2canvas')); };
|
|
47
|
+
document.head.appendChild(script);
|
|
48
|
+
});
|
|
49
|
+
if (typeof win.html2canvas === 'function') {
|
|
50
|
+
cachedHtml2Canvas = win.html2canvas;
|
|
51
|
+
return cachedHtml2Canvas;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Silently fail — user can still attach a file manually
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Captures a screenshot of the current page as a data URL.
|
|
61
|
+
*
|
|
62
|
+
* Returns `null` if html2canvas is unavailable or the capture fails.
|
|
63
|
+
*
|
|
64
|
+
* The overlay element (if any) is hidden during capture and restored after.
|
|
65
|
+
*/
|
|
66
|
+
export async function capturePageScreenshot() {
|
|
67
|
+
if (typeof window === 'undefined' || typeof document === 'undefined')
|
|
68
|
+
return null;
|
|
69
|
+
const html2canvas = await loadHtml2Canvas();
|
|
70
|
+
if (!html2canvas)
|
|
71
|
+
return null;
|
|
72
|
+
const canvas = await html2canvas(document.body, {
|
|
73
|
+
scale: Math.min(window.devicePixelRatio, 2),
|
|
74
|
+
useCORS: true,
|
|
75
|
+
logging: false,
|
|
76
|
+
windowWidth: document.documentElement.scrollWidth,
|
|
77
|
+
windowHeight: document.documentElement.scrollHeight,
|
|
78
|
+
ignoreElements: (el) => {
|
|
79
|
+
// Ignore the bug reporter's own overlay so it doesn't appear in the screenshot
|
|
80
|
+
return el.id === '__bugreport_overlay__' || el.id === '__bugreport_styles__';
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
return canvas.toDataURL('image/png');
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=screenshotCapture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screenshotCapture.js","sourceRoot":"","sources":["../../src/utils/screenshotCapture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { WidgetInstance } from '../types/widget.types';
|
|
2
|
+
import type { WidgetTheme } from '@bugreport/shared-types';
|
|
3
|
+
/**
|
|
4
|
+
* Injects a minimal floating trigger button into the DOM.
|
|
5
|
+
*
|
|
6
|
+
* TODO: Replace with a polished design or a React-rendered component.
|
|
7
|
+
* For now this is a plain DOM element so the SDK works without React.
|
|
8
|
+
*/
|
|
9
|
+
export declare function injectFloatingButton(instance: WidgetInstance, theme?: WidgetTheme): void;
|
|
10
|
+
export declare function removeFloatingButton(): void;
|
|
11
|
+
//# sourceMappingURL=button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../src/widget/button.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAI3D;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CA4BxF;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const BUTTON_ID = '__bugreport_floating_btn__';
|
|
2
|
+
/**
|
|
3
|
+
* Injects a minimal floating trigger button into the DOM.
|
|
4
|
+
*
|
|
5
|
+
* TODO: Replace with a polished design or a React-rendered component.
|
|
6
|
+
* For now this is a plain DOM element so the SDK works without React.
|
|
7
|
+
*/
|
|
8
|
+
export function injectFloatingButton(instance, theme) {
|
|
9
|
+
if (document.getElementById(BUTTON_ID))
|
|
10
|
+
return;
|
|
11
|
+
const position = theme?.buttonPosition ?? 'bottom-right';
|
|
12
|
+
const primaryColor = theme?.primaryColor ?? '#e11d48';
|
|
13
|
+
const zIndex = theme?.zIndex ?? 9999;
|
|
14
|
+
const positionStyles = {
|
|
15
|
+
'bottom-right': 'bottom:24px;right:24px;',
|
|
16
|
+
'bottom-left': 'bottom:24px;left:24px;',
|
|
17
|
+
'top-right': 'top:24px;right:24px;',
|
|
18
|
+
'top-left': 'top:24px;left:24px;',
|
|
19
|
+
};
|
|
20
|
+
const button = document.createElement('button');
|
|
21
|
+
button.id = BUTTON_ID;
|
|
22
|
+
button.textContent = '🐛 Report bug';
|
|
23
|
+
button.setAttribute('style', `position:fixed;${positionStyles[position]}z-index:${zIndex};` +
|
|
24
|
+
`background:${primaryColor};color:#fff;border:none;border-radius:24px;` +
|
|
25
|
+
`padding:10px 18px;font-size:14px;font-weight:600;cursor:pointer;` +
|
|
26
|
+
`box-shadow:0 4px 12px rgba(0,0,0,0.2);transition:opacity 0.2s;`);
|
|
27
|
+
button.addEventListener('click', () => instance.open());
|
|
28
|
+
document.body.appendChild(button);
|
|
29
|
+
}
|
|
30
|
+
export function removeFloatingButton() {
|
|
31
|
+
document.getElementById(BUTTON_ID)?.remove();
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.js","sourceRoot":"","sources":["../../src/widget/button.ts"],"names":[],"mappings":"AAGA,MAAM,SAAS,GAAG,4BAA4B,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAwB,EAAE,KAAmB;IAChF,IAAI,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC;QAAE,OAAO;IAE/C,MAAM,QAAQ,GAAG,KAAK,EAAE,cAAc,IAAI,cAAc,CAAC;IACzD,MAAM,YAAY,GAAG,KAAK,EAAE,YAAY,IAAI,SAAS,CAAC;IACtD,MAAM,MAAM,GAAG,KAAK,EAAE,MAAM,IAAI,IAAI,CAAC;IAErC,MAAM,cAAc,GAA2B;QAC7C,cAAc,EAAE,yBAAyB;QACzC,aAAa,EAAE,wBAAwB;QACvC,WAAW,EAAE,sBAAsB;QACnC,UAAU,EAAE,qBAAqB;KAClC,CAAC;IAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,CAAC,EAAE,GAAG,SAAS,CAAC;IACtB,MAAM,CAAC,WAAW,GAAG,eAAe,CAAC;IACrC,MAAM,CAAC,YAAY,CACjB,OAAO,EACP,kBAAkB,cAAc,CAAC,QAAQ,CAAC,WAAW,MAAM,GAAG;QAC5D,cAAc,YAAY,6CAA6C;QACvE,kEAAkE;QAClE,gEAAgE,CACnE,CAAC;IAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAExD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { BugReporterConfig } from '@bugreport/shared-types';
|
|
2
|
+
import type { WidgetInstance } from '../types/widget.types';
|
|
3
|
+
/**
|
|
4
|
+
* Initialises the bug reporter widget.
|
|
5
|
+
*
|
|
6
|
+
* Call this once in your stage app's entry point (e.g. main.tsx or _app.tsx).
|
|
7
|
+
*
|
|
8
|
+
* Stage-only guardrails — the widget renders only when ALL of the following are true:
|
|
9
|
+
* - `enabled` is not explicitly `false`
|
|
10
|
+
* - `environment` is `"stage"` or `"staging"` (or `enabled` is explicitly `true`)
|
|
11
|
+
* - `apiBaseUrl` is provided
|
|
12
|
+
* - running in a browser context
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { initBugReporter } from '@bugreport/widget-sdk';
|
|
17
|
+
*
|
|
18
|
+
* initBugReporter({
|
|
19
|
+
* apiBaseUrl: 'https://bugreport.betait.no',
|
|
20
|
+
* environment: 'staging',
|
|
21
|
+
* enabled: true,
|
|
22
|
+
* appVersion: '1.2.3',
|
|
23
|
+
* commitSha: process.env.VITE_COMMIT_SHA,
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function initBugReporter(config: BugReporterConfig): WidgetInstance;
|
|
28
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/widget/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAwC,MAAM,uBAAuB,CAAC;AAMlG;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,cAAc,CAiDzE"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { injectFloatingButton, removeFloatingButton } from './button';
|
|
2
|
+
import { openModal, closeModal } from './modal';
|
|
3
|
+
import { installConsoleErrorHook } from '../utils/consoleCapture';
|
|
4
|
+
import { installNetworkCaptureHook } from '../utils/networkCapture';
|
|
5
|
+
/**
|
|
6
|
+
* Initialises the bug reporter widget.
|
|
7
|
+
*
|
|
8
|
+
* Call this once in your stage app's entry point (e.g. main.tsx or _app.tsx).
|
|
9
|
+
*
|
|
10
|
+
* Stage-only guardrails — the widget renders only when ALL of the following are true:
|
|
11
|
+
* - `enabled` is not explicitly `false`
|
|
12
|
+
* - `environment` is `"stage"` or `"staging"` (or `enabled` is explicitly `true`)
|
|
13
|
+
* - `apiBaseUrl` is provided
|
|
14
|
+
* - running in a browser context
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { initBugReporter } from '@bugreport/widget-sdk';
|
|
19
|
+
*
|
|
20
|
+
* initBugReporter({
|
|
21
|
+
* apiBaseUrl: 'https://bugreport.betait.no',
|
|
22
|
+
* environment: 'staging',
|
|
23
|
+
* enabled: true,
|
|
24
|
+
* appVersion: '1.2.3',
|
|
25
|
+
* commitSha: process.env.VITE_COMMIT_SHA,
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function initBugReporter(config) {
|
|
30
|
+
const listeners = {};
|
|
31
|
+
const emit = (type, payload) => {
|
|
32
|
+
listeners[type]?.forEach((fn) => fn({ type, payload }));
|
|
33
|
+
};
|
|
34
|
+
const instance = {
|
|
35
|
+
config,
|
|
36
|
+
state: 'idle',
|
|
37
|
+
open: () => {
|
|
38
|
+
if (instance.state === 'open')
|
|
39
|
+
return;
|
|
40
|
+
instance.state = 'open';
|
|
41
|
+
emit('open');
|
|
42
|
+
openModal(config, {
|
|
43
|
+
onClose: () => {
|
|
44
|
+
instance.state = 'idle';
|
|
45
|
+
emit('close');
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
close: () => {
|
|
50
|
+
if (instance.state === 'idle')
|
|
51
|
+
return;
|
|
52
|
+
closeModal();
|
|
53
|
+
instance.state = 'idle';
|
|
54
|
+
emit('close');
|
|
55
|
+
},
|
|
56
|
+
on: (type, listener) => {
|
|
57
|
+
if (!listeners[type])
|
|
58
|
+
listeners[type] = [];
|
|
59
|
+
listeners[type].push(listener);
|
|
60
|
+
},
|
|
61
|
+
destroy: () => {
|
|
62
|
+
closeModal();
|
|
63
|
+
removeFloatingButton();
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
const shouldRender = shouldShowWidget(config);
|
|
67
|
+
if (shouldRender) {
|
|
68
|
+
// Install the console.error hook so recent errors are available when the
|
|
69
|
+
// tester opens the modal.
|
|
70
|
+
installConsoleErrorHook();
|
|
71
|
+
// Install the network capture hook to record failed fetch/XHR requests.
|
|
72
|
+
installNetworkCaptureHook();
|
|
73
|
+
injectFloatingButton(instance, config.theme);
|
|
74
|
+
}
|
|
75
|
+
return instance;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Determines whether the widget should be injected into the page.
|
|
79
|
+
*
|
|
80
|
+
* Rules:
|
|
81
|
+
* 1. If `enabled` is explicitly `false` → never render.
|
|
82
|
+
* 2. If not in a browser context → never render.
|
|
83
|
+
* 3. If `apiBaseUrl` is missing → never render (would fail anyway).
|
|
84
|
+
* 4. If `enabled` is explicitly `true` → always render (consumer opts in).
|
|
85
|
+
* 5. Otherwise render only when environment exactly matches an allowed stage value.
|
|
86
|
+
*/
|
|
87
|
+
function shouldShowWidget(config) {
|
|
88
|
+
if (config.enabled === false)
|
|
89
|
+
return false;
|
|
90
|
+
if (typeof document === 'undefined')
|
|
91
|
+
return false;
|
|
92
|
+
if (!config.apiBaseUrl)
|
|
93
|
+
return false;
|
|
94
|
+
if (config.enabled === true)
|
|
95
|
+
return true;
|
|
96
|
+
// Exact-match against known staging environment names to avoid false positives
|
|
97
|
+
// (e.g. "backstage", "prestage", "stage-production").
|
|
98
|
+
const STAGE_ENVS = new Set(['stage', 'staging', 'uat', 'test']);
|
|
99
|
+
const env = config.environment?.toLowerCase() ?? '';
|
|
100
|
+
return STAGE_ENVS.has(env);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/widget/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BugReporterConfig } from '@bugreport/shared-types';
|
|
2
|
+
export interface ModalCallbacks {
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Opens the bug report modal and wires up form submission.
|
|
7
|
+
*
|
|
8
|
+
* The modal is a plain DOM element with production-ready CSS injected into the
|
|
9
|
+
* page. No React or CSS framework required — works in any web app.
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - Focus trap (Tab/Shift-Tab cycle within modal)
|
|
13
|
+
* - Animated overlay + slide-up entrance
|
|
14
|
+
* - Responsive layout (stacks on mobile)
|
|
15
|
+
* - "Capture current screen" button (html2canvas when available)
|
|
16
|
+
* - Accessible: aria roles, keyboard dismiss, label associations
|
|
17
|
+
*/
|
|
18
|
+
export declare function openModal(config: BugReporterConfig, callbacks: ModalCallbacks): void;
|
|
19
|
+
export declare function closeModal(callbacks?: ModalCallbacks): void;
|
|
20
|
+
//# sourceMappingURL=modal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modal.d.ts","sourceRoot":"","sources":["../../src/widget/modal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAUjE,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAsND;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,iBAAiB,EAAE,SAAS,EAAE,cAAc,GAAG,IAAI,CA+CpF;AAED,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI,CAU3D"}
|