@bworlds/launchkit 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 +172 -0
- package/dist/events.d.ts +57 -0
- package/dist/index.d.ts +61 -0
- package/dist/launchkit.cjs +441 -0
- package/dist/launchkit.cjs.map +1 -0
- package/dist/launchkit.js +9977 -0
- package/dist/launchkit.js.map +1 -0
- package/dist/launchkit.umd.js +441 -0
- package/dist/launchkit.umd.js.map +1 -0
- package/dist/privacy.d.ts +41 -0
- package/dist/recorder.d.ts +72 -0
- package/dist/screenshot.d.ts +40 -0
- package/dist/types.d.ts +97 -0
- package/dist/ui/InviteDialog.d.ts +41 -0
- package/dist/ui/Toolbar.d.ts +64 -0
- package/dist/ui/injectStyles.d.ts +6 -0
- package/dist/uploader.d.ts +36 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# @bworlds/launchkit
|
|
2
|
+
|
|
3
|
+
Launch kit for builders - demo recording, feedback tools, and more for BWorlds.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Session Recording** - Captures user interactions using rrweb
|
|
8
|
+
- **Automatic Screenshots** - Takes snapshots on page load, navigation, form submit, modal open, and scroll
|
|
9
|
+
- **Privacy-First** - Automatically masks passwords and credit card inputs
|
|
10
|
+
- **Lightweight UI** - Minimal toolbar (~3KB) with start/pause/stop controls
|
|
11
|
+
- **Auto-Stop** - Recordings automatically stop after 15 minutes
|
|
12
|
+
- **Zero Config** - Just add the URL parameter to start recording
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @bworlds/launchkit
|
|
18
|
+
# or
|
|
19
|
+
pnpm add @bworlds/launchkit
|
|
20
|
+
# or
|
|
21
|
+
yarn add @bworlds/launchkit
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Auto-Activation (Recommended)
|
|
27
|
+
|
|
28
|
+
Import the package anywhere in your app - it auto-activates when the URL contains `?_bw_record=<api_key>`:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// In your app entry point or layout
|
|
32
|
+
import '@bworlds/launchkit';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then visit your app with the recording parameter:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
https://yourapp.com?_bw_record=your_api_key
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
A toolbar will appear in the bottom-right corner.
|
|
42
|
+
|
|
43
|
+
### Manual Control
|
|
44
|
+
|
|
45
|
+
For programmatic control over recording:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { DemoRecorder } from '@bworlds/launchkit';
|
|
49
|
+
|
|
50
|
+
const recorder = new DemoRecorder({
|
|
51
|
+
apiKey: 'your_api_key',
|
|
52
|
+
maxDuration: 10 * 60 * 1000, // 10 minutes (default: 15)
|
|
53
|
+
maskInputs: true, // default: true
|
|
54
|
+
toolbar: {
|
|
55
|
+
position: 'bottom-right', // or 'bottom-left', 'top-right', 'top-left'
|
|
56
|
+
enabled: true,
|
|
57
|
+
},
|
|
58
|
+
onComplete: (result) => {
|
|
59
|
+
console.log('Recording URL:', result.playbackUrl);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Initialize toolbar
|
|
64
|
+
recorder.init();
|
|
65
|
+
|
|
66
|
+
// Control recording programmatically
|
|
67
|
+
await recorder.start();
|
|
68
|
+
recorder.pause();
|
|
69
|
+
recorder.resume();
|
|
70
|
+
await recorder.stop();
|
|
71
|
+
|
|
72
|
+
// Take manual screenshot
|
|
73
|
+
await recorder.screenshot();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Script Tag (CDN)
|
|
77
|
+
|
|
78
|
+
For non-bundled applications:
|
|
79
|
+
|
|
80
|
+
```html
|
|
81
|
+
<script src="https://cdn.bworlds.com/recorder.umd.js"></script>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then visit with `?_bw_record=your_api_key` to activate.
|
|
85
|
+
|
|
86
|
+
## Next.js / React Setup
|
|
87
|
+
|
|
88
|
+
Create a client component:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
// components/DemoRecorder.tsx
|
|
92
|
+
'use client';
|
|
93
|
+
|
|
94
|
+
import { useEffect } from 'react';
|
|
95
|
+
|
|
96
|
+
export function DemoRecorder() {
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
import('@bworlds/launchkit');
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Add to your layout:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// app/layout.tsx
|
|
109
|
+
import { DemoRecorder } from '@/components/DemoRecorder';
|
|
110
|
+
|
|
111
|
+
export default function RootLayout({ children }) {
|
|
112
|
+
return (
|
|
113
|
+
<html>
|
|
114
|
+
<body>
|
|
115
|
+
<DemoRecorder />
|
|
116
|
+
{children}
|
|
117
|
+
</body>
|
|
118
|
+
</html>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Configuration
|
|
124
|
+
|
|
125
|
+
| Option | Type | Default | Description |
|
|
126
|
+
|--------|------|---------|-------------|
|
|
127
|
+
| `apiKey` | `string` | required | Your BWorlds API key |
|
|
128
|
+
| `apiEndpoint` | `string` | `https://api.bworlds.com` | API endpoint URL |
|
|
129
|
+
| `maxDuration` | `number` | `900000` (15 min) | Max recording duration in ms |
|
|
130
|
+
| `maskInputs` | `boolean` | `true` | Mask sensitive inputs |
|
|
131
|
+
| `toolbar.position` | `string` | `bottom-right` | Toolbar position |
|
|
132
|
+
| `toolbar.enabled` | `boolean` | `true` | Show/hide toolbar |
|
|
133
|
+
| `onComplete` | `function` | - | Called when recording finishes |
|
|
134
|
+
| `onStateChange` | `function` | - | Called on state changes |
|
|
135
|
+
| `onError` | `function` | - | Called on errors |
|
|
136
|
+
|
|
137
|
+
## Automatic Screenshots
|
|
138
|
+
|
|
139
|
+
Screenshots are captured automatically on:
|
|
140
|
+
|
|
141
|
+
- **Page Load** - After initial render
|
|
142
|
+
- **Navigation** - On route changes (SPA or browser)
|
|
143
|
+
- **Form Submit** - Before form submission
|
|
144
|
+
- **Modal Open** - When dialogs/modals appear
|
|
145
|
+
- **Scroll** - After scrolling >50% of viewport
|
|
146
|
+
|
|
147
|
+
You can also take manual screenshots via the camera button or `recorder.screenshot()`.
|
|
148
|
+
|
|
149
|
+
## Privacy
|
|
150
|
+
|
|
151
|
+
The SDK automatically masks:
|
|
152
|
+
|
|
153
|
+
- Password inputs (`type="password"`)
|
|
154
|
+
- Credit card fields (`autocomplete="cc-*"`)
|
|
155
|
+
- Fields with `data-private` or `data-sensitive` attributes
|
|
156
|
+
|
|
157
|
+
To exclude an element from recording entirely:
|
|
158
|
+
|
|
159
|
+
```html
|
|
160
|
+
<div data-recorder-block>This won't be recorded</div>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Browser Support
|
|
164
|
+
|
|
165
|
+
- Chrome 80+
|
|
166
|
+
- Firefox 75+
|
|
167
|
+
- Safari 13+
|
|
168
|
+
- Edge 80+
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { eventWithTime } from 'rrweb';
|
|
2
|
+
import type { ScreenshotCapture } from './screenshot';
|
|
3
|
+
/**
|
|
4
|
+
* Event detection for automatic screenshots
|
|
5
|
+
*/
|
|
6
|
+
export declare class EventDetector {
|
|
7
|
+
private screenshotCapture;
|
|
8
|
+
private lastScrollY;
|
|
9
|
+
private viewportHeight;
|
|
10
|
+
private observers;
|
|
11
|
+
private isRecording;
|
|
12
|
+
private hasInitialScreenshot;
|
|
13
|
+
constructor(screenshotCapture: ScreenshotCapture);
|
|
14
|
+
/**
|
|
15
|
+
* Start event detection
|
|
16
|
+
*/
|
|
17
|
+
start(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Stop event detection
|
|
20
|
+
*/
|
|
21
|
+
stop(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Handle rrweb event for additional detection
|
|
24
|
+
*/
|
|
25
|
+
handleRrwebEvent(event: eventWithTime): void;
|
|
26
|
+
/**
|
|
27
|
+
* Trigger a screenshot with event type
|
|
28
|
+
*/
|
|
29
|
+
private triggerScreenshot;
|
|
30
|
+
/**
|
|
31
|
+
* Set up modal/dialog detection using MutationObserver
|
|
32
|
+
*/
|
|
33
|
+
private setupModalDetection;
|
|
34
|
+
/**
|
|
35
|
+
* Check if an element is a modal/dialog
|
|
36
|
+
*/
|
|
37
|
+
private isModal;
|
|
38
|
+
/**
|
|
39
|
+
* Set up scroll detection
|
|
40
|
+
*/
|
|
41
|
+
private setupScrollDetection;
|
|
42
|
+
private handleScroll;
|
|
43
|
+
/**
|
|
44
|
+
* Set up form submission detection
|
|
45
|
+
*/
|
|
46
|
+
private setupFormDetection;
|
|
47
|
+
private handleFormSubmit;
|
|
48
|
+
/**
|
|
49
|
+
* Set up navigation detection
|
|
50
|
+
*/
|
|
51
|
+
private setupNavigationDetection;
|
|
52
|
+
private handleNavigation;
|
|
53
|
+
/**
|
|
54
|
+
* Clean up all listeners
|
|
55
|
+
*/
|
|
56
|
+
destroy(): void;
|
|
57
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { InviteDialogController } from './ui/InviteDialog';
|
|
2
|
+
import type { RecorderConfig, RecorderState, RecordingResult } from './types';
|
|
3
|
+
export { InviteDialogController };
|
|
4
|
+
export type { RecorderConfig, RecorderState, RecordingResult, ToolbarPosition, ScreenshotMarker, ScreenshotEventType, } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Main DemoRecorder class - orchestrates all components
|
|
7
|
+
*/
|
|
8
|
+
export declare class DemoRecorder {
|
|
9
|
+
private config;
|
|
10
|
+
private recorder;
|
|
11
|
+
private screenshotMarker;
|
|
12
|
+
private eventDetector;
|
|
13
|
+
private toolbar;
|
|
14
|
+
private isInitialized;
|
|
15
|
+
constructor(config: RecorderConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Initialize the recorder (mount toolbar)
|
|
18
|
+
*/
|
|
19
|
+
init(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Start recording
|
|
22
|
+
*/
|
|
23
|
+
start(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Pause recording
|
|
26
|
+
*/
|
|
27
|
+
pause(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Resume recording
|
|
30
|
+
*/
|
|
31
|
+
resume(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Stop recording
|
|
34
|
+
*/
|
|
35
|
+
stop(): Promise<RecordingResult | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* Add a manual screenshot marker
|
|
38
|
+
*/
|
|
39
|
+
screenshot(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Restart - reset everything for a new recording
|
|
42
|
+
*/
|
|
43
|
+
restart(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get current state
|
|
46
|
+
*/
|
|
47
|
+
getState(): RecorderState;
|
|
48
|
+
/**
|
|
49
|
+
* Get elapsed time
|
|
50
|
+
*/
|
|
51
|
+
getElapsedTime(): number;
|
|
52
|
+
/**
|
|
53
|
+
* Destroy the recorder
|
|
54
|
+
*/
|
|
55
|
+
destroy(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Handle state changes
|
|
58
|
+
*/
|
|
59
|
+
private handleStateChange;
|
|
60
|
+
}
|
|
61
|
+
export default DemoRecorder;
|