@error-explorer/react 1.1.1

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,465 @@
1
+ # @error-explorer/react
2
+
3
+ Official Error Explorer SDK for React. Provides React-specific error handling with ErrorBoundary, hooks, and React Router integration.
4
+
5
+ ## Features
6
+
7
+ - 🛡️ **ErrorBoundary** - Catch and report React component errors
8
+ - 🪝 **React Hooks** - `useErrorExplorer`, `useErrorHandler`, `useUserContext`
9
+ - 🔄 **React Router integration** - Automatic navigation breadcrumbs
10
+ - 📦 **HOC Support** - `withErrorBoundary` for wrapping components
11
+ - 🎯 **Context Provider** - Share SDK instance across your app
12
+ - 📝 **TypeScript** - Full type definitions included
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ # npm
18
+ npm install @error-explorer/react
19
+
20
+ # yarn
21
+ yarn add @error-explorer/react
22
+
23
+ # pnpm
24
+ pnpm add @error-explorer/react
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### Option 1: Provider (Recommended)
30
+
31
+ ```tsx
32
+ import { ErrorExplorerProvider, ErrorBoundary } from '@error-explorer/react';
33
+
34
+ function App() {
35
+ return (
36
+ <ErrorExplorerProvider
37
+ options={{
38
+ token: 'ee_your_project_token',
39
+ project: 'my-react-app',
40
+ environment: 'production',
41
+ }}
42
+ >
43
+ <ErrorBoundary>
44
+ <MainContent />
45
+ </ErrorBoundary>
46
+ </ErrorExplorerProvider>
47
+ );
48
+ }
49
+ ```
50
+
51
+ ### Option 2: Direct Initialization
52
+
53
+ ```tsx
54
+ import { initErrorExplorer, ErrorBoundary } from '@error-explorer/react';
55
+
56
+ // In your entry file (main.tsx or index.tsx)
57
+ initErrorExplorer({
58
+ token: 'ee_your_project_token',
59
+ project: 'my-react-app',
60
+ environment: 'production',
61
+ });
62
+
63
+ function App() {
64
+ return (
65
+ <ErrorBoundary>
66
+ <MainContent />
67
+ </ErrorBoundary>
68
+ );
69
+ }
70
+ ```
71
+
72
+ ## ErrorBoundary
73
+
74
+ Catch errors in component trees and report them to Error Explorer:
75
+
76
+ ```tsx
77
+ import { ErrorBoundary } from '@error-explorer/react';
78
+
79
+ // Basic usage
80
+ <ErrorBoundary>
81
+ <RiskyComponent />
82
+ </ErrorBoundary>
83
+
84
+ // With custom fallback
85
+ <ErrorBoundary
86
+ fallback={<div>Something went wrong</div>}
87
+ >
88
+ <RiskyComponent />
89
+ </ErrorBoundary>
90
+
91
+ // With render prop fallback
92
+ <ErrorBoundary
93
+ fallback={({ error, resetErrorBoundary }) => (
94
+ <div>
95
+ <p>Error: {error.message}</p>
96
+ <button onClick={resetErrorBoundary}>Try again</button>
97
+ </div>
98
+ )}
99
+ >
100
+ <RiskyComponent />
101
+ </ErrorBoundary>
102
+
103
+ // With callbacks and context
104
+ <ErrorBoundary
105
+ onError={(error, errorInfo) => console.log('Caught:', error)}
106
+ onReset={() => console.log('Reset')}
107
+ tags={{ component: 'UserProfile' }}
108
+ context={{ userId: '123' }}
109
+ >
110
+ <UserProfile />
111
+ </ErrorBoundary>
112
+ ```
113
+
114
+ ### ErrorBoundary Props
115
+
116
+ | Prop | Type | Description |
117
+ |------|------|-------------|
118
+ | `children` | ReactNode | Components to wrap |
119
+ | `fallback` | ReactNode \| Function | UI to show on error |
120
+ | `onError` | Function | Called when error is caught |
121
+ | `onReset` | Function | Called when boundary resets |
122
+ | `capture` | boolean | Send to Error Explorer (default: true) |
123
+ | `tags` | Record<string, string> | Additional tags for filtering |
124
+ | `context` | Record<string, unknown> | Extra context data |
125
+ | `resetKeys` | unknown[] | Keys that trigger reset when changed |
126
+
127
+ ## withErrorBoundary HOC
128
+
129
+ Wrap components with error boundary using HOC pattern:
130
+
131
+ ```tsx
132
+ import { withErrorBoundary } from '@error-explorer/react';
133
+
134
+ const SafeComponent = withErrorBoundary(RiskyComponent, {
135
+ fallback: <ErrorFallback />,
136
+ onError: (error) => console.error(error),
137
+ tags: { feature: 'checkout' },
138
+ });
139
+
140
+ // Use it like a normal component
141
+ <SafeComponent userId="123" />
142
+ ```
143
+
144
+ ## Hooks
145
+
146
+ ### useErrorExplorer
147
+
148
+ Access SDK methods from any component:
149
+
150
+ ```tsx
151
+ import { useErrorExplorer } from '@error-explorer/react';
152
+
153
+ function MyComponent() {
154
+ const { captureException, addBreadcrumb, setUser } = useErrorExplorer();
155
+
156
+ const handleClick = async () => {
157
+ try {
158
+ await riskyOperation();
159
+ } catch (error) {
160
+ captureException(error, {
161
+ tags: { action: 'risky_operation' },
162
+ });
163
+ }
164
+ };
165
+
166
+ return <button onClick={handleClick}>Do Something</button>;
167
+ }
168
+ ```
169
+
170
+ ### useErrorHandler
171
+
172
+ Simplified error handling for async operations:
173
+
174
+ ```tsx
175
+ import { useErrorHandler } from '@error-explorer/react';
176
+
177
+ function MyComponent() {
178
+ const { handleError, wrapAsync, tryCatch } = useErrorHandler({
179
+ tags: { component: 'MyComponent' },
180
+ });
181
+
182
+ // Option 1: Wrap async function
183
+ const safeSubmit = wrapAsync(async (data) => {
184
+ await api.submit(data);
185
+ });
186
+
187
+ // Option 2: Manual handling
188
+ const handleClick = async () => {
189
+ try {
190
+ await riskyOperation();
191
+ } catch (error) {
192
+ handleError(error, { extra: { action: 'click' } });
193
+ }
194
+ };
195
+
196
+ // Option 3: Sync try-catch wrapper
197
+ const result = tryCatch(() => JSON.parse(data));
198
+
199
+ return <button onClick={() => safeSubmit({ name: 'test' })}>Submit</button>;
200
+ }
201
+ ```
202
+
203
+ ### useUserContext
204
+
205
+ Manage user context with automatic cleanup:
206
+
207
+ ```tsx
208
+ import { useUserContext } from '@error-explorer/react';
209
+
210
+ function App() {
211
+ const currentUser = useAuth(); // Your auth hook
212
+
213
+ // Automatically sets user context and clears on logout/unmount
214
+ useUserContext(currentUser ? {
215
+ id: currentUser.id,
216
+ email: currentUser.email,
217
+ name: currentUser.name,
218
+ plan: currentUser.plan, // Custom fields allowed
219
+ } : null);
220
+
221
+ return <MainContent />;
222
+ }
223
+ ```
224
+
225
+ ### useActionTracker
226
+
227
+ Track user interactions as breadcrumbs:
228
+
229
+ ```tsx
230
+ import { useActionTracker } from '@error-explorer/react';
231
+
232
+ function CheckoutForm() {
233
+ const { trackAction, trackInteraction } = useActionTracker('CheckoutForm');
234
+
235
+ const handleSubmit = () => {
236
+ trackAction('checkout_submitted', { total: 149.99 });
237
+ // ... submit logic
238
+ };
239
+
240
+ return (
241
+ <form onSubmit={handleSubmit}>
242
+ <input
243
+ onFocus={() => trackInteraction('email-input', 'focus')}
244
+ onBlur={() => trackInteraction('email-input', 'blur')}
245
+ />
246
+ <button onClick={() => trackInteraction('submit-button', 'click')}>
247
+ Pay Now
248
+ </button>
249
+ </form>
250
+ );
251
+ }
252
+ ```
253
+
254
+ ### useComponentBreadcrumbs
255
+
256
+ Track component lifecycle:
257
+
258
+ ```tsx
259
+ import { useComponentBreadcrumbs } from '@error-explorer/react';
260
+
261
+ function UserDashboard() {
262
+ // Adds breadcrumbs for mount/unmount
263
+ useComponentBreadcrumbs('UserDashboard');
264
+
265
+ return <div>Dashboard content</div>;
266
+ }
267
+ ```
268
+
269
+ ### useErrorBoundary
270
+
271
+ Programmatically trigger error boundary from functional components:
272
+
273
+ ```tsx
274
+ import { ErrorBoundary, useErrorBoundary } from '@error-explorer/react';
275
+
276
+ function AsyncComponent() {
277
+ const { showBoundary } = useErrorBoundary();
278
+
279
+ const loadData = async () => {
280
+ try {
281
+ await fetchData();
282
+ } catch (error) {
283
+ showBoundary(error); // Triggers nearest ErrorBoundary
284
+ }
285
+ };
286
+
287
+ return <button onClick={loadData}>Load Data</button>;
288
+ }
289
+
290
+ // Wrap with ErrorBoundary to catch the error
291
+ <ErrorBoundary>
292
+ <AsyncComponent />
293
+ </ErrorBoundary>
294
+ ```
295
+
296
+ ## React Router Integration
297
+
298
+ Track navigation as breadcrumbs:
299
+
300
+ ### Using the Hook (React Router v6+)
301
+
302
+ ```tsx
303
+ import { useLocation } from 'react-router-dom';
304
+ import { useRouterBreadcrumbs } from '@error-explorer/react/router';
305
+
306
+ function App() {
307
+ const location = useLocation();
308
+
309
+ // Track navigation automatically
310
+ useRouterBreadcrumbs(location, {
311
+ trackQuery: false, // Don't include query params (default)
312
+ trackHash: false, // Don't include hash (default)
313
+ });
314
+
315
+ return <Routes>{/* your routes */}</Routes>;
316
+ }
317
+ ```
318
+
319
+ ### Using the Router Subscriber
320
+
321
+ ```tsx
322
+ import { createBrowserRouter } from 'react-router-dom';
323
+ import { createNavigationListener } from '@error-explorer/react/router';
324
+
325
+ const router = createBrowserRouter([/* routes */]);
326
+
327
+ // Subscribe to navigation
328
+ createNavigationListener(router);
329
+
330
+ // In your app
331
+ <RouterProvider router={router} />
332
+ ```
333
+
334
+ ### Using HOC
335
+
336
+ ```tsx
337
+ import { BrowserRouter } from 'react-router-dom';
338
+ import { withRouterTracking } from '@error-explorer/react/router';
339
+
340
+ const TrackedRouter = withRouterTracking(BrowserRouter, {
341
+ trackQuery: true,
342
+ });
343
+
344
+ function App() {
345
+ return (
346
+ <TrackedRouter>
347
+ <Routes>{/* your routes */}</Routes>
348
+ </TrackedRouter>
349
+ );
350
+ }
351
+ ```
352
+
353
+ ## TypeScript Support
354
+
355
+ Full TypeScript support with exported types:
356
+
357
+ ```typescript
358
+ import {
359
+ ErrorBoundary,
360
+ ErrorExplorerProvider,
361
+ useErrorExplorer,
362
+ type ReactErrorExplorerOptions,
363
+ type ErrorBoundaryProps,
364
+ type FallbackProps,
365
+ type ErrorExplorerContextValue,
366
+ } from '@error-explorer/react';
367
+
368
+ // All types are fully typed
369
+ const options: ReactErrorExplorerOptions = {
370
+ token: 'ee_token',
371
+ project: 'my-app',
372
+ environment: 'production',
373
+ };
374
+ ```
375
+
376
+ ## Configuration
377
+
378
+ All configuration options from `@error-explorer/browser` are supported, plus React-specific options:
379
+
380
+ ```tsx
381
+ <ErrorExplorerProvider
382
+ options={{
383
+ // Required
384
+ token: 'ee_your_project_token',
385
+ project: 'my-react-app',
386
+
387
+ // Recommended
388
+ environment: 'production',
389
+ release: '1.0.0',
390
+
391
+ // React-specific
392
+ captureComponentStack: true, // Include React component stack (default: true)
393
+
394
+ // Filtering
395
+ ignoreErrors: [/ResizeObserver/],
396
+
397
+ // Hooks
398
+ beforeSend: (event) => {
399
+ // Modify or filter events
400
+ return event;
401
+ },
402
+ }}
403
+ >
404
+ <App />
405
+ </ErrorExplorerProvider>
406
+ ```
407
+
408
+ ## Best Practices
409
+
410
+ 1. **Wrap at the top level** - Add ErrorBoundary at your app's root
411
+ 2. **Use multiple boundaries** - Add ErrorBoundaries around critical sections
412
+ 3. **Set user context early** - Use `useUserContext` after authentication
413
+ 4. **Track key actions** - Use `useActionTracker` for important user flows
414
+ 5. **Use meaningful tags** - Add tags like `feature`, `component`, `action`
415
+
416
+ ## Example: Complete Setup
417
+
418
+ ```tsx
419
+ // main.tsx
420
+ import React from 'react';
421
+ import ReactDOM from 'react-dom/client';
422
+ import { BrowserRouter } from 'react-router-dom';
423
+ import {
424
+ ErrorExplorerProvider,
425
+ ErrorBoundary,
426
+ } from '@error-explorer/react';
427
+ import App from './App';
428
+
429
+ ReactDOM.createRoot(document.getElementById('root')!).render(
430
+ <React.StrictMode>
431
+ <ErrorExplorerProvider
432
+ options={{
433
+ token: import.meta.env.VITE_ERROR_EXPLORER_TOKEN,
434
+ project: 'my-react-app',
435
+ environment: import.meta.env.MODE,
436
+ release: import.meta.env.VITE_APP_VERSION,
437
+ }}
438
+ >
439
+ <ErrorBoundary
440
+ fallback={({ error, resetErrorBoundary }) => (
441
+ <div className="error-page">
442
+ <h1>Oops! Something went wrong</h1>
443
+ <p>{error.message}</p>
444
+ <button onClick={resetErrorBoundary}>Try again</button>
445
+ </div>
446
+ )}
447
+ >
448
+ <BrowserRouter>
449
+ <App />
450
+ </BrowserRouter>
451
+ </ErrorBoundary>
452
+ </ErrorExplorerProvider>
453
+ </React.StrictMode>
454
+ );
455
+ ```
456
+
457
+ ## Related Packages
458
+
459
+ - `@error-explorer/browser` - Core browser SDK
460
+ - `@error-explorer/vue` - Vue.js SDK
461
+ - `@error-explorer/node` - Node.js SDK
462
+
463
+ ## License
464
+
465
+ MIT