@watchupltd/browser 1.0.0 → 1.0.3

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 ADDED
@@ -0,0 +1,280 @@
1
+ # @watchupltd/browser
2
+
3
+ Browser runtime integration for incident tracking in vanilla JavaScript/TypeScript applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @watchupltd/browser
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Setup
14
+
15
+ ```javascript
16
+ import { init } from '@watchupltd/browser';
17
+
18
+ const client = init({
19
+ apiKey: 'your-api-key',
20
+ projectId: 'your-project-id',
21
+ environment: 'production',
22
+ captureConsoleErrors: true // Optional: capture console.error calls
23
+ });
24
+ ```
25
+
26
+ ### Manual Error Capture
27
+
28
+ ```javascript
29
+ try {
30
+ riskyOperation();
31
+ } catch (error) {
32
+ client.captureError(error, {
33
+ tags: { section: 'checkout' },
34
+ extra: { orderId: '12345' }
35
+ });
36
+ }
37
+ ```
38
+
39
+ ### Capture Messages
40
+
41
+ ```javascript
42
+ client.captureMessage('Payment processed successfully', 'info');
43
+ ```
44
+
45
+ ### Set User Context
46
+
47
+ ```javascript
48
+ client.setUser({
49
+ id: 'user-123',
50
+ email: 'user@example.com',
51
+ username: 'john_doe'
52
+ });
53
+ ```
54
+
55
+ ### Add Breadcrumbs
56
+
57
+ ```javascript
58
+ client.addBreadcrumb({
59
+ message: 'User clicked checkout button',
60
+ category: 'user-action',
61
+ level: 'info'
62
+ });
63
+ ```
64
+
65
+ ### Add Tags
66
+
67
+ ```javascript
68
+ client.setTag('version', '1.2.3');
69
+ client.setTags({
70
+ browser: 'chrome',
71
+ os: 'windows'
72
+ });
73
+ ```
74
+
75
+ ## What It Tracks
76
+
77
+ ### Automatic Tracking
78
+
79
+ - **Global JavaScript Errors**: Captures all uncaught errors via `window.onerror`
80
+ - **Unhandled Promise Rejections**: Captures via `window.onunhandledrejection`
81
+ - **Console Errors**: Optionally captures `console.error()` calls
82
+
83
+ ### Manual Tracking
84
+
85
+ - Custom errors via `captureError()`
86
+ - Log messages via `captureMessage()`
87
+ - User actions via `addBreadcrumb()`
88
+
89
+ ## Configuration Options
90
+
91
+ ```typescript
92
+ interface BrowserConfig {
93
+ apiKey: string; // Required: Your API key
94
+ projectId: string; // Required: Your project ID
95
+ endpoint?: string; // Optional: Custom API endpoint
96
+ environment?: string; // Optional: Environment (default: 'production')
97
+ batchInterval?: number; // Optional: Batch interval in ms (default: 5000)
98
+ maxBatchSize?: number; // Optional: Max events per batch (default: 10)
99
+ maxRetries?: number; // Optional: Max retry attempts (default: 3)
100
+ enabled?: boolean; // Optional: Enable/disable SDK (default: true)
101
+ captureConsoleErrors?: boolean; // Optional: Capture console.error (default: false)
102
+ }
103
+ ```
104
+
105
+ ## Data Models
106
+
107
+ ### Event Model
108
+
109
+ ```json
110
+ {
111
+ "id": "550e8400-e29b-41d4-a716-446655440000",
112
+ "project_id": "proj_abc123",
113
+ "fingerprint": "a1b2c3d4e5f6...",
114
+ "title": "ValueError",
115
+ "message": "Invalid user input: expected integer",
116
+ "stack_trace": "Traceback (most recent call last):\n File \"app.py\", line 42...",
117
+ "service": "frontend",
118
+ "environment": "production",
119
+ "severity": "error",
120
+ "timestamp": 1678901234567,
121
+ "platform": "javascript",
122
+ "release": "1.2.3",
123
+ "server_name": "web-app-01",
124
+ "metadata": {
125
+ "custom_key": "custom_value"
126
+ },
127
+ "user": {
128
+ "id": "user-123",
129
+ "email": "user@example.com",
130
+ "username": "john_doe",
131
+ "ip_address": "192.168.1.1"
132
+ },
133
+ "tags": {
134
+ "component": "payment",
135
+ "version": "1.2.3"
136
+ },
137
+ "breadcrumbs": [
138
+ {
139
+ "timestamp": 1678901230000,
140
+ "message": "User logged in",
141
+ "category": "auth",
142
+ "level": "info",
143
+ "data": {}
144
+ }
145
+ ],
146
+ "context": {
147
+ "browser": {
148
+ "name": "Chrome",
149
+ "version": "120.0.0"
150
+ },
151
+ "os": {
152
+ "name": "Windows",
153
+ "version": "10.0"
154
+ }
155
+ }
156
+ }
157
+ ```
158
+
159
+ ### User Model
160
+
161
+ ```json
162
+ {
163
+ "id": "user-123",
164
+ "email": "user@example.com",
165
+ "username": "john_doe",
166
+ "ip_address": "192.168.1.1"
167
+ }
168
+ ```
169
+
170
+ ### Breadcrumb Model
171
+
172
+ ```json
173
+ {
174
+ "timestamp": 1678901234567,
175
+ "message": "User action description",
176
+ "category": "user-action | navigation | http | database | console",
177
+ "level": "fatal | error | warning | info | debug",
178
+ "data": {
179
+ "key": "value"
180
+ }
181
+ }
182
+ ```
183
+
184
+ ## Use Cases
185
+
186
+ Perfect for:
187
+ - Vanilla JavaScript applications
188
+ - TypeScript applications without frameworks
189
+ - Static websites with custom JavaScript
190
+ - Browser extensions
191
+ - Bookmarklets
192
+ - Any web application not using React/Vue/Angular/etc.
193
+
194
+ ## Example: Complete Setup
195
+
196
+ ```html
197
+ <!DOCTYPE html>
198
+ <html>
199
+ <head>
200
+ <title>My App</title>
201
+ </head>
202
+ <body>
203
+ <button id="testBtn">Test Error</button>
204
+
205
+ <script type="module">
206
+ import { init } from '@watchupltd/browser';
207
+
208
+ // Initialize
209
+ const client = init({
210
+ apiKey: 'your-api-key',
211
+ projectId: 'your-project-id',
212
+ environment: 'production',
213
+ captureConsoleErrors: true
214
+ });
215
+
216
+ // Set user context
217
+ client.setUser({
218
+ id: '123',
219
+ email: 'user@example.com'
220
+ });
221
+
222
+ // Add breadcrumb
223
+ client.addBreadcrumb({
224
+ message: 'Page loaded',
225
+ category: 'navigation'
226
+ });
227
+
228
+ // Manual error capture
229
+ document.getElementById('testBtn').addEventListener('click', () => {
230
+ try {
231
+ throw new Error('Test error');
232
+ } catch (error) {
233
+ client.captureError(error, {
234
+ tags: { source: 'button-click' }
235
+ });
236
+ }
237
+ });
238
+ </script>
239
+ </body>
240
+ </html>
241
+ ```
242
+
243
+ ## TypeScript Support
244
+
245
+ Full TypeScript support with type definitions included.
246
+
247
+ ```typescript
248
+ import { init, getClient, IncidentClient } from '@watchupltd/browser';
249
+ import type { BrowserConfig, SeverityLevel } from '@watchupltd/browser';
250
+
251
+ const config: BrowserConfig = {
252
+ apiKey: 'your-api-key',
253
+ projectId: 'your-project-id'
254
+ };
255
+
256
+ const client: IncidentClient = init(config);
257
+ ```
258
+
259
+ ## API Reference
260
+
261
+ ### `init(config: BrowserConfig): IncidentClient`
262
+ Initialize the browser SDK and set up global error handlers.
263
+
264
+ ### `getClient(): IncidentClient | null`
265
+ Get the current client instance.
266
+
267
+ ### `IncidentClient` Methods
268
+
269
+ - `captureError(error: Error, context?: EventContext): Promise<string | null>`
270
+ - `captureMessage(message: string, level?: SeverityLevel, context?: EventContext): Promise<string | null>`
271
+ - `addBreadcrumb(breadcrumb: Breadcrumb): void`
272
+ - `setUser(user: User | null): void`
273
+ - `setTag(key: string, value: string): void`
274
+ - `setTags(tags: Record<string, string>): void`
275
+ - `flush(): Promise<void>`
276
+ - `close(): void`
277
+
278
+ ## License
279
+
280
+ MIT
@@ -0,0 +1,10 @@
1
+ import { IncidentConfig, IncidentClient } from '@watchupltd/core';
2
+ export { Breadcrumb, IncidentClient, IncidentConfig, SeverityLevel, User } from '@watchupltd/core';
3
+
4
+ interface BrowserConfig extends IncidentConfig {
5
+ captureConsoleErrors?: boolean;
6
+ }
7
+ declare function init(config: BrowserConfig): IncidentClient;
8
+ declare function getClient(): IncidentClient | null;
9
+
10
+ export { BrowserConfig, getClient, init };
@@ -0,0 +1,10 @@
1
+ import { IncidentConfig, IncidentClient } from '@watchupltd/core';
2
+ export { Breadcrumb, IncidentClient, IncidentConfig, SeverityLevel, User } from '@watchupltd/core';
3
+
4
+ interface BrowserConfig extends IncidentConfig {
5
+ captureConsoleErrors?: boolean;
6
+ }
7
+ declare function init(config: BrowserConfig): IncidentClient;
8
+ declare function getClient(): IncidentClient | null;
9
+
10
+ export { BrowserConfig, getClient, init };
package/dist/index.js ADDED
@@ -0,0 +1,80 @@
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 src_exports = {};
22
+ __export(src_exports, {
23
+ IncidentClient: () => import_core2.IncidentClient,
24
+ getClient: () => getClient,
25
+ init: () => init
26
+ });
27
+ module.exports = __toCommonJS(src_exports);
28
+ var import_core = require("@watchupltd/core");
29
+ var import_core2 = require("@watchupltd/core");
30
+ var globalClient = null;
31
+ function init(config) {
32
+ if (globalClient) {
33
+ return globalClient;
34
+ }
35
+ globalClient = new import_core.IncidentClient(config);
36
+ if (typeof window !== "undefined") {
37
+ setupGlobalErrorHandlers(globalClient);
38
+ if (config.captureConsoleErrors) {
39
+ setupConsoleCapture(globalClient);
40
+ }
41
+ }
42
+ return globalClient;
43
+ }
44
+ function getClient() {
45
+ return globalClient;
46
+ }
47
+ function setupGlobalErrorHandlers(client) {
48
+ window.addEventListener("error", (event) => {
49
+ const error = event.error || new Error(event.message);
50
+ client.captureError(error, {
51
+ extra: {
52
+ filename: event.filename,
53
+ lineno: event.lineno,
54
+ colno: event.colno
55
+ }
56
+ });
57
+ });
58
+ window.addEventListener("unhandledrejection", (event) => {
59
+ const error = event.reason instanceof Error ? event.reason : new Error(String(event.reason));
60
+ client.captureError(error, {
61
+ tags: { type: "unhandledrejection" }
62
+ });
63
+ });
64
+ }
65
+ function setupConsoleCapture(client) {
66
+ const originalError = console.error;
67
+ console.error = (...args) => {
68
+ originalError.apply(console, args);
69
+ const message = args.map(
70
+ (arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)
71
+ ).join(" ");
72
+ client.captureMessage(message, "error");
73
+ };
74
+ }
75
+ // Annotate the CommonJS export names for ESM import in node:
76
+ 0 && (module.exports = {
77
+ IncidentClient,
78
+ getClient,
79
+ init
80
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,53 @@
1
+ // src/index.ts
2
+ import { IncidentClient } from "@watchupltd/core";
3
+ import { IncidentClient as IncidentClient2 } from "@watchupltd/core";
4
+ var globalClient = null;
5
+ function init(config) {
6
+ if (globalClient) {
7
+ return globalClient;
8
+ }
9
+ globalClient = new IncidentClient(config);
10
+ if (typeof window !== "undefined") {
11
+ setupGlobalErrorHandlers(globalClient);
12
+ if (config.captureConsoleErrors) {
13
+ setupConsoleCapture(globalClient);
14
+ }
15
+ }
16
+ return globalClient;
17
+ }
18
+ function getClient() {
19
+ return globalClient;
20
+ }
21
+ function setupGlobalErrorHandlers(client) {
22
+ window.addEventListener("error", (event) => {
23
+ const error = event.error || new Error(event.message);
24
+ client.captureError(error, {
25
+ extra: {
26
+ filename: event.filename,
27
+ lineno: event.lineno,
28
+ colno: event.colno
29
+ }
30
+ });
31
+ });
32
+ window.addEventListener("unhandledrejection", (event) => {
33
+ const error = event.reason instanceof Error ? event.reason : new Error(String(event.reason));
34
+ client.captureError(error, {
35
+ tags: { type: "unhandledrejection" }
36
+ });
37
+ });
38
+ }
39
+ function setupConsoleCapture(client) {
40
+ const originalError = console.error;
41
+ console.error = (...args) => {
42
+ originalError.apply(console, args);
43
+ const message = args.map(
44
+ (arg) => typeof arg === "object" ? JSON.stringify(arg) : String(arg)
45
+ ).join(" ");
46
+ client.captureMessage(message, "error");
47
+ };
48
+ }
49
+ export {
50
+ IncidentClient2 as IncidentClient,
51
+ getClient,
52
+ init
53
+ };
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@watchupltd/browser",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
7
11
  "exports": {
8
12
  ".": {
9
13
  "import": "./dist/index.mjs",
@@ -12,11 +16,11 @@
12
16
  }
13
17
  },
14
18
  "scripts": {
15
- "build": "tsup src/index.ts --format cjs,esm --dts",
16
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch"
19
+ "build": "tsup src/index.ts --format cjs,esm --dts --external @watchupltd/core --no-splitting",
20
+ "dev": "tsup src/index.ts --format cjs,esm --dts --external @watchupltd/core --no-splitting --watch"
17
21
  },
18
22
  "dependencies": {
19
- "@watchupltd/core": "file:../core"
23
+ "@watchupltd/core": "^1.0.0"
20
24
  },
21
25
  "devDependencies": {
22
26
  "tsup": "^7.0.0",
package/src/index.ts DELETED
@@ -1,70 +0,0 @@
1
- import { IncidentClient } from '@watchupltd/core';
2
- import type { IncidentConfig } from '@watchupltd/core';
3
-
4
- let globalClient: IncidentClient | null = null;
5
-
6
- export interface BrowserConfig extends IncidentConfig {
7
- captureConsoleErrors?: boolean;
8
- }
9
-
10
- export function init(config: BrowserConfig): IncidentClient {
11
- if (globalClient) {
12
- return globalClient;
13
- }
14
-
15
- globalClient = new IncidentClient(config);
16
-
17
- if (typeof window !== 'undefined') {
18
- setupGlobalErrorHandlers(globalClient);
19
-
20
- if (config.captureConsoleErrors) {
21
- setupConsoleCapture(globalClient);
22
- }
23
- }
24
-
25
- return globalClient;
26
- }
27
-
28
- export function getClient(): IncidentClient | null {
29
- return globalClient;
30
- }
31
-
32
- function setupGlobalErrorHandlers(client: IncidentClient): void {
33
- window.addEventListener('error', (event) => {
34
- const error = event.error || new Error(event.message);
35
- client.captureError(error, {
36
- extra: {
37
- filename: event.filename,
38
- lineno: event.lineno,
39
- colno: event.colno
40
- }
41
- });
42
- });
43
-
44
- window.addEventListener('unhandledrejection', (event) => {
45
- const error = event.reason instanceof Error
46
- ? event.reason
47
- : new Error(String(event.reason));
48
-
49
- client.captureError(error, {
50
- tags: { type: 'unhandledrejection' }
51
- });
52
- });
53
- }
54
-
55
- function setupConsoleCapture(client: IncidentClient): void {
56
- const originalError = console.error;
57
-
58
- console.error = (...args: any[]) => {
59
- originalError.apply(console, args);
60
-
61
- const message = args.map(arg =>
62
- typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
63
- ).join(' ');
64
-
65
- client.captureMessage(message, 'error');
66
- };
67
- }
68
-
69
- export { IncidentClient } from '@watchupltd/core';
70
- export type { IncidentConfig, SeverityLevel, User, Breadcrumb } from '@watchupltd/core';
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./src",
6
- "lib": ["ES2020", "DOM"]
7
- },
8
- "include": ["src/**/*"]
9
- }