blinker-sdk 1.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.
- package/README.md +339 -0
- package/dist/Blinker.d.ts +47 -0
- package/dist/Blinker.d.ts.map +1 -0
- package/dist/blinker.min.js +1 -0
- package/dist/errorHandler.d.ts +19 -0
- package/dist/errorHandler.d.ts.map +1 -0
- package/dist/index.cjs.js +313 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +290 -0
- package/dist/sender.d.ts +11 -0
- package/dist/sender.d.ts.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# Blinker SDK
|
|
2
|
+
|
|
3
|
+
Universal JavaScript SDK for error tracking and event capture. Works with **any framework** - React, Vue, Angular, Next.js, or Vanilla JavaScript.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
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
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### npm / yarn / pnpm
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install blinker-sdk
|
|
20
|
+
# or
|
|
21
|
+
yarn add blinker-sdk
|
|
22
|
+
# or
|
|
23
|
+
pnpm add blinker-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### CDN
|
|
27
|
+
|
|
28
|
+
```html
|
|
29
|
+
<script src="https://unpkg.com/blinker-sdk/dist/blinker.min.js"></script>
|
|
30
|
+
<script>
|
|
31
|
+
const { blinker } = BlinkerSDK;
|
|
32
|
+
blinker.init({ token: 'your-token', api: 'https://api.example.com' });
|
|
33
|
+
</script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import { blinker } from 'blinker-sdk';
|
|
40
|
+
|
|
41
|
+
// Initialize the SDK
|
|
42
|
+
blinker.init({
|
|
43
|
+
token: 'your-blinker-token',
|
|
44
|
+
api: 'https://api.example.com'
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// That's it! Errors are now automatically captured.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
### Initialization
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
import { blinker } from 'blinker-sdk';
|
|
56
|
+
|
|
57
|
+
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)
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Track Custom Events
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
// Basic event
|
|
70
|
+
blinker.track('click', 'Button clicked');
|
|
71
|
+
|
|
72
|
+
// Event with payload
|
|
73
|
+
blinker.track('purchase', 'User made a purchase', {
|
|
74
|
+
productId: '12345',
|
|
75
|
+
amount: 99.99,
|
|
76
|
+
currency: 'USD'
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Page view
|
|
80
|
+
blinker.trackPageView();
|
|
81
|
+
|
|
82
|
+
// Page view with custom name
|
|
83
|
+
blinker.trackPageView('Home Page', { section: 'hero' });
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Manual Error Capture
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
try {
|
|
90
|
+
// Your code
|
|
91
|
+
} catch (error) {
|
|
92
|
+
blinker.captureError(error, { context: 'checkout' });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Or with a string
|
|
96
|
+
blinker.captureError('Something went wrong', { userId: '123' });
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Check SDK Status
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
// Check if initialized
|
|
103
|
+
if (blinker.isInitialized()) {
|
|
104
|
+
// SDK is ready
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Get current config (without sensitive data)
|
|
108
|
+
const config = blinker.getConfig();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Cleanup
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
// Remove error handlers and reset SDK
|
|
115
|
+
blinker.destroy();
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Framework Examples
|
|
119
|
+
|
|
120
|
+
### React
|
|
121
|
+
|
|
122
|
+
```jsx
|
|
123
|
+
// app.jsx or index.jsx
|
|
124
|
+
import { blinker } from 'blinker-sdk';
|
|
125
|
+
|
|
126
|
+
blinker.init({
|
|
127
|
+
token: process.env.REACT_APP_BLINKER_TOKEN,
|
|
128
|
+
api: process.env.REACT_APP_BLINKER_API
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
function App() {
|
|
132
|
+
const handleClick = () => {
|
|
133
|
+
blinker.track('click', 'CTA button clicked', { page: 'home' });
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return <button onClick={handleClick}>Click me</button>;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Next.js
|
|
141
|
+
|
|
142
|
+
```jsx
|
|
143
|
+
// app/layout.tsx or pages/_app.tsx
|
|
144
|
+
'use client';
|
|
145
|
+
|
|
146
|
+
import { useEffect } from 'react';
|
|
147
|
+
import { blinker } from 'blinker-sdk';
|
|
148
|
+
|
|
149
|
+
export default function RootLayout({ children }) {
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
blinker.init({
|
|
152
|
+
token: process.env.NEXT_PUBLIC_BLINKER_TOKEN,
|
|
153
|
+
api: process.env.NEXT_PUBLIC_BLINKER_API
|
|
154
|
+
});
|
|
155
|
+
}, []);
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<html>
|
|
159
|
+
<body>{children}</body>
|
|
160
|
+
</html>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Vue.js
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
// main.js
|
|
169
|
+
import { createApp } from 'vue';
|
|
170
|
+
import { blinker } from 'blinker-sdk';
|
|
171
|
+
import App from './App.vue';
|
|
172
|
+
|
|
173
|
+
blinker.init({
|
|
174
|
+
token: import.meta.env.VITE_BLINKER_TOKEN,
|
|
175
|
+
api: import.meta.env.VITE_BLINKER_API
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
createApp(App).mount('#app');
|
|
179
|
+
```
|
|
180
|
+
|
|
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
|
+
### Vanilla JavaScript
|
|
199
|
+
|
|
200
|
+
```html
|
|
201
|
+
<!DOCTYPE html>
|
|
202
|
+
<html>
|
|
203
|
+
<head>
|
|
204
|
+
<script src="https://unpkg.com/blinker-sdk/dist/blinker.min.js"></script>
|
|
205
|
+
</head>
|
|
206
|
+
<body>
|
|
207
|
+
<button id="myButton">Click me</button>
|
|
208
|
+
|
|
209
|
+
<script>
|
|
210
|
+
const { blinker } = BlinkerSDK;
|
|
211
|
+
|
|
212
|
+
blinker.init({
|
|
213
|
+
token: 'your-token',
|
|
214
|
+
api: 'https://api.example.com'
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
document.getElementById('myButton').addEventListener('click', () => {
|
|
218
|
+
blinker.track('click', 'Button clicked');
|
|
219
|
+
});
|
|
220
|
+
</script>
|
|
221
|
+
</body>
|
|
222
|
+
</html>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## API Reference
|
|
226
|
+
|
|
227
|
+
### `blinker.init(config)`
|
|
228
|
+
|
|
229
|
+
Initialize the SDK with configuration options.
|
|
230
|
+
|
|
231
|
+
| Option | Type | Default | Description |
|
|
232
|
+
|--------|------|---------|-------------|
|
|
233
|
+
| `token` | `string` | **required** | Your Blinker API token |
|
|
234
|
+
| `api` | `string` | **required** | API endpoint URL |
|
|
235
|
+
| `captureErrors` | `boolean` | `true` | Auto-capture window errors |
|
|
236
|
+
| `captureRejections` | `boolean` | `true` | Auto-capture unhandled rejections |
|
|
237
|
+
| `debug` | `boolean` | `false` | Enable debug logging |
|
|
238
|
+
|
|
239
|
+
### `blinker.track(type, message, payload?)`
|
|
240
|
+
|
|
241
|
+
Track a custom event.
|
|
242
|
+
|
|
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
|
+
**Returns:** `Promise<{ success: boolean, error?: string }>`
|
|
250
|
+
|
|
251
|
+
### `blinker.captureError(error, payload?)`
|
|
252
|
+
|
|
253
|
+
Manually capture an error.
|
|
254
|
+
|
|
255
|
+
| Parameter | Type | Description |
|
|
256
|
+
|-----------|------|-------------|
|
|
257
|
+
| `error` | `Error \| string` | Error object or message |
|
|
258
|
+
| `payload` | `object` | Optional additional data |
|
|
259
|
+
|
|
260
|
+
### `blinker.trackPageView(pageName?, payload?)`
|
|
261
|
+
|
|
262
|
+
Track a page view.
|
|
263
|
+
|
|
264
|
+
| Parameter | Type | Description |
|
|
265
|
+
|-----------|------|-------------|
|
|
266
|
+
| `pageName` | `string` | Optional page name (defaults to URL path) |
|
|
267
|
+
| `payload` | `object` | Optional additional data |
|
|
268
|
+
|
|
269
|
+
### `blinker.isInitialized()`
|
|
270
|
+
|
|
271
|
+
Check if SDK is initialized. Returns `boolean`.
|
|
272
|
+
|
|
273
|
+
### `blinker.getConfig()`
|
|
274
|
+
|
|
275
|
+
Get current configuration (without token). Returns config object or `null`.
|
|
276
|
+
|
|
277
|
+
### `blinker.destroy()`
|
|
278
|
+
|
|
279
|
+
Remove error handlers and reset SDK state.
|
|
280
|
+
|
|
281
|
+
## Event Payload
|
|
282
|
+
|
|
283
|
+
Events sent to the API have the following structure:
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"type": "error",
|
|
288
|
+
"message": "Error message",
|
|
289
|
+
"payload": {
|
|
290
|
+
"custom": "data"
|
|
291
|
+
},
|
|
292
|
+
"timestamp": "2024-01-15T12:00:00.000Z",
|
|
293
|
+
"url": "https://example.com/page",
|
|
294
|
+
"userAgent": "Mozilla/5.0..."
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## TypeScript
|
|
299
|
+
|
|
300
|
+
The SDK is written in TypeScript and includes type definitions.
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { blinker, BlinkerConfig, BlinkerEvent } from 'blinker-sdk';
|
|
304
|
+
|
|
305
|
+
const config: BlinkerConfig = {
|
|
306
|
+
token: 'your-token',
|
|
307
|
+
api: 'https://api.example.com'
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
blinker.init(config);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Multiple Instances
|
|
314
|
+
|
|
315
|
+
If you need multiple SDK instances:
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
import { Blinker } from 'blinker-sdk';
|
|
319
|
+
|
|
320
|
+
const instance1 = new Blinker();
|
|
321
|
+
const instance2 = new Blinker();
|
|
322
|
+
|
|
323
|
+
instance1.init({ token: 'token1', api: 'https://api1.example.com' });
|
|
324
|
+
instance2.init({ token: 'token2', api: 'https://api2.example.com' });
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Browser Support
|
|
328
|
+
|
|
329
|
+
- Chrome 63+
|
|
330
|
+
- Firefox 67+
|
|
331
|
+
- Safari 12+
|
|
332
|
+
- Edge 79+
|
|
333
|
+
|
|
334
|
+
The SDK uses modern JavaScript features (ES2018) including `async/await` and `fetch`.
|
|
335
|
+
|
|
336
|
+
## License
|
|
337
|
+
|
|
338
|
+
MIT
|
|
339
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blinker SDK Main Class
|
|
3
|
+
* Universal JavaScript SDK for error tracking and event capture
|
|
4
|
+
*/
|
|
5
|
+
import type { BlinkerConfig, SendResult } from './types';
|
|
6
|
+
export declare class Blinker {
|
|
7
|
+
private config;
|
|
8
|
+
private initialized;
|
|
9
|
+
/**
|
|
10
|
+
* Initialize the Blinker SDK
|
|
11
|
+
* @param config Configuration options
|
|
12
|
+
*/
|
|
13
|
+
init(config: BlinkerConfig): void;
|
|
14
|
+
/**
|
|
15
|
+
* Track a custom event
|
|
16
|
+
* @param type Event type (e.g., 'click', 'pageview', 'custom')
|
|
17
|
+
* @param message Event message or description
|
|
18
|
+
* @param payload Optional additional data
|
|
19
|
+
*/
|
|
20
|
+
track(type: string, message: string, payload?: Record<string, unknown>): Promise<SendResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Track an error manually
|
|
23
|
+
* @param error Error object or message
|
|
24
|
+
* @param additionalPayload Optional additional data
|
|
25
|
+
*/
|
|
26
|
+
captureError(error: Error | string, additionalPayload?: Record<string, unknown>): Promise<SendResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Track a page view
|
|
29
|
+
* @param pageName Optional page name (defaults to current URL path)
|
|
30
|
+
* @param additionalPayload Optional additional data
|
|
31
|
+
*/
|
|
32
|
+
trackPageView(pageName?: string, additionalPayload?: Record<string, unknown>): Promise<SendResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Check if SDK is initialized
|
|
35
|
+
*/
|
|
36
|
+
isInitialized(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Get current configuration (without token for security)
|
|
39
|
+
*/
|
|
40
|
+
getConfig(): Omit<BlinkerConfig, 'token'> | null;
|
|
41
|
+
/**
|
|
42
|
+
* Destroy the SDK instance
|
|
43
|
+
* Removes error handlers and resets state
|
|
44
|
+
*/
|
|
45
|
+
destroy(): void;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=Blinker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Blinker.d.ts","sourceRoot":"","sources":["../src/Blinker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAwB,UAAU,EAAE,MAAM,SAAS,CAAC;AAI/E,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,WAAW,CAAkB;IAErC;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IA6CjC;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAoB5F;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAcrG;;;;OAIG;IACH,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IASlG;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,SAAS,IAAI,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG,IAAI;IAOhD;;;OAGG;IACH,OAAO,IAAI,IAAI;CAWhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var BlinkerSDK=(()=>{var w=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var b=(s,e)=>{for(var n in e)w(s,n,{get:e[n],enumerable:!0})},S=(s,e,n,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of B(e))!R.call(s,r)&&r!==n&&w(s,r,{get:()=>e[r],enumerable:!(t=v(e,r))||t.enumerable});return s};var P=s=>S(w({},"__esModule",{value:!0}),s);var O={};b(O,{Blinker:()=>f,blinker:()=>h,default:()=>j});async function y(s,e,n,t=!1){let r=`${s.replace(/\/$/,"")}/events`,l=async()=>{try{let o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json","x-blinker-token":e},body:JSON.stringify({type:n.type,message:n.message,payload:n.payload||{},timestamp:n.timestamp,url:n.url,userAgent:n.userAgent})});if(!o.ok){let i=await o.text().catch(()=>"Unknown error");return t&&console.error(`[Blinker] Failed to send event: ${o.status} - ${i}`),{success:!1,error:`HTTP ${o.status}: ${i}`}}return t&&console.log("[Blinker] Event sent successfully:",n.type),{success:!0}}catch(o){let i=o instanceof Error?o.message:"Unknown error";return t&&console.error("[Blinker] Error sending event:",i),{success:!1,error:i}}},a=await l();return!a.success&&typeof navigator!="undefined"&&!navigator.onLine&&(t&&console.log("[Blinker] Offline, waiting for connection to retry..."),await new Promise(d=>{let p=setTimeout(()=>d(!1),3e4),g=()=>{clearTimeout(p),typeof window!="undefined"&&window.removeEventListener("online",g),d(!0)};typeof window!="undefined"?window.addEventListener("online",g):d(!1)}))?(t&&console.log("[Blinker] Back online, retrying..."),l()):a}var c=null,u=null,k=!1;function m(s,e={}){let{captureErrors:n=!0,captureRejections:t=!0,debug:r=!1}=e;if(k){r&&console.warn("[Blinker] Error handlers already set up");return}if(typeof window=="undefined"){r&&console.log("[Blinker] Not in browser environment, skipping error handlers");return}n&&(c=window.onerror,window.onerror=function(l,a,o,i,d){let p=typeof l=="string"?l:l.type||"Unknown error",g={source:a,lineno:o,colno:i,stack:d==null?void 0:d.stack,errorType:d==null?void 0:d.name};return r&&console.log("[Blinker] Captured error:",p),s("error",p,g),typeof c=="function"?c.call(window,l,a,o,i,d):!1}),t&&(u=window.onunhandledrejection,window.onunhandledrejection=function(l){let a="Unhandled Rejection",o={},i=l.reason;if(i instanceof Error)a=i.message||a,o.stack=i.stack,o.errorType=i.name;else if(typeof i=="string")a=i;else if(i!=null)try{a=JSON.stringify(i)}catch(d){a=String(i)}r&&console.log("[Blinker] Captured unhandled rejection:",a),s("error",a,o),typeof u=="function"&&u.call(window,l)}),k=!0}function E(){typeof window!="undefined"&&(c!==void 0&&(window.onerror=c),u!==void 0&&(window.onunhandledrejection=u),c=null,u=null,k=!1)}var f=class{constructor(){this.config=null;this.initialized=!1}init(e){if(this.initialized){e.debug&&console.warn("[Blinker] SDK already initialized");return}if(!e.token)throw new Error("[Blinker] Token is required");if(!e.api)throw new Error("[Blinker] API endpoint is required");this.config={captureErrors:!0,captureRejections:!0,debug:!1,...e},(this.config.captureErrors||this.config.captureRejections)&&m((n,t,r)=>{this.track(n,t,r)},{captureErrors:this.config.captureErrors,captureRejections:this.config.captureRejections,debug:this.config.debug}),this.initialized=!0,this.config.debug&&console.log("[Blinker] SDK initialized successfully")}track(e,n,t){var l;if(!this.initialized||!this.config)return(l=this.config)!=null&&l.debug&&console.warn("[Blinker] SDK not initialized. Call blinker.init() first."),Promise.resolve({success:!1,error:"SDK not initialized"});let r={type:e,message:n,payload:t,timestamp:new Date().toISOString(),url:typeof window!="undefined"?window.location.href:void 0,userAgent:typeof navigator!="undefined"?navigator.userAgent:void 0};return y(this.config.api,this.config.token,r,this.config.debug)}captureError(e,n){let t=e instanceof Error?e.message:e,r={...n};return e instanceof Error&&(r.stack=e.stack,r.errorType=e.name),this.track("error",t,r)}trackPageView(e,n){let t=e||(typeof window!="undefined"?window.location.pathname:"unknown");return this.track("pageview",t,{...n,referrer:typeof document!="undefined"?document.referrer:void 0})}isInitialized(){return this.initialized}getConfig(){if(!this.config)return null;let{token:e,...n}=this.config;return n}destroy(){var n;let e=(n=this.config)==null?void 0:n.debug;E(),this.config=null,this.initialized=!1,e&&console.log("[Blinker] SDK destroyed")}};var h=new f;var j=h;return P(O);})();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global error handler module
|
|
3
|
+
* Captures window.onerror and unhandledrejection events
|
|
4
|
+
*/
|
|
5
|
+
import type { BlinkerErrorPayload } from './types';
|
|
6
|
+
export type ErrorCallback = (type: string, message: string, payload: BlinkerErrorPayload) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Sets up global error handlers
|
|
9
|
+
*/
|
|
10
|
+
export declare function setupErrorHandlers(callback: ErrorCallback, options?: {
|
|
11
|
+
captureErrors?: boolean;
|
|
12
|
+
captureRejections?: boolean;
|
|
13
|
+
debug?: boolean;
|
|
14
|
+
}): void;
|
|
15
|
+
/**
|
|
16
|
+
* Removes global error handlers and restores originals
|
|
17
|
+
*/
|
|
18
|
+
export declare function teardownErrorHandlers(): void;
|
|
19
|
+
//# sourceMappingURL=errorHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../src/errorHandler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,mBAAmB,KACzB,IAAI,CAAC;AAOV;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,aAAa,EACvB,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACtF,IAAI,CA6FN;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAgB5C"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Blinker: () => Blinker,
|
|
24
|
+
blinker: () => blinker,
|
|
25
|
+
default: () => index_default
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/sender.ts
|
|
30
|
+
async function sendEvent(api, token, event, debug = false) {
|
|
31
|
+
const endpoint = `${api.replace(/\/$/, "")}/events`;
|
|
32
|
+
const sendRequest = async () => {
|
|
33
|
+
try {
|
|
34
|
+
const response = await fetch(endpoint, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
"x-blinker-token": token
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify({
|
|
41
|
+
type: event.type,
|
|
42
|
+
message: event.message,
|
|
43
|
+
payload: event.payload || {},
|
|
44
|
+
timestamp: event.timestamp,
|
|
45
|
+
url: event.url,
|
|
46
|
+
userAgent: event.userAgent
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
51
|
+
if (debug) {
|
|
52
|
+
console.error(`[Blinker] Failed to send event: ${response.status} - ${errorText}`);
|
|
53
|
+
}
|
|
54
|
+
return { success: false, error: `HTTP ${response.status}: ${errorText}` };
|
|
55
|
+
}
|
|
56
|
+
if (debug) {
|
|
57
|
+
console.log(`[Blinker] Event sent successfully:`, event.type);
|
|
58
|
+
}
|
|
59
|
+
return { success: true };
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
62
|
+
if (debug) {
|
|
63
|
+
console.error(`[Blinker] Error sending event:`, errorMessage);
|
|
64
|
+
}
|
|
65
|
+
return { success: false, error: errorMessage };
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const result = await sendRequest();
|
|
69
|
+
if (!result.success && typeof navigator !== "undefined" && !navigator.onLine) {
|
|
70
|
+
if (debug) {
|
|
71
|
+
console.log(`[Blinker] Offline, waiting for connection to retry...`);
|
|
72
|
+
}
|
|
73
|
+
const waitForOnline = new Promise((resolve) => {
|
|
74
|
+
const timeout = setTimeout(() => resolve(false), 3e4);
|
|
75
|
+
const onlineHandler = () => {
|
|
76
|
+
clearTimeout(timeout);
|
|
77
|
+
if (typeof window !== "undefined") {
|
|
78
|
+
window.removeEventListener("online", onlineHandler);
|
|
79
|
+
}
|
|
80
|
+
resolve(true);
|
|
81
|
+
};
|
|
82
|
+
if (typeof window !== "undefined") {
|
|
83
|
+
window.addEventListener("online", onlineHandler);
|
|
84
|
+
} else {
|
|
85
|
+
resolve(false);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
const isOnline = await waitForOnline;
|
|
89
|
+
if (isOnline) {
|
|
90
|
+
if (debug) {
|
|
91
|
+
console.log(`[Blinker] Back online, retrying...`);
|
|
92
|
+
}
|
|
93
|
+
return sendRequest();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/errorHandler.ts
|
|
100
|
+
var originalOnError = null;
|
|
101
|
+
var originalOnUnhandledRejection = null;
|
|
102
|
+
var isSetup = false;
|
|
103
|
+
function setupErrorHandlers(callback, options = {}) {
|
|
104
|
+
const { captureErrors = true, captureRejections = true, debug = false } = options;
|
|
105
|
+
if (isSetup) {
|
|
106
|
+
if (debug) {
|
|
107
|
+
console.warn("[Blinker] Error handlers already set up");
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (typeof window === "undefined") {
|
|
112
|
+
if (debug) {
|
|
113
|
+
console.log("[Blinker] Not in browser environment, skipping error handlers");
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (captureErrors) {
|
|
118
|
+
originalOnError = window.onerror;
|
|
119
|
+
window.onerror = function(message, source, lineno, colno, error) {
|
|
120
|
+
const errorMessage = typeof message === "string" ? message : message.type || "Unknown error";
|
|
121
|
+
const payload = {
|
|
122
|
+
source,
|
|
123
|
+
lineno,
|
|
124
|
+
colno,
|
|
125
|
+
stack: error == null ? void 0 : error.stack,
|
|
126
|
+
errorType: error == null ? void 0 : error.name
|
|
127
|
+
};
|
|
128
|
+
if (debug) {
|
|
129
|
+
console.log("[Blinker] Captured error:", errorMessage);
|
|
130
|
+
}
|
|
131
|
+
callback("error", errorMessage, payload);
|
|
132
|
+
if (typeof originalOnError === "function") {
|
|
133
|
+
return originalOnError.call(window, message, source, lineno, colno, error);
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (captureRejections) {
|
|
139
|
+
originalOnUnhandledRejection = window.onunhandledrejection;
|
|
140
|
+
window.onunhandledrejection = function(event) {
|
|
141
|
+
let message = "Unhandled Rejection";
|
|
142
|
+
const payload = {};
|
|
143
|
+
const reason = event.reason;
|
|
144
|
+
if (reason instanceof Error) {
|
|
145
|
+
message = reason.message || message;
|
|
146
|
+
payload.stack = reason.stack;
|
|
147
|
+
payload.errorType = reason.name;
|
|
148
|
+
} else if (typeof reason === "string") {
|
|
149
|
+
message = reason;
|
|
150
|
+
} else if (reason !== void 0 && reason !== null) {
|
|
151
|
+
try {
|
|
152
|
+
message = JSON.stringify(reason);
|
|
153
|
+
} catch (e) {
|
|
154
|
+
message = String(reason);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (debug) {
|
|
158
|
+
console.log("[Blinker] Captured unhandled rejection:", message);
|
|
159
|
+
}
|
|
160
|
+
callback("error", message, payload);
|
|
161
|
+
if (typeof originalOnUnhandledRejection === "function") {
|
|
162
|
+
originalOnUnhandledRejection.call(window, event);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
isSetup = true;
|
|
167
|
+
}
|
|
168
|
+
function teardownErrorHandlers() {
|
|
169
|
+
if (typeof window === "undefined") {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (originalOnError !== void 0) {
|
|
173
|
+
window.onerror = originalOnError;
|
|
174
|
+
}
|
|
175
|
+
if (originalOnUnhandledRejection !== void 0) {
|
|
176
|
+
window.onunhandledrejection = originalOnUnhandledRejection;
|
|
177
|
+
}
|
|
178
|
+
originalOnError = null;
|
|
179
|
+
originalOnUnhandledRejection = null;
|
|
180
|
+
isSetup = false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/Blinker.ts
|
|
184
|
+
var Blinker = class {
|
|
185
|
+
constructor() {
|
|
186
|
+
this.config = null;
|
|
187
|
+
this.initialized = false;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Initialize the Blinker SDK
|
|
191
|
+
* @param config Configuration options
|
|
192
|
+
*/
|
|
193
|
+
init(config) {
|
|
194
|
+
if (this.initialized) {
|
|
195
|
+
if (config.debug) {
|
|
196
|
+
console.warn("[Blinker] SDK already initialized");
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!config.token) {
|
|
201
|
+
throw new Error("[Blinker] Token is required");
|
|
202
|
+
}
|
|
203
|
+
if (!config.api) {
|
|
204
|
+
throw new Error("[Blinker] API endpoint is required");
|
|
205
|
+
}
|
|
206
|
+
this.config = {
|
|
207
|
+
captureErrors: true,
|
|
208
|
+
captureRejections: true,
|
|
209
|
+
debug: false,
|
|
210
|
+
...config
|
|
211
|
+
};
|
|
212
|
+
if (this.config.captureErrors || this.config.captureRejections) {
|
|
213
|
+
setupErrorHandlers(
|
|
214
|
+
(type, message, payload) => {
|
|
215
|
+
this.track(type, message, payload);
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
captureErrors: this.config.captureErrors,
|
|
219
|
+
captureRejections: this.config.captureRejections,
|
|
220
|
+
debug: this.config.debug
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
this.initialized = true;
|
|
225
|
+
if (this.config.debug) {
|
|
226
|
+
console.log("[Blinker] SDK initialized successfully");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Track a custom event
|
|
231
|
+
* @param type Event type (e.g., 'click', 'pageview', 'custom')
|
|
232
|
+
* @param message Event message or description
|
|
233
|
+
* @param payload Optional additional data
|
|
234
|
+
*/
|
|
235
|
+
track(type, message, payload) {
|
|
236
|
+
var _a;
|
|
237
|
+
if (!this.initialized || !this.config) {
|
|
238
|
+
if ((_a = this.config) == null ? void 0 : _a.debug) {
|
|
239
|
+
console.warn("[Blinker] SDK not initialized. Call blinker.init() first.");
|
|
240
|
+
}
|
|
241
|
+
return Promise.resolve({ success: false, error: "SDK not initialized" });
|
|
242
|
+
}
|
|
243
|
+
const event = {
|
|
244
|
+
type,
|
|
245
|
+
message,
|
|
246
|
+
payload,
|
|
247
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
248
|
+
url: typeof window !== "undefined" ? window.location.href : void 0,
|
|
249
|
+
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0
|
|
250
|
+
};
|
|
251
|
+
return sendEvent(this.config.api, this.config.token, event, this.config.debug);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Track an error manually
|
|
255
|
+
* @param error Error object or message
|
|
256
|
+
* @param additionalPayload Optional additional data
|
|
257
|
+
*/
|
|
258
|
+
captureError(error, additionalPayload) {
|
|
259
|
+
const message = error instanceof Error ? error.message : error;
|
|
260
|
+
const payload = {
|
|
261
|
+
...additionalPayload
|
|
262
|
+
};
|
|
263
|
+
if (error instanceof Error) {
|
|
264
|
+
payload.stack = error.stack;
|
|
265
|
+
payload.errorType = error.name;
|
|
266
|
+
}
|
|
267
|
+
return this.track("error", message, payload);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Track a page view
|
|
271
|
+
* @param pageName Optional page name (defaults to current URL path)
|
|
272
|
+
* @param additionalPayload Optional additional data
|
|
273
|
+
*/
|
|
274
|
+
trackPageView(pageName, additionalPayload) {
|
|
275
|
+
const page = pageName || (typeof window !== "undefined" ? window.location.pathname : "unknown");
|
|
276
|
+
return this.track("pageview", page, {
|
|
277
|
+
...additionalPayload,
|
|
278
|
+
referrer: typeof document !== "undefined" ? document.referrer : void 0
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Check if SDK is initialized
|
|
283
|
+
*/
|
|
284
|
+
isInitialized() {
|
|
285
|
+
return this.initialized;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get current configuration (without token for security)
|
|
289
|
+
*/
|
|
290
|
+
getConfig() {
|
|
291
|
+
if (!this.config) return null;
|
|
292
|
+
const { token: _token, ...safeConfig } = this.config;
|
|
293
|
+
return safeConfig;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Destroy the SDK instance
|
|
297
|
+
* Removes error handlers and resets state
|
|
298
|
+
*/
|
|
299
|
+
destroy() {
|
|
300
|
+
var _a;
|
|
301
|
+
const wasDebug = (_a = this.config) == null ? void 0 : _a.debug;
|
|
302
|
+
teardownErrorHandlers();
|
|
303
|
+
this.config = null;
|
|
304
|
+
this.initialized = false;
|
|
305
|
+
if (wasDebug) {
|
|
306
|
+
console.log("[Blinker] SDK destroyed");
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// src/index.ts
|
|
312
|
+
var blinker = new Blinker();
|
|
313
|
+
var index_default = blinker;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blinker SDK
|
|
3
|
+
* Universal JavaScript SDK for error tracking and event capture
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* import { blinker } from 'blinker-sdk';
|
|
7
|
+
*
|
|
8
|
+
* blinker.init({
|
|
9
|
+
* token: 'your-token',
|
|
10
|
+
* api: 'https://api.blinker.io'
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* // Track custom events
|
|
14
|
+
* blinker.track('click', 'Button clicked', { buttonId: 'submit' });
|
|
15
|
+
*
|
|
16
|
+
* // Track errors manually
|
|
17
|
+
* blinker.captureError(new Error('Something went wrong'));
|
|
18
|
+
*
|
|
19
|
+
* // Track page views
|
|
20
|
+
* blinker.trackPageView();
|
|
21
|
+
*/
|
|
22
|
+
import { Blinker } from './Blinker';
|
|
23
|
+
export type { BlinkerConfig, BlinkerEvent, BlinkerEventInternal, BlinkerErrorPayload, SendResult } from './types';
|
|
24
|
+
export { Blinker };
|
|
25
|
+
declare const blinker: Blinker;
|
|
26
|
+
export { blinker };
|
|
27
|
+
export default blinker;
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,YAAY,EACV,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACX,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,OAAO,EAAE,CAAC;AAGnB,QAAA,MAAM,OAAO,SAAgB,CAAC;AAE9B,OAAO,EAAE,OAAO,EAAE,CAAC;AAGnB,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// src/sender.ts
|
|
2
|
+
async function sendEvent(api, token, event, debug = false) {
|
|
3
|
+
const endpoint = `${api.replace(/\/$/, "")}/events`;
|
|
4
|
+
const sendRequest = async () => {
|
|
5
|
+
try {
|
|
6
|
+
const response = await fetch(endpoint, {
|
|
7
|
+
method: "POST",
|
|
8
|
+
headers: {
|
|
9
|
+
"Content-Type": "application/json",
|
|
10
|
+
"x-blinker-token": token
|
|
11
|
+
},
|
|
12
|
+
body: JSON.stringify({
|
|
13
|
+
type: event.type,
|
|
14
|
+
message: event.message,
|
|
15
|
+
payload: event.payload || {},
|
|
16
|
+
timestamp: event.timestamp,
|
|
17
|
+
url: event.url,
|
|
18
|
+
userAgent: event.userAgent
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
23
|
+
if (debug) {
|
|
24
|
+
console.error(`[Blinker] Failed to send event: ${response.status} - ${errorText}`);
|
|
25
|
+
}
|
|
26
|
+
return { success: false, error: `HTTP ${response.status}: ${errorText}` };
|
|
27
|
+
}
|
|
28
|
+
if (debug) {
|
|
29
|
+
console.log(`[Blinker] Event sent successfully:`, event.type);
|
|
30
|
+
}
|
|
31
|
+
return { success: true };
|
|
32
|
+
} catch (error) {
|
|
33
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
34
|
+
if (debug) {
|
|
35
|
+
console.error(`[Blinker] Error sending event:`, errorMessage);
|
|
36
|
+
}
|
|
37
|
+
return { success: false, error: errorMessage };
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const result = await sendRequest();
|
|
41
|
+
if (!result.success && typeof navigator !== "undefined" && !navigator.onLine) {
|
|
42
|
+
if (debug) {
|
|
43
|
+
console.log(`[Blinker] Offline, waiting for connection to retry...`);
|
|
44
|
+
}
|
|
45
|
+
const waitForOnline = new Promise((resolve) => {
|
|
46
|
+
const timeout = setTimeout(() => resolve(false), 3e4);
|
|
47
|
+
const onlineHandler = () => {
|
|
48
|
+
clearTimeout(timeout);
|
|
49
|
+
if (typeof window !== "undefined") {
|
|
50
|
+
window.removeEventListener("online", onlineHandler);
|
|
51
|
+
}
|
|
52
|
+
resolve(true);
|
|
53
|
+
};
|
|
54
|
+
if (typeof window !== "undefined") {
|
|
55
|
+
window.addEventListener("online", onlineHandler);
|
|
56
|
+
} else {
|
|
57
|
+
resolve(false);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
const isOnline = await waitForOnline;
|
|
61
|
+
if (isOnline) {
|
|
62
|
+
if (debug) {
|
|
63
|
+
console.log(`[Blinker] Back online, retrying...`);
|
|
64
|
+
}
|
|
65
|
+
return sendRequest();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/errorHandler.ts
|
|
72
|
+
var originalOnError = null;
|
|
73
|
+
var originalOnUnhandledRejection = null;
|
|
74
|
+
var isSetup = false;
|
|
75
|
+
function setupErrorHandlers(callback, options = {}) {
|
|
76
|
+
const { captureErrors = true, captureRejections = true, debug = false } = options;
|
|
77
|
+
if (isSetup) {
|
|
78
|
+
if (debug) {
|
|
79
|
+
console.warn("[Blinker] Error handlers already set up");
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (typeof window === "undefined") {
|
|
84
|
+
if (debug) {
|
|
85
|
+
console.log("[Blinker] Not in browser environment, skipping error handlers");
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (captureErrors) {
|
|
90
|
+
originalOnError = window.onerror;
|
|
91
|
+
window.onerror = function(message, source, lineno, colno, error) {
|
|
92
|
+
const errorMessage = typeof message === "string" ? message : message.type || "Unknown error";
|
|
93
|
+
const payload = {
|
|
94
|
+
source,
|
|
95
|
+
lineno,
|
|
96
|
+
colno,
|
|
97
|
+
stack: error == null ? void 0 : error.stack,
|
|
98
|
+
errorType: error == null ? void 0 : error.name
|
|
99
|
+
};
|
|
100
|
+
if (debug) {
|
|
101
|
+
console.log("[Blinker] Captured error:", errorMessage);
|
|
102
|
+
}
|
|
103
|
+
callback("error", errorMessage, payload);
|
|
104
|
+
if (typeof originalOnError === "function") {
|
|
105
|
+
return originalOnError.call(window, message, source, lineno, colno, error);
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (captureRejections) {
|
|
111
|
+
originalOnUnhandledRejection = window.onunhandledrejection;
|
|
112
|
+
window.onunhandledrejection = function(event) {
|
|
113
|
+
let message = "Unhandled Rejection";
|
|
114
|
+
const payload = {};
|
|
115
|
+
const reason = event.reason;
|
|
116
|
+
if (reason instanceof Error) {
|
|
117
|
+
message = reason.message || message;
|
|
118
|
+
payload.stack = reason.stack;
|
|
119
|
+
payload.errorType = reason.name;
|
|
120
|
+
} else if (typeof reason === "string") {
|
|
121
|
+
message = reason;
|
|
122
|
+
} else if (reason !== void 0 && reason !== null) {
|
|
123
|
+
try {
|
|
124
|
+
message = JSON.stringify(reason);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
message = String(reason);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (debug) {
|
|
130
|
+
console.log("[Blinker] Captured unhandled rejection:", message);
|
|
131
|
+
}
|
|
132
|
+
callback("error", message, payload);
|
|
133
|
+
if (typeof originalOnUnhandledRejection === "function") {
|
|
134
|
+
originalOnUnhandledRejection.call(window, event);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
isSetup = true;
|
|
139
|
+
}
|
|
140
|
+
function teardownErrorHandlers() {
|
|
141
|
+
if (typeof window === "undefined") {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (originalOnError !== void 0) {
|
|
145
|
+
window.onerror = originalOnError;
|
|
146
|
+
}
|
|
147
|
+
if (originalOnUnhandledRejection !== void 0) {
|
|
148
|
+
window.onunhandledrejection = originalOnUnhandledRejection;
|
|
149
|
+
}
|
|
150
|
+
originalOnError = null;
|
|
151
|
+
originalOnUnhandledRejection = null;
|
|
152
|
+
isSetup = false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/Blinker.ts
|
|
156
|
+
var Blinker = class {
|
|
157
|
+
constructor() {
|
|
158
|
+
this.config = null;
|
|
159
|
+
this.initialized = false;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Initialize the Blinker SDK
|
|
163
|
+
* @param config Configuration options
|
|
164
|
+
*/
|
|
165
|
+
init(config) {
|
|
166
|
+
if (this.initialized) {
|
|
167
|
+
if (config.debug) {
|
|
168
|
+
console.warn("[Blinker] SDK already initialized");
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (!config.token) {
|
|
173
|
+
throw new Error("[Blinker] Token is required");
|
|
174
|
+
}
|
|
175
|
+
if (!config.api) {
|
|
176
|
+
throw new Error("[Blinker] API endpoint is required");
|
|
177
|
+
}
|
|
178
|
+
this.config = {
|
|
179
|
+
captureErrors: true,
|
|
180
|
+
captureRejections: true,
|
|
181
|
+
debug: false,
|
|
182
|
+
...config
|
|
183
|
+
};
|
|
184
|
+
if (this.config.captureErrors || this.config.captureRejections) {
|
|
185
|
+
setupErrorHandlers(
|
|
186
|
+
(type, message, payload) => {
|
|
187
|
+
this.track(type, message, payload);
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
captureErrors: this.config.captureErrors,
|
|
191
|
+
captureRejections: this.config.captureRejections,
|
|
192
|
+
debug: this.config.debug
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
this.initialized = true;
|
|
197
|
+
if (this.config.debug) {
|
|
198
|
+
console.log("[Blinker] SDK initialized successfully");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Track a custom event
|
|
203
|
+
* @param type Event type (e.g., 'click', 'pageview', 'custom')
|
|
204
|
+
* @param message Event message or description
|
|
205
|
+
* @param payload Optional additional data
|
|
206
|
+
*/
|
|
207
|
+
track(type, message, payload) {
|
|
208
|
+
var _a;
|
|
209
|
+
if (!this.initialized || !this.config) {
|
|
210
|
+
if ((_a = this.config) == null ? void 0 : _a.debug) {
|
|
211
|
+
console.warn("[Blinker] SDK not initialized. Call blinker.init() first.");
|
|
212
|
+
}
|
|
213
|
+
return Promise.resolve({ success: false, error: "SDK not initialized" });
|
|
214
|
+
}
|
|
215
|
+
const event = {
|
|
216
|
+
type,
|
|
217
|
+
message,
|
|
218
|
+
payload,
|
|
219
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
220
|
+
url: typeof window !== "undefined" ? window.location.href : void 0,
|
|
221
|
+
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0
|
|
222
|
+
};
|
|
223
|
+
return sendEvent(this.config.api, this.config.token, event, this.config.debug);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Track an error manually
|
|
227
|
+
* @param error Error object or message
|
|
228
|
+
* @param additionalPayload Optional additional data
|
|
229
|
+
*/
|
|
230
|
+
captureError(error, additionalPayload) {
|
|
231
|
+
const message = error instanceof Error ? error.message : error;
|
|
232
|
+
const payload = {
|
|
233
|
+
...additionalPayload
|
|
234
|
+
};
|
|
235
|
+
if (error instanceof Error) {
|
|
236
|
+
payload.stack = error.stack;
|
|
237
|
+
payload.errorType = error.name;
|
|
238
|
+
}
|
|
239
|
+
return this.track("error", message, payload);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Track a page view
|
|
243
|
+
* @param pageName Optional page name (defaults to current URL path)
|
|
244
|
+
* @param additionalPayload Optional additional data
|
|
245
|
+
*/
|
|
246
|
+
trackPageView(pageName, additionalPayload) {
|
|
247
|
+
const page = pageName || (typeof window !== "undefined" ? window.location.pathname : "unknown");
|
|
248
|
+
return this.track("pageview", page, {
|
|
249
|
+
...additionalPayload,
|
|
250
|
+
referrer: typeof document !== "undefined" ? document.referrer : void 0
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Check if SDK is initialized
|
|
255
|
+
*/
|
|
256
|
+
isInitialized() {
|
|
257
|
+
return this.initialized;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Get current configuration (without token for security)
|
|
261
|
+
*/
|
|
262
|
+
getConfig() {
|
|
263
|
+
if (!this.config) return null;
|
|
264
|
+
const { token: _token, ...safeConfig } = this.config;
|
|
265
|
+
return safeConfig;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Destroy the SDK instance
|
|
269
|
+
* Removes error handlers and resets state
|
|
270
|
+
*/
|
|
271
|
+
destroy() {
|
|
272
|
+
var _a;
|
|
273
|
+
const wasDebug = (_a = this.config) == null ? void 0 : _a.debug;
|
|
274
|
+
teardownErrorHandlers();
|
|
275
|
+
this.config = null;
|
|
276
|
+
this.initialized = false;
|
|
277
|
+
if (wasDebug) {
|
|
278
|
+
console.log("[Blinker] SDK destroyed");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// src/index.ts
|
|
284
|
+
var blinker = new Blinker();
|
|
285
|
+
var index_default = blinker;
|
|
286
|
+
export {
|
|
287
|
+
Blinker,
|
|
288
|
+
blinker,
|
|
289
|
+
index_default as default
|
|
290
|
+
};
|
package/dist/sender.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event sender module
|
|
3
|
+
* Handles sending events to the Blinker API
|
|
4
|
+
*/
|
|
5
|
+
import type { BlinkerEventInternal, SendResult } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Sends an event to the Blinker API
|
|
8
|
+
* Attempts to send once, with a simple retry if offline
|
|
9
|
+
*/
|
|
10
|
+
export declare function sendEvent(api: string, token: string, event: BlinkerEventInternal, debug?: boolean): Promise<SendResult>;
|
|
11
|
+
//# sourceMappingURL=sender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../src/sender.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEhE;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,oBAAoB,EAC3B,KAAK,GAAE,OAAe,GACrB,OAAO,CAAC,UAAU,CAAC,CAiFrB"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blinker SDK Types
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for initializing the Blinker SDK
|
|
6
|
+
*/
|
|
7
|
+
export interface BlinkerConfig {
|
|
8
|
+
/** The authentication token for the Blinker API */
|
|
9
|
+
token: string;
|
|
10
|
+
/** The base URL of the Blinker API endpoint */
|
|
11
|
+
api: string;
|
|
12
|
+
/** Enable automatic error capture (default: true) */
|
|
13
|
+
captureErrors?: boolean;
|
|
14
|
+
/** Enable automatic unhandled rejection capture (default: true) */
|
|
15
|
+
captureRejections?: boolean;
|
|
16
|
+
/** Enable debug mode for logging (default: false) */
|
|
17
|
+
debug?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Event payload to be sent to the Blinker API
|
|
21
|
+
*/
|
|
22
|
+
export interface BlinkerEvent {
|
|
23
|
+
/** Event type (e.g., 'error', 'click', 'pageview', custom types) */
|
|
24
|
+
type: string;
|
|
25
|
+
/** Event message or description */
|
|
26
|
+
message: string;
|
|
27
|
+
/** Additional event data */
|
|
28
|
+
payload?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Internal event with metadata
|
|
32
|
+
*/
|
|
33
|
+
export interface BlinkerEventInternal extends BlinkerEvent {
|
|
34
|
+
/** Timestamp when the event was created */
|
|
35
|
+
timestamp: string;
|
|
36
|
+
/** URL where the event occurred */
|
|
37
|
+
url?: string;
|
|
38
|
+
/** User agent string */
|
|
39
|
+
userAgent?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Error payload structure
|
|
43
|
+
*/
|
|
44
|
+
export interface BlinkerErrorPayload extends Record<string, unknown> {
|
|
45
|
+
/** Error stack trace */
|
|
46
|
+
stack?: string;
|
|
47
|
+
/** Source file where error occurred */
|
|
48
|
+
source?: string;
|
|
49
|
+
/** Line number */
|
|
50
|
+
lineno?: number;
|
|
51
|
+
/** Column number */
|
|
52
|
+
colno?: number;
|
|
53
|
+
/** Original error object type */
|
|
54
|
+
errorType?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Send result status
|
|
58
|
+
*/
|
|
59
|
+
export interface SendResult {
|
|
60
|
+
success: boolean;
|
|
61
|
+
error?: string;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "blinker-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Universal JavaScript SDK for error tracking and event capture - works with any framework",
|
|
5
|
+
"author": "Blinker",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"blinker",
|
|
9
|
+
"error-tracking",
|
|
10
|
+
"analytics",
|
|
11
|
+
"monitoring",
|
|
12
|
+
"javascript",
|
|
13
|
+
"typescript",
|
|
14
|
+
"sdk",
|
|
15
|
+
"universal",
|
|
16
|
+
"react",
|
|
17
|
+
"vue",
|
|
18
|
+
"angular",
|
|
19
|
+
"nextjs"
|
|
20
|
+
],
|
|
21
|
+
"main": "./dist/index.cjs.js",
|
|
22
|
+
"module": "./dist/index.esm.js",
|
|
23
|
+
"browser": "./dist/blinker.min.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"browser": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.esm.js",
|
|
30
|
+
"require": "./dist/index.cjs.js"
|
|
31
|
+
},
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/index.esm.js"
|
|
35
|
+
},
|
|
36
|
+
"require": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"default": "./dist/index.cjs.js"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"README.md"
|
|
45
|
+
],
|
|
46
|
+
"sideEffects": false,
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "npm run build:types && npm run build:esm && npm run build:cjs && npm run build:umd",
|
|
49
|
+
"build:types": "tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
50
|
+
"build:esm": "esbuild src/index.ts --bundle --format=esm --outfile=dist/index.esm.js --target=es2018",
|
|
51
|
+
"build:cjs": "esbuild src/index.ts --bundle --format=cjs --outfile=dist/index.cjs.js --target=es2018",
|
|
52
|
+
"build:umd": "esbuild src/index.ts --bundle --format=iife --global-name=BlinkerSDK --outfile=dist/blinker.min.js --minify --target=es2018",
|
|
53
|
+
"clean": "rm -rf dist",
|
|
54
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
55
|
+
"typecheck": "tsc --noEmit"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"esbuild": "^0.24.0",
|
|
59
|
+
"typescript": "^5.6.0"
|
|
60
|
+
},
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=16.0.0"
|
|
63
|
+
},
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "https://github.com/blinker/blinker-sdk.git"
|
|
67
|
+
},
|
|
68
|
+
"bugs": {
|
|
69
|
+
"url": "https://github.com/blinker/blinker-sdk/issues"
|
|
70
|
+
},
|
|
71
|
+
"homepage": "https://github.com/blinker/blinker-sdk#readme"
|
|
72
|
+
}
|
|
73
|
+
|