@bentolabs/sdk 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 BentoLabs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,254 @@
1
+ # BentoLabs SDK
2
+
3
+ A TypeScript SDK for user session recording and analytics using rrweb.
4
+
5
+ [![CI/CD Pipeline](https://github.com/bentolabs/bentolabs-sdk/workflows/CI%2FCD%20Pipeline/badge.svg)](https://github.com/bentolabs/bentolabs-sdk/actions)
6
+ [![Code Quality](https://github.com/bentolabs/bentolabs-sdk/workflows/Code%20Quality/badge.svg)](https://github.com/bentolabs/bentolabs-sdk/actions)
7
+ [![npm version](https://badge.fury.io/js/%40bentolabs%2Fsdk.svg)](https://badge.fury.io/js/%40bentolabs%2Fsdk)
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @bentolabs/sdk
13
+ ```
14
+
15
+ ## CI/CD Pipeline
16
+
17
+ This project includes a streamlined CI/CD pipeline with:
18
+
19
+ - ✅ **Release-Triggered Builds** - Only runs when you create a GitHub release
20
+ - ✅ **Automated Testing** on Node.js 18.x
21
+ - ✅ **Code Quality Checks** (ESLint, Prettier, TypeScript)
22
+ - ✅ **Automated Build** and validation
23
+ - ✅ **Automated NPM Publishing** on releases
24
+ - ✅ **Dependency Management** with Dependabot
25
+
26
+ ### Quick Setup
27
+
28
+ 1. **Set NPM Token**: Add `NPM_TOKEN` to GitHub repository secrets
29
+ 2. **Create Release**: Tag and release on GitHub to automatically build, test, and publish to npm
30
+
31
+ See [DEPLOYMENT.md](./DEPLOYMENT.md) for detailed setup instructions.
32
+
33
+ ## Quick Start
34
+
35
+ ```typescript
36
+ import { BentoLabsSDK } from '@bentolabs/sdk';
37
+
38
+ // Create SDK instance
39
+ const sdk = new BentoLabsSDK();
40
+
41
+ // Initialize with your API key
42
+ sdk.init('your-api-key', {
43
+ endpoint: 'https://api.bentolabs.ai',
44
+ debug: true,
45
+ });
46
+
47
+ // Check status
48
+ console.log('Session ID:', sdk.getSessionId());
49
+ console.log('Recording:', sdk.isRecordingActive());
50
+ ```
51
+
52
+ ## API Reference
53
+
54
+ ### Initialization
55
+
56
+ #### `init(apiKey: string, options?: SDKOptions)`
57
+
58
+ Initialize the SDK with your API key and optional configuration.
59
+
60
+ **Parameters:**
61
+
62
+ - `apiKey` (string): Your BentoLabs API key
63
+ - `options` (SDKOptions, optional): Configuration options
64
+
65
+ **Options:**
66
+
67
+ ```typescript
68
+ interface SDKOptions {
69
+ endpoint?: string; // API endpoint URL (default: 'https://api.bentolabs.ai')
70
+ debug?: boolean; // Enable debug logging (default: false)
71
+ }
72
+ ```
73
+
74
+ **Example:**
75
+
76
+ ```typescript
77
+ sdk.init('your-api-key', {
78
+ endpoint: 'https://custom-endpoint.com',
79
+ debug: true,
80
+ });
81
+ ```
82
+
83
+ ### Methods
84
+
85
+ #### `getSessionId(): string`
86
+
87
+ Returns the current session ID.
88
+
89
+ ```typescript
90
+ const sessionId = sdk.getSessionId();
91
+ console.log('Current session:', sessionId); // sess_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
92
+ ```
93
+
94
+ #### `isRecordingActive(): boolean`
95
+
96
+ Check if recording is currently active.
97
+
98
+ ```typescript
99
+ if (sdk.isRecordingActive()) {
100
+ console.log('Recording user interactions...');
101
+ }
102
+ ```
103
+
104
+ #### `getConfig(): Omit<SDKConfig, 'apiKey'> & { apiKey: string }`
105
+
106
+ Get current configuration with masked API key for security.
107
+
108
+ ```typescript
109
+ const config = sdk.getConfig();
110
+ console.log(config);
111
+ // {
112
+ // apiKey: 'your-api...',
113
+ // endpoint: 'https://api.bentolabs.ai',
114
+ // debug: false
115
+ // }
116
+ ```
117
+
118
+ ## Examples
119
+
120
+ ### React Integration
121
+
122
+ ```typescript
123
+ import React, { useEffect, useState } from 'react';
124
+ import { BentoLabsSDK } from '@bentolabs/sdk';
125
+
126
+ function App() {
127
+ const [sdk] = useState(() => new BentoLabsSDK());
128
+ const [sessionId, setSessionId] = useState('');
129
+
130
+ useEffect(() => {
131
+ sdk.init('your-api-key', { debug: true });
132
+ setSessionId(sdk.getSessionId());
133
+ }, [sdk]);
134
+
135
+ return (
136
+ <div>
137
+ <h1>My App</h1>
138
+ <p>Session: {sessionId}</p>
139
+ <p>Recording: {sdk.isRecordingActive() ? 'Active' : 'Inactive'}</p>
140
+ </div>
141
+ );
142
+ }
143
+ ```
144
+
145
+ ### Vanilla JavaScript
146
+
147
+ ```html
148
+ <!DOCTYPE html>
149
+ <html>
150
+ <head>
151
+ <script src="https://unpkg.com/@bentolabs/sdk@latest/dist/index.js"></script>
152
+ </head>
153
+ <body>
154
+ <script>
155
+ const sdk = new BentoLabsSDK();
156
+ sdk.init('your-api-key', { debug: true });
157
+
158
+ console.log('Session ID:', sdk.getSessionId());
159
+ console.log('Recording:', sdk.isRecordingActive());
160
+ </script>
161
+ </body>
162
+ </html>
163
+ ```
164
+
165
+ ## Examples Directory
166
+
167
+ Check out the [examples](./examples/) directory for complete working examples:
168
+
169
+ - **[React Example](./examples/react-example/)**: Comprehensive React application with interactive demo
170
+ - **[Vanilla JS Example](./examples/vanilla-js/)**: Simple HTML/JavaScript integration
171
+
172
+ ## Development
173
+
174
+ ### Setup
175
+
176
+ ```bash
177
+ # Clone the repository
178
+ git clone https://github.com/bentolabs/bentolabs-sdk.git
179
+ cd bentolabs-sdk
180
+
181
+ # Install dependencies
182
+ npm install
183
+
184
+ # Build the project
185
+ npm run build
186
+
187
+ # Run tests
188
+ npm test
189
+
190
+ # Run tests with coverage
191
+ npm run test:coverage
192
+
193
+ # Start development mode
194
+ npm run dev
195
+ ```
196
+
197
+ ### Scripts
198
+
199
+ - `npm run build` - Build the TypeScript project
200
+ - `npm run dev` - Start TypeScript compiler in watch mode
201
+ - `npm test` - Run all tests
202
+ - `npm run test:watch` - Run tests in watch mode
203
+ - `npm run test:coverage` - Run tests with coverage report
204
+ - `npm run lint` - Run ESLint
205
+ - `npm run format` - Format code with Prettier
206
+
207
+ ### Project Structure
208
+
209
+ ```
210
+ bentolabs-sdk/
211
+ ├── src/ # Source code
212
+ │ └── index.ts # Main SDK implementation
213
+ ├── tests/ # Test files
214
+ │ ├── BentoLabsSDK.test.ts
215
+ │ └── integration.test.ts
216
+ ├── examples/ # Example applications
217
+ │ └── react-example/ # React example
218
+ ├── dist/ # Built files (generated)
219
+ ├── coverage/ # Test coverage (generated)
220
+ └── .github/ # GitHub Actions workflows
221
+ ```
222
+
223
+ ## Contributing
224
+
225
+ 1. Fork the repository
226
+ 2. Create a feature branch: `git checkout -b feature/my-feature`
227
+ 3. Make your changes and add tests
228
+ 4. Run tests: `npm test`
229
+ 5. Run linting: `npm run lint`
230
+ 6. Commit your changes: `git commit -am 'Add my feature'`
231
+ 7. Push to the branch: `git push origin feature/my-feature`
232
+ 8. Submit a pull request
233
+
234
+ ## Publishing
235
+
236
+ ### Stable Release
237
+
238
+ 1. Create a GitHub release with a version tag (e.g., `v1.0.0`)
239
+ 2. GitHub Actions will automatically publish to npm
240
+
241
+ ### Beta Release
242
+
243
+ 1. Push changes to the `develop` branch
244
+ 2. GitHub Actions will automatically publish a beta version
245
+
246
+ ## License
247
+
248
+ MIT License - see [LICENSE](LICENSE) file for details.
249
+
250
+ ## Support
251
+
252
+ - 📖 [Documentation](https://github.com/bentolabs/bentolabs-sdk)
253
+ - 🐛 [Issue Tracker](https://github.com/bentolabs/bentolabs-sdk/issues)
254
+ - 💬 [Discussions](https://github.com/bentolabs/bentolabs-sdk/discussions)
@@ -0,0 +1,91 @@
1
+ interface SDKConfig {
2
+ apiKey: string;
3
+ endpoint: string;
4
+ debug: boolean;
5
+ batchSize: number;
6
+ batchInterval: number;
7
+ enableRecording: boolean;
8
+ maxRetries: number;
9
+ baseRetryDelay: number;
10
+ }
11
+ interface SDKOptions {
12
+ endpoint?: string;
13
+ debug?: boolean;
14
+ batchSize?: number;
15
+ batchInterval?: number;
16
+ enableRecording?: boolean;
17
+ maxRetries?: number;
18
+ baseRetryDelay?: number;
19
+ }
20
+ export declare class BentoLabsSDK {
21
+ private config;
22
+ private sessionId;
23
+ private events;
24
+ private isRecording;
25
+ private batchTimer;
26
+ private retryTimer;
27
+ private stopRecording;
28
+ constructor();
29
+ /**
30
+ * Initialize the BentoLabs SDK
31
+ * @param apiKey - Your API key for authentication
32
+ * @param options - Optional configuration options
33
+ */
34
+ init(apiKey: string, options?: SDKOptions): void;
35
+ /**
36
+ * Generate a unique session ID with 'sess_' prefix
37
+ */
38
+ private generateSessionId;
39
+ /**
40
+ * Generate a simple UUID v4
41
+ */
42
+ private generateUUID;
43
+ /**
44
+ * Start recording user interactions
45
+ */
46
+ private startRecording;
47
+ /**
48
+ * Start batching events for transmission
49
+ */
50
+ private startBatching;
51
+ /**
52
+ * Add an event to the events array
53
+ */
54
+ private addEvent;
55
+ /**
56
+ * Send batched events to the API with exponential backoff retry
57
+ */
58
+ private sendBatch;
59
+ /**
60
+ * Schedule retry attempts for failed events
61
+ */
62
+ private scheduleRetry;
63
+ /**
64
+ * Stop recording and clean up resources
65
+ */
66
+ stop(): void;
67
+ /**
68
+ * Get current session ID
69
+ */
70
+ getSessionId(): string;
71
+ /**
72
+ * Check if recording is active
73
+ */
74
+ isRecordingActive(): boolean;
75
+ /**
76
+ * Get current configuration (without exposing sensitive data)
77
+ */
78
+ getConfig(): Omit<SDKConfig, 'apiKey'> & {
79
+ apiKey: string;
80
+ };
81
+ /**
82
+ * Get current event queue length
83
+ */
84
+ getEventQueueLength(): number;
85
+ /**
86
+ * Manually trigger a batch send
87
+ */
88
+ flushEvents(): Promise<void>;
89
+ }
90
+ declare const _default: BentoLabsSDK;
91
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BentoLabsSDK = void 0;
4
+ const rrweb_1 = require("rrweb");
5
+ class BentoLabsSDK {
6
+ constructor() {
7
+ this.config = {
8
+ apiKey: '',
9
+ endpoint: '',
10
+ debug: false,
11
+ batchSize: 50,
12
+ batchInterval: 10000, // 10 seconds
13
+ enableRecording: true,
14
+ maxRetries: 3,
15
+ baseRetryDelay: 1000,
16
+ };
17
+ this.sessionId = '';
18
+ this.events = [];
19
+ this.isRecording = false;
20
+ this.batchTimer = null;
21
+ this.retryTimer = null;
22
+ this.stopRecording = null;
23
+ }
24
+ /**
25
+ * Initialize the BentoLabs SDK
26
+ * @param apiKey - Your API key for authentication
27
+ * @param options - Optional configuration options
28
+ */
29
+ init(apiKey, options) {
30
+ var _a;
31
+ // Merge options with defaults
32
+ const defaultOptions = {
33
+ endpoint: 'https://api.bentolabs.ai',
34
+ debug: false,
35
+ batchSize: 100, // Increased from 50 to reduce API calls
36
+ batchInterval: 30000, // 30 seconds (increased from 10s)
37
+ enableRecording: true,
38
+ maxRetries: 3,
39
+ baseRetryDelay: 1000, // 1 second
40
+ };
41
+ const mergedOptions = Object.assign(Object.assign(Object.assign({}, defaultOptions), options), {
42
+ // Ensure debug is always a boolean
43
+ debug: (_a = options === null || options === void 0 ? void 0 : options.debug) !== null && _a !== void 0 ? _a : defaultOptions.debug });
44
+ // Set up configuration
45
+ this.config = {
46
+ apiKey,
47
+ endpoint: mergedOptions.endpoint,
48
+ debug: mergedOptions.debug,
49
+ batchSize: mergedOptions.batchSize,
50
+ batchInterval: mergedOptions.batchInterval,
51
+ enableRecording: mergedOptions.enableRecording,
52
+ maxRetries: mergedOptions.maxRetries,
53
+ baseRetryDelay: mergedOptions.baseRetryDelay,
54
+ };
55
+ // Generate session ID with 'sess_' prefix
56
+ this.sessionId = this.generateSessionId();
57
+ // Log initialization if debug mode is on
58
+ if (this.config.debug) {
59
+ console.log('[BentoLabsSDK] Initialized with config:', {
60
+ apiKey: apiKey.substring(0, 8) + '...',
61
+ endpoint: this.config.endpoint,
62
+ debug: this.config.debug,
63
+ sessionId: this.sessionId,
64
+ });
65
+ }
66
+ // Start recording and batching
67
+ this.startRecording();
68
+ this.startBatching();
69
+ }
70
+ /**
71
+ * Generate a unique session ID with 'sess_' prefix
72
+ */
73
+ generateSessionId() {
74
+ const uuid = this.generateUUID();
75
+ return `sess_${uuid}`;
76
+ }
77
+ /**
78
+ * Generate a simple UUID v4
79
+ */
80
+ generateUUID() {
81
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
82
+ const r = (Math.random() * 16) | 0;
83
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
84
+ return v.toString(16);
85
+ });
86
+ }
87
+ /**
88
+ * Start recording user interactions
89
+ */
90
+ startRecording() {
91
+ if (!this.config.enableRecording) {
92
+ if (this.config.debug) {
93
+ console.log('[BentoLabsSDK] Recording disabled in configuration');
94
+ }
95
+ return;
96
+ }
97
+ if (this.config.debug) {
98
+ console.log('[BentoLabsSDK] Starting recording for session:', this.sessionId);
99
+ }
100
+ try {
101
+ const stopFn = (0, rrweb_1.record)({
102
+ emit: (event) => {
103
+ this.addEvent({
104
+ timestamp: event.timestamp,
105
+ type: event.type.toString(),
106
+ data: event,
107
+ sessionId: this.sessionId,
108
+ });
109
+ },
110
+ recordCanvas: true,
111
+ collectFonts: true,
112
+ plugins: [],
113
+ // Sampling and throttling to reduce event volume
114
+ sampling: {
115
+ mousemove: true, // Sample mouse movements
116
+ mouseInteraction: { click: false, dblclick: false }, // Capture all clicks
117
+ scroll: 150, // Throttle scroll events to 150ms
118
+ input: 'last', // Only record final input value
119
+ },
120
+ checkoutEveryNms: 5 * 60 * 1000, // Take full snapshot every 5 minutes
121
+ });
122
+ this.stopRecording = stopFn || null;
123
+ this.isRecording = true;
124
+ if (this.config.debug) {
125
+ console.log('[BentoLabsSDK] Recording started successfully');
126
+ }
127
+ }
128
+ catch (error) {
129
+ console.error('[BentoLabsSDK] Failed to start recording:', error);
130
+ this.isRecording = false;
131
+ }
132
+ }
133
+ /**
134
+ * Start batching events for transmission
135
+ */
136
+ startBatching() {
137
+ if (this.config.debug) {
138
+ console.log('[BentoLabsSDK] Starting event batching');
139
+ }
140
+ // Clear any existing timer
141
+ if (this.batchTimer) {
142
+ clearInterval(this.batchTimer);
143
+ }
144
+ // Set up periodic batch sending
145
+ this.batchTimer = setInterval(() => {
146
+ this.sendBatch();
147
+ }, this.config.batchInterval);
148
+ if (this.config.debug) {
149
+ console.log(`[BentoLabsSDK] Batch timer set for ${this.config.batchInterval}ms intervals`);
150
+ }
151
+ }
152
+ /**
153
+ * Add an event to the events array
154
+ */
155
+ addEvent(event) {
156
+ this.events.push(event);
157
+ if (this.config.debug) {
158
+ console.log('[BentoLabsSDK] Event added:', event.type);
159
+ }
160
+ // Check if we should send a batch based on size
161
+ if (this.events.length >= this.config.batchSize) {
162
+ if (this.config.debug) {
163
+ console.log(`[BentoLabsSDK] Batch size limit reached (${this.config.batchSize}), sending batch`);
164
+ }
165
+ this.sendBatch();
166
+ }
167
+ }
168
+ /**
169
+ * Send batched events to the API with exponential backoff retry
170
+ */
171
+ async sendBatch() {
172
+ // Filter out events that are not ready for retry yet
173
+ const now = Date.now();
174
+ const readyEvents = this.events.filter(event => {
175
+ if ('nextRetryTime' in event) {
176
+ return now >= event.nextRetryTime;
177
+ }
178
+ return true;
179
+ });
180
+ if (readyEvents.length === 0) {
181
+ return;
182
+ }
183
+ // Remove ready events from the main array
184
+ this.events = this.events.filter(event => !readyEvents.includes(event));
185
+ const payload = {
186
+ sessionId: this.sessionId,
187
+ events: readyEvents,
188
+ timestamp: now,
189
+ userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'Unknown',
190
+ url: typeof window !== 'undefined' ? window.location.href : 'Unknown',
191
+ };
192
+ if (this.config.debug) {
193
+ console.log(`[BentoLabsSDK] Sending batch with ${readyEvents.length} events`);
194
+ }
195
+ try {
196
+ const response = await fetch(`${this.config.endpoint}/events/`, {
197
+ method: 'POST',
198
+ headers: {
199
+ 'Content-Type': 'application/json',
200
+ Authorization: `Bearer ${this.config.apiKey}`,
201
+ 'X-Session-ID': this.sessionId,
202
+ },
203
+ body: JSON.stringify(payload),
204
+ });
205
+ if (!response.ok) {
206
+ throw new Error(`HTTP error! status: ${response.status}`);
207
+ }
208
+ if (this.config.debug) {
209
+ console.log('[BentoLabsSDK] Batch sent successfully');
210
+ }
211
+ }
212
+ catch (error) {
213
+ console.error('[BentoLabsSDK] Failed to send batch:', error);
214
+ // Convert events to retryable events with exponential backoff
215
+ const retryableEvents = readyEvents.map(event => {
216
+ const retryCount = 'retryCount' in event ? event.retryCount + 1 : 1;
217
+ const delay = this.config.baseRetryDelay * Math.pow(2, retryCount - 1);
218
+ return Object.assign(Object.assign({}, event), { retryCount, nextRetryTime: now + delay });
219
+ });
220
+ // Filter out events that have exceeded max retries
221
+ const eventsToRetry = retryableEvents.filter(event => event.retryCount <= this.config.maxRetries);
222
+ const droppedEvents = retryableEvents.length - eventsToRetry.length;
223
+ if (droppedEvents > 0 && this.config.debug) {
224
+ console.log(`[BentoLabsSDK] Dropped ${droppedEvents} events after max retries`);
225
+ }
226
+ // Re-add events that can still be retried
227
+ this.events.unshift(...eventsToRetry);
228
+ if (this.config.debug && eventsToRetry.length > 0) {
229
+ const nextRetryIn = Math.min(...eventsToRetry.map(e => e.nextRetryTime)) - now;
230
+ console.log(`[BentoLabsSDK] ${eventsToRetry.length} events re-queued for retry in ${nextRetryIn}ms`);
231
+ }
232
+ // Set up retry timer if we have events to retry
233
+ this.scheduleRetry();
234
+ }
235
+ }
236
+ /**
237
+ * Schedule retry attempts for failed events
238
+ */
239
+ scheduleRetry() {
240
+ // Clear existing retry timer
241
+ if (this.retryTimer) {
242
+ clearTimeout(this.retryTimer);
243
+ this.retryTimer = null;
244
+ }
245
+ // Find the next retry time
246
+ const now = Date.now();
247
+ const retryableEvents = this.events.filter(event => 'nextRetryTime' in event);
248
+ if (retryableEvents.length === 0) {
249
+ return;
250
+ }
251
+ const nextRetryTime = Math.min(...retryableEvents.map(e => e.nextRetryTime));
252
+ const delay = Math.max(0, nextRetryTime - now);
253
+ if (this.config.debug) {
254
+ console.log(`[BentoLabsSDK] Scheduling retry in ${delay}ms`);
255
+ }
256
+ this.retryTimer = setTimeout(() => {
257
+ this.sendBatch();
258
+ }, delay);
259
+ }
260
+ /**
261
+ * Stop recording and clean up resources
262
+ */
263
+ stop() {
264
+ if (this.config.debug) {
265
+ console.log('[BentoLabsSDK] Stopping recording and batching');
266
+ }
267
+ // Stop rrweb recording
268
+ if (this.stopRecording) {
269
+ this.stopRecording();
270
+ this.stopRecording = null;
271
+ }
272
+ // Clear batch timer
273
+ if (this.batchTimer) {
274
+ clearInterval(this.batchTimer);
275
+ this.batchTimer = null;
276
+ }
277
+ // Clear retry timer
278
+ if (this.retryTimer) {
279
+ clearTimeout(this.retryTimer);
280
+ this.retryTimer = null;
281
+ }
282
+ // Send any remaining events
283
+ if (this.events.length > 0) {
284
+ this.sendBatch();
285
+ }
286
+ this.isRecording = false;
287
+ if (this.config.debug) {
288
+ console.log('[BentoLabsSDK] Stopped successfully');
289
+ }
290
+ }
291
+ /**
292
+ * Get current session ID
293
+ */
294
+ getSessionId() {
295
+ return this.sessionId;
296
+ }
297
+ /**
298
+ * Check if recording is active
299
+ */
300
+ isRecordingActive() {
301
+ return this.isRecording;
302
+ }
303
+ /**
304
+ * Get current configuration (without exposing sensitive data)
305
+ */
306
+ getConfig() {
307
+ return {
308
+ apiKey: this.config.apiKey
309
+ ? this.config.apiKey.substring(0, 8) + '...'
310
+ : '',
311
+ endpoint: this.config.endpoint,
312
+ debug: this.config.debug,
313
+ batchSize: this.config.batchSize,
314
+ batchInterval: this.config.batchInterval,
315
+ enableRecording: this.config.enableRecording,
316
+ maxRetries: this.config.maxRetries,
317
+ baseRetryDelay: this.config.baseRetryDelay,
318
+ };
319
+ }
320
+ /**
321
+ * Get current event queue length
322
+ */
323
+ getEventQueueLength() {
324
+ return this.events.length;
325
+ }
326
+ /**
327
+ * Manually trigger a batch send
328
+ */
329
+ async flushEvents() {
330
+ await this.sendBatch();
331
+ }
332
+ }
333
+ exports.BentoLabsSDK = BentoLabsSDK;
334
+ // Export a default instance for convenience
335
+ exports.default = new BentoLabsSDK();
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@bentolabs/sdk",
3
+ "version": "0.2.0",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "dev": "tsc --watch",
9
+ "test": "jest",
10
+ "test:watch": "jest --watch",
11
+ "test:coverage": "jest --coverage",
12
+ "test:ci": "jest --ci --coverage --watchAll=false",
13
+ "lint": "eslint src/**/*.ts --fix",
14
+ "lint:check": "eslint src/**/*.ts",
15
+ "format": "prettier --write \"src/**/*.{ts,js,json}\"",
16
+ "format:check": "prettier --check \"src/**/*.{ts,js,json}\"",
17
+ "prepublishOnly": "npm run build && npm test",
18
+ "preversion": "npm run lint:check && npm test"
19
+ },
20
+ "description": "BentoLabs SDK for user session recording and analytics",
21
+ "keywords": [
22
+ "analytics",
23
+ "session-recording",
24
+ "user-tracking",
25
+ "rrweb",
26
+ "typescript",
27
+ "sdk"
28
+ ],
29
+ "author": "kacppian",
30
+ "license": "MIT",
31
+ "homepage": "https://github.com/bentolabs/bentolabs-sdk#readme",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/bentolabs/bentolabs-sdk.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/bentolabs/bentolabs-sdk/issues"
38
+ },
39
+ "files": [
40
+ "dist/**/*",
41
+ "README.md",
42
+ "LICENSE"
43
+ ],
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "registry": "https://registry.npmjs.org/"
47
+ },
48
+ "engines": {
49
+ "node": ">=14.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@types/jest": "^30.0.0",
53
+ "@types/node": "^24.5.1",
54
+ "@typescript-eslint/eslint-plugin": "^7.2.0",
55
+ "@typescript-eslint/parser": "^7.2.0",
56
+ "eslint": "^8.57.1",
57
+ "eslint-config-prettier": "^10.1.8",
58
+ "eslint-plugin-prettier": "^5.5.4",
59
+ "jest": "^30.1.3",
60
+ "jest-environment-jsdom": "^30.1.2",
61
+ "prettier": "^3.6.2",
62
+ "ts-jest": "^29.4.2",
63
+ "typescript": "^5.9.2"
64
+ },
65
+ "dependencies": {
66
+ "rrweb": "^1.1.3"
67
+ }
68
+ }