blinker-sdk 1.0.0 → 2.0.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.
Files changed (91) hide show
  1. package/README.md +287 -84
  2. package/dist/blinker.min.js +452 -1
  3. package/dist/capture/deduplication.d.ts +26 -0
  4. package/dist/capture/deduplication.d.ts.map +1 -0
  5. package/dist/capture/errorHandler.d.ts +5 -0
  6. package/dist/capture/errorHandler.d.ts.map +1 -0
  7. package/dist/capture/index.d.ts +4 -0
  8. package/dist/capture/index.d.ts.map +1 -0
  9. package/dist/capture/types.d.ts +13 -0
  10. package/dist/capture/types.d.ts.map +1 -0
  11. package/dist/context/SessionManager.d.ts +16 -0
  12. package/dist/context/SessionManager.d.ts.map +1 -0
  13. package/dist/context/UserContext.d.ts +19 -0
  14. package/dist/context/UserContext.d.ts.map +1 -0
  15. package/dist/context/index.d.ts +4 -0
  16. package/dist/context/index.d.ts.map +1 -0
  17. package/dist/context/types.d.ts +18 -0
  18. package/dist/context/types.d.ts.map +1 -0
  19. package/dist/core/Blinker.d.ts +42 -0
  20. package/dist/core/Blinker.d.ts.map +1 -0
  21. package/dist/core/config.d.ts +26 -0
  22. package/dist/core/config.d.ts.map +1 -0
  23. package/dist/core/index.d.ts +4 -0
  24. package/dist/core/index.d.ts.map +1 -0
  25. package/dist/core/types.d.ts +50 -0
  26. package/dist/core/types.d.ts.map +1 -0
  27. package/dist/filters/FilterEngine.d.ts +9 -0
  28. package/dist/filters/FilterEngine.d.ts.map +1 -0
  29. package/dist/filters/defaults.d.ts +3 -0
  30. package/dist/filters/defaults.d.ts.map +1 -0
  31. package/dist/filters/index.d.ts +4 -0
  32. package/dist/filters/index.d.ts.map +1 -0
  33. package/dist/filters/types.d.ts +8 -0
  34. package/dist/filters/types.d.ts.map +1 -0
  35. package/dist/index.cjs.js +2098 -125
  36. package/dist/index.d.ts +7 -24
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.esm.js +2098 -125
  39. package/dist/queue/EventQueue.d.ts +21 -0
  40. package/dist/queue/EventQueue.d.ts.map +1 -0
  41. package/dist/queue/index.d.ts +4 -0
  42. package/dist/queue/index.d.ts.map +1 -0
  43. package/dist/queue/storage.d.ts +16 -0
  44. package/dist/queue/storage.d.ts.map +1 -0
  45. package/dist/queue/types.d.ts +19 -0
  46. package/dist/queue/types.d.ts.map +1 -0
  47. package/dist/sampling/RateLimiter.d.ts +12 -0
  48. package/dist/sampling/RateLimiter.d.ts.map +1 -0
  49. package/dist/sampling/Sampler.d.ts +16 -0
  50. package/dist/sampling/Sampler.d.ts.map +1 -0
  51. package/dist/sampling/index.d.ts +4 -0
  52. package/dist/sampling/index.d.ts.map +1 -0
  53. package/dist/sampling/types.d.ts +10 -0
  54. package/dist/sampling/types.d.ts.map +1 -0
  55. package/dist/transport/index.d.ts +3 -0
  56. package/dist/transport/index.d.ts.map +1 -0
  57. package/dist/transport/sender.d.ts +4 -0
  58. package/dist/transport/sender.d.ts.map +1 -0
  59. package/dist/transport/types.d.ts +12 -0
  60. package/dist/transport/types.d.ts.map +1 -0
  61. package/dist/utils/browser.d.ts +10 -0
  62. package/dist/utils/browser.d.ts.map +1 -0
  63. package/dist/utils/hash.d.ts +4 -0
  64. package/dist/utils/hash.d.ts.map +1 -0
  65. package/dist/utils/index.d.ts +4 -0
  66. package/dist/utils/index.d.ts.map +1 -0
  67. package/dist/utils/logger.d.ts +9 -0
  68. package/dist/utils/logger.d.ts.map +1 -0
  69. package/dist/widget/Avatar.d.ts +20 -0
  70. package/dist/widget/Avatar.d.ts.map +1 -0
  71. package/dist/widget/Dialog.d.ts +25 -0
  72. package/dist/widget/Dialog.d.ts.map +1 -0
  73. package/dist/widget/QuestionEngine.d.ts +7 -0
  74. package/dist/widget/QuestionEngine.d.ts.map +1 -0
  75. package/dist/widget/Widget.d.ts +28 -0
  76. package/dist/widget/Widget.d.ts.map +1 -0
  77. package/dist/widget/index.d.ts +8 -0
  78. package/dist/widget/index.d.ts.map +1 -0
  79. package/dist/widget/styles.d.ts +5 -0
  80. package/dist/widget/styles.d.ts.map +1 -0
  81. package/dist/widget/types.d.ts +46 -0
  82. package/dist/widget/types.d.ts.map +1 -0
  83. package/package.json +2 -3
  84. package/dist/Blinker.d.ts +0 -47
  85. package/dist/Blinker.d.ts.map +0 -1
  86. package/dist/errorHandler.d.ts +0 -19
  87. package/dist/errorHandler.d.ts.map +0 -1
  88. package/dist/sender.d.ts +0 -11
  89. package/dist/sender.d.ts.map +0 -1
  90. package/dist/types.d.ts +0 -63
  91. package/dist/types.d.ts.map +0 -1
package/README.md CHANGED
@@ -4,12 +4,19 @@ Universal JavaScript SDK for error tracking and event capture. Works with **any
4
4
 
5
5
  ## Features
6
6
 
7
- - 🚀 **Zero dependencies** - Lightweight and fast
8
- - 🌐 **Universal** - Works in any JavaScript environment
9
- - 🔄 **Automatic error capture** - Catches global errors and unhandled rejections
10
- - 📊 **Custom events** - Track any event you need
11
- - 📦 **Multiple formats** - ESM, CommonJS, and UMD (CDN)
12
- - 🔒 **Type-safe** - Full TypeScript support
7
+ - **Zero dependencies** - Lightweight and fast
8
+ - **Universal** - Works in any JavaScript environment
9
+ - **Automatic error capture** - Catches global errors and unhandled rejections
10
+ - **Smart filtering** - Ignores common non-bugs (401, 403, ResizeObserver) by default
11
+ - **Event batching** - Efficient sending with configurable batch size
12
+ - **Offline support** - Persists events when offline, sends when back online
13
+ - **Deduplication** - Prevents flood of identical errors
14
+ - **Rate limiting** - Protects against excessive event sending
15
+ - **Sampling** - Sample events for high-traffic apps
16
+ - **Session tracking** - Automatic session management with pageview counting
17
+ - **User context** - Identify users and attach custom context
18
+ - **Multiple formats** - ESM, CommonJS, and UMD (CDN)
19
+ - **Type-safe** - Full TypeScript support
13
20
 
14
21
  ## Installation
15
22
 
@@ -29,7 +36,7 @@ pnpm add blinker-sdk
29
36
  <script src="https://unpkg.com/blinker-sdk/dist/blinker.min.js"></script>
30
37
  <script>
31
38
  const { blinker } = BlinkerSDK;
32
- blinker.init({ token: 'your-token', api: 'https://api.example.com' });
39
+ blinker.init({ token: 'your-token' });
33
40
  </script>
34
41
  ```
35
42
 
@@ -38,13 +45,15 @@ pnpm add blinker-sdk
38
45
  ```javascript
39
46
  import { blinker } from 'blinker-sdk';
40
47
 
41
- // Initialize the SDK
42
- blinker.init({
43
- token: 'your-blinker-token',
44
- api: 'https://api.example.com'
45
- });
48
+ // Initialize the SDK - just pass your token!
49
+ blinker.init({ token: 'your-blinker-token' });
46
50
 
47
51
  // That's it! Errors are now automatically captured.
52
+ // ✅ Batches events for efficient sending
53
+ // ✅ Works offline with localStorage persistence
54
+ // ✅ Deduplicates repeated errors
55
+ // ✅ Ignores 401/403 errors by default
56
+ // ✅ Filters out common browser noise
48
57
  ```
49
58
 
50
59
  ## Usage
@@ -54,13 +63,105 @@ blinker.init({
54
63
  ```javascript
55
64
  import { blinker } from 'blinker-sdk';
56
65
 
66
+ // Minimal setup - just the token!
67
+ blinker.init({ token: 'your-blinker-token' });
68
+
69
+ // Or with all options
57
70
  blinker.init({
58
- token: 'your-blinker-token', // Required: Your API token
59
- api: 'https://api.example.com', // Required: API endpoint
60
- captureErrors: true, // Optional: Auto-capture errors (default: true)
61
- captureRejections: true, // Optional: Auto-capture promise rejections (default: true)
62
- debug: false // Optional: Enable debug logging (default: false)
71
+ token: 'your-blinker-token',
72
+ // Capture options
73
+ captureErrors: true,
74
+ captureRejections: true,
75
+ // Batching
76
+ enableBatching: true,
77
+ batchSize: 10,
78
+ flushInterval: 5000,
79
+ // Offline persistence
80
+ enableOfflineStorage: true,
81
+ maxStoredEvents: 100,
82
+ // Deduplication
83
+ enableDeduplication: true,
84
+ deduplicationWindow: 60000,
85
+ // Rate limiting & sampling
86
+ maxEventsPerMinute: 100,
87
+ sampleRate: 1.0,
88
+ // Filters
89
+ filters: {
90
+ ignoreHttpCodes: [401, 403],
91
+ captureAll: false
92
+ },
93
+ // Debug
94
+ debug: false
95
+ });
96
+ ```
97
+
98
+ ### User Identification
99
+
100
+ Identify users to associate events with specific users:
101
+
102
+ ```javascript
103
+ // Identify a user with just an ID
104
+ blinker.identify('user-123');
105
+
106
+ // Identify with traits
107
+ blinker.identify('user-123', {
108
+ name: 'John Doe',
109
+ email: 'john@example.com',
110
+ plan: 'pro',
111
+ company: 'Acme Inc'
63
112
  });
113
+
114
+ // Clear user context on logout
115
+ blinker.clearContext();
116
+ ```
117
+
118
+ ### Custom Context
119
+
120
+ Add custom context that's included in all events:
121
+
122
+ ```javascript
123
+ // Set context values
124
+ blinker.setContext('environment', 'production');
125
+ blinker.setContext('appVersion', '2.1.0');
126
+ blinker.setContext('feature', 'checkout');
127
+
128
+ // Get current context
129
+ const context = blinker.getContext();
130
+ // { environment: 'production', appVersion: '2.1.0', feature: 'checkout' }
131
+
132
+ // Clear all context
133
+ blinker.clearContext();
134
+ ```
135
+
136
+ ### Session Information
137
+
138
+ Access session tracking data:
139
+
140
+ ```javascript
141
+ // Get current session ID
142
+ const sessionId = blinker.getSessionId();
143
+
144
+ // Get full session info
145
+ const session = blinker.getSession();
146
+ // {
147
+ // sessionId: 'abc123...',
148
+ // startTime: 1706700000000,
149
+ // pageViews: 5,
150
+ // duration: 120000
151
+ // }
152
+ ```
153
+
154
+ ### Queue Control
155
+
156
+ Manage the event queue:
157
+
158
+ ```javascript
159
+ // Get number of pending events
160
+ const pending = blinker.getQueueSize();
161
+ console.log(`${pending} events waiting to be sent`);
162
+
163
+ // Force flush all queued events immediately
164
+ await blinker.flush();
64
165
  ```
65
166
 
66
167
  ### Track Custom Events
@@ -96,6 +197,72 @@ try {
96
197
  blinker.captureError('Something went wrong', { userId: '123' });
97
198
  ```
98
199
 
200
+ ### Error Filters (Smart Defaults)
201
+
202
+ The SDK comes with **intelligent default filters** that ignore common non-bug errors.
203
+
204
+ #### Default Behavior
205
+
206
+ By default, the SDK **ignores**:
207
+ - `401` and `403` HTTP errors (authentication/authorization - usually expected behavior)
208
+ - `ResizeObserver loop` errors (benign browser behavior)
209
+ - `Script error` (cross-origin errors with no useful info)
210
+
211
+ ```javascript
212
+ // Minimal initialization - all defaults applied automatically!
213
+ blinker.init({ token: 'your-token' });
214
+ ```
215
+
216
+ #### Capture Everything
217
+
218
+ ```javascript
219
+ blinker.init({
220
+ token: 'your-token',
221
+ filters: { captureAll: true }
222
+ });
223
+ ```
224
+
225
+ #### Custom HTTP Code Filters
226
+
227
+ ```javascript
228
+ // Only ignore 401 (capture 403)
229
+ blinker.init({
230
+ token: 'your-token',
231
+ filters: { ignoreHttpCodes: [401] }
232
+ });
233
+
234
+ // Ignore more codes
235
+ blinker.init({
236
+ token: 'your-token',
237
+ filters: { ignoreHttpCodes: [401, 403, 404, 429] }
238
+ });
239
+ ```
240
+
241
+ #### Ignore Specific Error Types
242
+
243
+ ```javascript
244
+ blinker.init({
245
+ token: 'your-token',
246
+ filters: { ignoreErrorTypes: ['TypeError', 'SyntaxError'] }
247
+ });
248
+ ```
249
+
250
+ #### Ignore Message Patterns
251
+
252
+ ```javascript
253
+ blinker.init({
254
+ token: 'your-token',
255
+ filters: {
256
+ ignoreMessagePatterns: [
257
+ 'ResizeObserver loop',
258
+ 'Script error',
259
+ 'ChunkLoadError',
260
+ 'Network request failed'
261
+ ]
262
+ }
263
+ });
264
+ ```
265
+
99
266
  ### Check SDK Status
100
267
 
101
268
  ```javascript
@@ -106,6 +273,9 @@ if (blinker.isInitialized()) {
106
273
 
107
274
  // Get current config (without sensitive data)
108
275
  const config = blinker.getConfig();
276
+
277
+ // Get current filters
278
+ const filters = blinker.getFilters();
109
279
  ```
110
280
 
111
281
  ### Cleanup
@@ -123,12 +293,13 @@ blinker.destroy();
123
293
  // app.jsx or index.jsx
124
294
  import { blinker } from 'blinker-sdk';
125
295
 
126
- blinker.init({
127
- token: process.env.REACT_APP_BLINKER_TOKEN,
128
- api: process.env.REACT_APP_BLINKER_API
129
- });
296
+ blinker.init({ token: process.env.REACT_APP_BLINKER_TOKEN });
130
297
 
131
298
  function App() {
299
+ useEffect(() => {
300
+ blinker.identify(user.id, { name: user.name, email: user.email });
301
+ }, [user]);
302
+
132
303
  const handleClick = () => {
133
304
  blinker.track('click', 'CTA button clicked', { page: 'home' });
134
305
  };
@@ -148,10 +319,7 @@ import { blinker } from 'blinker-sdk';
148
319
 
149
320
  export default function RootLayout({ children }) {
150
321
  useEffect(() => {
151
- blinker.init({
152
- token: process.env.NEXT_PUBLIC_BLINKER_TOKEN,
153
- api: process.env.NEXT_PUBLIC_BLINKER_API
154
- });
322
+ blinker.init({ token: process.env.NEXT_PUBLIC_BLINKER_TOKEN });
155
323
  }, []);
156
324
 
157
325
  return (
@@ -170,31 +338,11 @@ import { createApp } from 'vue';
170
338
  import { blinker } from 'blinker-sdk';
171
339
  import App from './App.vue';
172
340
 
173
- blinker.init({
174
- token: import.meta.env.VITE_BLINKER_TOKEN,
175
- api: import.meta.env.VITE_BLINKER_API
176
- });
341
+ blinker.init({ token: import.meta.env.VITE_BLINKER_TOKEN });
177
342
 
178
343
  createApp(App).mount('#app');
179
344
  ```
180
345
 
181
- ### Angular
182
-
183
- ```typescript
184
- // app.module.ts
185
- import { blinker } from 'blinker-sdk';
186
-
187
- blinker.init({
188
- token: environment.blinkerToken,
189
- api: environment.blinkerApi
190
- });
191
-
192
- @NgModule({
193
- // ...
194
- })
195
- export class AppModule {}
196
- ```
197
-
198
346
  ### Vanilla JavaScript
199
347
 
200
348
  ```html
@@ -205,15 +353,15 @@ export class AppModule {}
205
353
  </head>
206
354
  <body>
207
355
  <button id="myButton">Click me</button>
208
-
356
+
209
357
  <script>
210
358
  const { blinker } = BlinkerSDK;
211
-
212
- blinker.init({
213
- token: 'your-token',
214
- api: 'https://api.example.com'
215
- });
216
-
359
+
360
+ blinker.init({ token: 'your-token' });
361
+
362
+ // Identify user
363
+ blinker.identify('user-123', { name: 'John' });
364
+
217
365
  document.getElementById('myButton').addEventListener('click', () => {
218
366
  blinker.track('click', 'Button clicked');
219
367
  });
@@ -231,40 +379,83 @@ Initialize the SDK with configuration options.
231
379
  | Option | Type | Default | Description |
232
380
  |--------|------|---------|-------------|
233
381
  | `token` | `string` | **required** | Your Blinker API token |
234
- | `api` | `string` | **required** | API endpoint URL |
235
382
  | `captureErrors` | `boolean` | `true` | Auto-capture window errors |
236
383
  | `captureRejections` | `boolean` | `true` | Auto-capture unhandled rejections |
384
+ | `enableBatching` | `boolean` | `true` | Enable event batching |
385
+ | `batchSize` | `number` | `10` | Events per batch |
386
+ | `flushInterval` | `number` | `5000` | Batch flush interval (ms) |
387
+ | `enableOfflineStorage` | `boolean` | `true` | Persist events when offline |
388
+ | `maxStoredEvents` | `number` | `100` | Max offline events to store |
389
+ | `enableDeduplication` | `boolean` | `true` | Enable error deduplication |
390
+ | `deduplicationWindow` | `number` | `60000` | Dedup window (ms) |
391
+ | `maxEventsPerMinute` | `number` | `100` | Rate limit (0 = unlimited) |
392
+ | `sampleRate` | `number` | `1.0` | Sample rate (0.0-1.0) |
393
+ | `filters` | `FilterSettings` | see below | Error filter configuration |
237
394
  | `debug` | `boolean` | `false` | Enable debug logging |
238
395
 
396
+ #### FilterSettings
397
+
398
+ | Option | Type | Default | Description |
399
+ |--------|------|---------|-------------|
400
+ | `ignoreHttpCodes` | `number[]` | `[401, 403]` | HTTP status codes to ignore |
401
+ | `ignoreErrorTypes` | `string[]` | `[]` | JS error types to ignore |
402
+ | `ignoreMessagePatterns` | `string[]` | `['ResizeObserver loop', 'Script error']` | Message patterns to ignore |
403
+ | `captureAll` | `boolean` | `false` | When true, disables all filters |
404
+
239
405
  ### `blinker.track(type, message, payload?)`
240
406
 
241
407
  Track a custom event.
242
408
 
243
- | Parameter | Type | Description |
244
- |-----------|------|-------------|
245
- | `type` | `string` | Event type (e.g., 'click', 'purchase') |
246
- | `message` | `string` | Event description |
247
- | `payload` | `object` | Optional additional data |
248
-
249
409
  **Returns:** `Promise<{ success: boolean, error?: string }>`
250
410
 
251
411
  ### `blinker.captureError(error, payload?)`
252
412
 
253
413
  Manually capture an error.
254
414
 
255
- | Parameter | Type | Description |
256
- |-----------|------|-------------|
257
- | `error` | `Error \| string` | Error object or message |
258
- | `payload` | `object` | Optional additional data |
259
-
260
415
  ### `blinker.trackPageView(pageName?, payload?)`
261
416
 
262
417
  Track a page view.
263
418
 
264
- | Parameter | Type | Description |
265
- |-----------|------|-------------|
266
- | `pageName` | `string` | Optional page name (defaults to URL path) |
267
- | `payload` | `object` | Optional additional data |
419
+ ### `blinker.identify(userId, traits?)`
420
+
421
+ Identify the current user. Traits are optional metadata about the user.
422
+
423
+ ### `blinker.setContext(key, value)`
424
+
425
+ Set a custom context value that will be included in all events.
426
+
427
+ ### `blinker.getContext()`
428
+
429
+ Get all custom context values. Returns `Record<string, unknown>`.
430
+
431
+ ### `blinker.clearContext()`
432
+
433
+ Clear all user context (use on logout).
434
+
435
+ ### `blinker.getSessionId()`
436
+
437
+ Get current session ID. Returns `string`.
438
+
439
+ ### `blinker.getSession()`
440
+
441
+ Get full session info. Returns `SessionInfo | null`.
442
+
443
+ ```typescript
444
+ interface SessionInfo {
445
+ sessionId: string;
446
+ startTime: number;
447
+ pageViews: number;
448
+ duration: number;
449
+ }
450
+ ```
451
+
452
+ ### `blinker.flush()`
453
+
454
+ Force flush all queued events immediately. Returns `Promise<void>`.
455
+
456
+ ### `blinker.getQueueSize()`
457
+
458
+ Get number of events waiting to be sent. Returns `number`.
268
459
 
269
460
  ### `blinker.isInitialized()`
270
461
 
@@ -274,54 +465,67 @@ Check if SDK is initialized. Returns `boolean`.
274
465
 
275
466
  Get current configuration (without token). Returns config object or `null`.
276
467
 
468
+ ### `blinker.getFilters()`
469
+
470
+ Get current filter settings. Returns `FilterSettings` object.
471
+
277
472
  ### `blinker.destroy()`
278
473
 
279
474
  Remove error handlers and reset SDK state.
280
475
 
281
476
  ## Event Payload
282
477
 
283
- Events sent to the API have the following structure:
478
+ Events sent to the API include:
284
479
 
285
480
  ```json
286
481
  {
287
482
  "type": "error",
288
483
  "message": "Error message",
289
- "payload": {
290
- "custom": "data"
291
- },
484
+ "payload": { "custom": "data" },
292
485
  "timestamp": "2024-01-15T12:00:00.000Z",
293
486
  "url": "https://example.com/page",
294
- "userAgent": "Mozilla/5.0..."
487
+ "userAgent": "Mozilla/5.0...",
488
+ "sessionId": "abc123...",
489
+ "userId": "user-123",
490
+ "userTraits": { "name": "John", "plan": "pro" },
491
+ "context": { "appVersion": "2.1.0" },
492
+ "count": 5
295
493
  }
296
494
  ```
297
495
 
298
496
  ## TypeScript
299
497
 
300
- The SDK is written in TypeScript and includes type definitions.
498
+ The SDK includes full type definitions.
301
499
 
302
500
  ```typescript
303
- import { blinker, BlinkerConfig, BlinkerEvent } from 'blinker-sdk';
501
+ import { blinker, BlinkerConfig, FilterSettings, SessionInfo } from 'blinker-sdk';
304
502
 
305
503
  const config: BlinkerConfig = {
306
504
  token: 'your-token',
307
- api: 'https://api.example.com'
505
+ enableBatching: true,
506
+ sampleRate: 0.5,
507
+ filters: {
508
+ ignoreHttpCodes: [401, 403, 404],
509
+ captureAll: false
510
+ }
308
511
  };
309
512
 
310
513
  blinker.init(config);
514
+
515
+ const filters: FilterSettings = blinker.getFilters();
516
+ const session: SessionInfo | null = blinker.getSession();
311
517
  ```
312
518
 
313
519
  ## Multiple Instances
314
520
 
315
- If you need multiple SDK instances:
316
-
317
521
  ```javascript
318
522
  import { Blinker } from 'blinker-sdk';
319
523
 
320
- const instance1 = new Blinker();
321
- const instance2 = new Blinker();
524
+ const frontendErrors = new Blinker();
525
+ const backendErrors = new Blinker();
322
526
 
323
- instance1.init({ token: 'token1', api: 'https://api1.example.com' });
324
- instance2.init({ token: 'token2', api: 'https://api2.example.com' });
527
+ frontendErrors.init({ token: 'frontend-token' });
528
+ backendErrors.init({ token: 'backend-token' });
325
529
  ```
326
530
 
327
531
  ## Browser Support
@@ -336,4 +540,3 @@ The SDK uses modern JavaScript features (ES2018) including `async/await` and `fe
336
540
  ## License
337
541
 
338
542
  MIT
339
-