@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 +465 -0
- package/dist/index.cjs +424 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +458 -0
- package/dist/index.d.ts +458 -0
- package/dist/index.js +376 -0
- package/dist/index.js.map +1 -0
- package/dist/router.cjs +125 -0
- package/dist/router.cjs.map +1 -0
- package/dist/router.d.cts +106 -0
- package/dist/router.d.ts +106 -0
- package/dist/router.js +98 -0
- package/dist/router.js.map +1 -0
- package/package.json +85 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// src/context.tsx
|
|
2
|
+
import { createContext, useEffect, useState, useMemo } from "react";
|
|
3
|
+
import { ErrorExplorer } from "@error-explorer/browser";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
var ErrorExplorerContext = createContext(null);
|
|
6
|
+
function ErrorExplorerProvider({
|
|
7
|
+
options,
|
|
8
|
+
children
|
|
9
|
+
}) {
|
|
10
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!ErrorExplorer.isInitialized()) {
|
|
13
|
+
ErrorExplorer.init(options);
|
|
14
|
+
setIsInitialized(true);
|
|
15
|
+
} else {
|
|
16
|
+
setIsInitialized(true);
|
|
17
|
+
}
|
|
18
|
+
return () => {
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
const contextValue = useMemo(
|
|
22
|
+
() => ({
|
|
23
|
+
isInitialized,
|
|
24
|
+
captureException: (error, context) => ErrorExplorer.captureException(error, context),
|
|
25
|
+
captureMessage: (message, level) => ErrorExplorer.captureMessage(message, level),
|
|
26
|
+
addBreadcrumb: (breadcrumb) => ErrorExplorer.addBreadcrumb(breadcrumb),
|
|
27
|
+
setUser: (user) => ErrorExplorer.setUser(user),
|
|
28
|
+
clearUser: () => ErrorExplorer.clearUser(),
|
|
29
|
+
setTag: (key, value) => ErrorExplorer.setTag(key, value),
|
|
30
|
+
setTags: (tags) => ErrorExplorer.setTags(tags),
|
|
31
|
+
setExtra: (extra) => ErrorExplorer.setExtra(extra),
|
|
32
|
+
setContext: (name, context) => ErrorExplorer.setContext(name, context),
|
|
33
|
+
flush: (timeout) => ErrorExplorer.flush(timeout),
|
|
34
|
+
close: (timeout) => ErrorExplorer.close(timeout)
|
|
35
|
+
}),
|
|
36
|
+
[isInitialized]
|
|
37
|
+
);
|
|
38
|
+
return /* @__PURE__ */ jsx(ErrorExplorerContext.Provider, { value: contextValue, children });
|
|
39
|
+
}
|
|
40
|
+
function initErrorExplorer(options) {
|
|
41
|
+
if (!ErrorExplorer.isInitialized()) {
|
|
42
|
+
ErrorExplorer.init(options);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/ErrorBoundary.tsx
|
|
47
|
+
import React2, { Component } from "react";
|
|
48
|
+
import { ErrorExplorer as ErrorExplorer2 } from "@error-explorer/browser";
|
|
49
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
50
|
+
var DefaultFallback = ({ error, resetErrorBoundary }) => /* @__PURE__ */ jsxs(
|
|
51
|
+
"div",
|
|
52
|
+
{
|
|
53
|
+
role: "alert",
|
|
54
|
+
style: {
|
|
55
|
+
padding: "20px",
|
|
56
|
+
border: "1px solid #f5c6cb",
|
|
57
|
+
borderRadius: "4px",
|
|
58
|
+
backgroundColor: "#f8d7da",
|
|
59
|
+
color: "#721c24"
|
|
60
|
+
},
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ jsx2("h2", { style: { margin: "0 0 10px 0" }, children: "Something went wrong" }),
|
|
63
|
+
/* @__PURE__ */ jsx2("pre", { style: {
|
|
64
|
+
whiteSpace: "pre-wrap",
|
|
65
|
+
wordBreak: "break-word",
|
|
66
|
+
backgroundColor: "rgba(0,0,0,0.1)",
|
|
67
|
+
padding: "10px",
|
|
68
|
+
borderRadius: "4px",
|
|
69
|
+
fontSize: "14px"
|
|
70
|
+
}, children: error.message }),
|
|
71
|
+
/* @__PURE__ */ jsx2(
|
|
72
|
+
"button",
|
|
73
|
+
{
|
|
74
|
+
onClick: resetErrorBoundary,
|
|
75
|
+
style: {
|
|
76
|
+
marginTop: "10px",
|
|
77
|
+
padding: "8px 16px",
|
|
78
|
+
backgroundColor: "#721c24",
|
|
79
|
+
color: "white",
|
|
80
|
+
border: "none",
|
|
81
|
+
borderRadius: "4px",
|
|
82
|
+
cursor: "pointer"
|
|
83
|
+
},
|
|
84
|
+
children: "Try again"
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
var ErrorBoundary = class extends Component {
|
|
91
|
+
constructor(props) {
|
|
92
|
+
super(props);
|
|
93
|
+
this.reset = () => {
|
|
94
|
+
const { onReset } = this.props;
|
|
95
|
+
this.setState({
|
|
96
|
+
hasError: false,
|
|
97
|
+
error: null,
|
|
98
|
+
errorInfo: null
|
|
99
|
+
});
|
|
100
|
+
if (onReset) {
|
|
101
|
+
onReset();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
this.state = {
|
|
105
|
+
hasError: false,
|
|
106
|
+
error: null,
|
|
107
|
+
errorInfo: null
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
static getDerivedStateFromError(error) {
|
|
111
|
+
return {
|
|
112
|
+
hasError: true,
|
|
113
|
+
error
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
componentDidCatch(error, errorInfo) {
|
|
117
|
+
this.setState({ errorInfo });
|
|
118
|
+
const { capture = true, tags = {}, context = {}, onError } = this.props;
|
|
119
|
+
if (onError) {
|
|
120
|
+
onError(error, errorInfo);
|
|
121
|
+
}
|
|
122
|
+
if (capture) {
|
|
123
|
+
ErrorExplorer2.captureException(error, {
|
|
124
|
+
tags: {
|
|
125
|
+
"react.errorBoundary": "true",
|
|
126
|
+
...tags
|
|
127
|
+
},
|
|
128
|
+
extra: {
|
|
129
|
+
componentStack: errorInfo.componentStack,
|
|
130
|
+
...context
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
componentDidUpdate(prevProps) {
|
|
136
|
+
const { resetKeys } = this.props;
|
|
137
|
+
const { hasError } = this.state;
|
|
138
|
+
if (hasError && resetKeys && prevProps.resetKeys) {
|
|
139
|
+
const hasResetKeyChanged = resetKeys.some(
|
|
140
|
+
(key, index) => key !== prevProps.resetKeys?.[index]
|
|
141
|
+
);
|
|
142
|
+
if (hasResetKeyChanged) {
|
|
143
|
+
this.reset();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
render() {
|
|
148
|
+
const { hasError, error, errorInfo } = this.state;
|
|
149
|
+
const { children, fallback } = this.props;
|
|
150
|
+
if (hasError && error) {
|
|
151
|
+
const fallbackProps = {
|
|
152
|
+
error,
|
|
153
|
+
errorInfo,
|
|
154
|
+
resetErrorBoundary: this.reset
|
|
155
|
+
};
|
|
156
|
+
if (typeof fallback === "function") {
|
|
157
|
+
return fallback(fallbackProps);
|
|
158
|
+
}
|
|
159
|
+
if (fallback) {
|
|
160
|
+
return fallback;
|
|
161
|
+
}
|
|
162
|
+
return /* @__PURE__ */ jsx2(DefaultFallback, { ...fallbackProps });
|
|
163
|
+
}
|
|
164
|
+
return children;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
ErrorBoundary.defaultProps = {
|
|
168
|
+
capture: true,
|
|
169
|
+
tags: {},
|
|
170
|
+
context: {}
|
|
171
|
+
};
|
|
172
|
+
function withErrorBoundary(Component2, options = {}) {
|
|
173
|
+
const { fallback, onError, capture = true, tags = {}, context = {} } = options;
|
|
174
|
+
const Wrapped = (props) => /* @__PURE__ */ jsx2(
|
|
175
|
+
ErrorBoundary,
|
|
176
|
+
{
|
|
177
|
+
fallback,
|
|
178
|
+
onError,
|
|
179
|
+
capture,
|
|
180
|
+
tags,
|
|
181
|
+
context,
|
|
182
|
+
children: /* @__PURE__ */ jsx2(Component2, { ...props })
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
const displayName = Component2.displayName || Component2.name || "Component";
|
|
186
|
+
Wrapped.displayName = `withErrorBoundary(${displayName})`;
|
|
187
|
+
return Wrapped;
|
|
188
|
+
}
|
|
189
|
+
function useErrorBoundary() {
|
|
190
|
+
const [error, setError] = React2.useState(null);
|
|
191
|
+
if (error) {
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
/**
|
|
196
|
+
* Trigger the nearest error boundary with the given error
|
|
197
|
+
*/
|
|
198
|
+
showBoundary: (err) => setError(err),
|
|
199
|
+
/**
|
|
200
|
+
* Reset the error state
|
|
201
|
+
*/
|
|
202
|
+
resetBoundary: () => setError(null)
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/hooks.ts
|
|
207
|
+
import { useContext, useEffect as useEffect2, useCallback, useRef } from "react";
|
|
208
|
+
import { ErrorExplorer as ErrorExplorer3 } from "@error-explorer/browser";
|
|
209
|
+
function useErrorExplorer() {
|
|
210
|
+
const contextValue = useContext(ErrorExplorerContext);
|
|
211
|
+
if (contextValue?.isInitialized) {
|
|
212
|
+
return contextValue;
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
isInitialized: ErrorExplorer3.isInitialized(),
|
|
216
|
+
captureException: (error, context) => ErrorExplorer3.captureException(error, context),
|
|
217
|
+
captureMessage: (message, level) => ErrorExplorer3.captureMessage(message, level),
|
|
218
|
+
addBreadcrumb: (breadcrumb) => ErrorExplorer3.addBreadcrumb(breadcrumb),
|
|
219
|
+
setUser: (user) => ErrorExplorer3.setUser(user),
|
|
220
|
+
clearUser: () => ErrorExplorer3.clearUser(),
|
|
221
|
+
setTag: (key, value) => ErrorExplorer3.setTag(key, value),
|
|
222
|
+
setTags: (tags) => ErrorExplorer3.setTags(tags),
|
|
223
|
+
setExtra: (extra) => ErrorExplorer3.setExtra(extra),
|
|
224
|
+
setContext: (name, context) => ErrorExplorer3.setContext(name, context),
|
|
225
|
+
flush: (timeout) => ErrorExplorer3.flush(timeout),
|
|
226
|
+
close: (timeout) => ErrorExplorer3.close(timeout)
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function useErrorHandler(defaultContext) {
|
|
230
|
+
const { captureException } = useErrorExplorer();
|
|
231
|
+
const handleError = useCallback(
|
|
232
|
+
(error, context) => {
|
|
233
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
234
|
+
captureException(err, {
|
|
235
|
+
...defaultContext,
|
|
236
|
+
...context,
|
|
237
|
+
tags: {
|
|
238
|
+
...defaultContext?.tags,
|
|
239
|
+
...context?.tags
|
|
240
|
+
},
|
|
241
|
+
extra: {
|
|
242
|
+
...defaultContext?.extra,
|
|
243
|
+
...context?.extra
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
return err;
|
|
247
|
+
},
|
|
248
|
+
[captureException, defaultContext]
|
|
249
|
+
);
|
|
250
|
+
const wrapAsync = useCallback(
|
|
251
|
+
(fn, context) => {
|
|
252
|
+
return async (...args) => {
|
|
253
|
+
try {
|
|
254
|
+
return await fn(...args);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
handleError(error, context);
|
|
257
|
+
return void 0;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
[handleError]
|
|
262
|
+
);
|
|
263
|
+
const tryCatch = useCallback(
|
|
264
|
+
(fn, context) => {
|
|
265
|
+
try {
|
|
266
|
+
return fn();
|
|
267
|
+
} catch (error) {
|
|
268
|
+
handleError(error, context);
|
|
269
|
+
return void 0;
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
[handleError]
|
|
273
|
+
);
|
|
274
|
+
return {
|
|
275
|
+
handleError,
|
|
276
|
+
wrapAsync,
|
|
277
|
+
tryCatch
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function useUserContext(user) {
|
|
281
|
+
const { setUser, clearUser } = useErrorExplorer();
|
|
282
|
+
const previousUser = useRef(null);
|
|
283
|
+
useEffect2(() => {
|
|
284
|
+
if (JSON.stringify(user) !== JSON.stringify(previousUser.current)) {
|
|
285
|
+
if (user) {
|
|
286
|
+
setUser(user);
|
|
287
|
+
} else {
|
|
288
|
+
clearUser();
|
|
289
|
+
}
|
|
290
|
+
previousUser.current = user;
|
|
291
|
+
}
|
|
292
|
+
}, [user, setUser, clearUser]);
|
|
293
|
+
useEffect2(() => {
|
|
294
|
+
return () => {
|
|
295
|
+
clearUser();
|
|
296
|
+
};
|
|
297
|
+
}, [clearUser]);
|
|
298
|
+
return { setUser, clearUser };
|
|
299
|
+
}
|
|
300
|
+
function useActionTracker(componentName) {
|
|
301
|
+
const { addBreadcrumb } = useErrorExplorer();
|
|
302
|
+
const trackAction = useCallback(
|
|
303
|
+
(action, data) => {
|
|
304
|
+
addBreadcrumb({
|
|
305
|
+
type: "user-action",
|
|
306
|
+
category: "action",
|
|
307
|
+
message: action,
|
|
308
|
+
level: "info",
|
|
309
|
+
data: {
|
|
310
|
+
component: componentName,
|
|
311
|
+
...data
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
[addBreadcrumb, componentName]
|
|
316
|
+
);
|
|
317
|
+
const trackInteraction = useCallback(
|
|
318
|
+
(element, action, data) => {
|
|
319
|
+
addBreadcrumb({
|
|
320
|
+
type: "user-action",
|
|
321
|
+
category: `ui.${action}`,
|
|
322
|
+
message: `${action} on ${element}`,
|
|
323
|
+
level: "info",
|
|
324
|
+
data: {
|
|
325
|
+
component: componentName,
|
|
326
|
+
element,
|
|
327
|
+
...data
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
},
|
|
331
|
+
[addBreadcrumb, componentName]
|
|
332
|
+
);
|
|
333
|
+
return {
|
|
334
|
+
trackAction,
|
|
335
|
+
trackInteraction
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
function useComponentBreadcrumbs(componentName) {
|
|
339
|
+
const { addBreadcrumb } = useErrorExplorer();
|
|
340
|
+
useEffect2(() => {
|
|
341
|
+
addBreadcrumb({
|
|
342
|
+
type: "debug",
|
|
343
|
+
category: "react.lifecycle",
|
|
344
|
+
message: `${componentName} mounted`,
|
|
345
|
+
level: "debug"
|
|
346
|
+
});
|
|
347
|
+
return () => {
|
|
348
|
+
addBreadcrumb({
|
|
349
|
+
type: "debug",
|
|
350
|
+
category: "react.lifecycle",
|
|
351
|
+
message: `${componentName} unmounted`,
|
|
352
|
+
level: "debug"
|
|
353
|
+
});
|
|
354
|
+
};
|
|
355
|
+
}, [componentName, addBreadcrumb]);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/index.ts
|
|
359
|
+
import { ErrorExplorer as ErrorExplorer4 } from "@error-explorer/browser";
|
|
360
|
+
var src_default = ErrorExplorerProvider;
|
|
361
|
+
export {
|
|
362
|
+
ErrorBoundary,
|
|
363
|
+
ErrorExplorer4 as ErrorExplorer,
|
|
364
|
+
ErrorExplorerContext,
|
|
365
|
+
ErrorExplorerProvider,
|
|
366
|
+
src_default as default,
|
|
367
|
+
initErrorExplorer,
|
|
368
|
+
useActionTracker,
|
|
369
|
+
useComponentBreadcrumbs,
|
|
370
|
+
useErrorBoundary,
|
|
371
|
+
useErrorExplorer,
|
|
372
|
+
useErrorHandler,
|
|
373
|
+
useUserContext,
|
|
374
|
+
withErrorBoundary
|
|
375
|
+
};
|
|
376
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/ErrorBoundary.tsx","../src/hooks.ts","../src/index.ts"],"sourcesContent":["/**\n * React Context Provider for Error Explorer\n */\n\nimport React, { createContext, useEffect, useState, useMemo, type ReactNode } from 'react';\nimport { ErrorExplorer } from '@error-explorer/browser';\nimport type { Breadcrumb, CaptureContext, UserContext } from '@error-explorer/browser';\nimport type { ReactErrorExplorerOptions, ErrorExplorerContextValue } from './types';\n\n/**\n * React Context for Error Explorer\n */\nexport const ErrorExplorerContext = createContext<ErrorExplorerContextValue | null>(null);\n\n/**\n * Error Explorer Provider Component\n *\n * Initializes the Error Explorer SDK and provides context to child components.\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <ErrorExplorerProvider\n * options={{\n * token: 'ee_your_token',\n * project: 'my-react-app',\n * environment: 'production',\n * }}\n * >\n * <MainContent />\n * </ErrorExplorerProvider>\n * );\n * }\n * ```\n */\nexport function ErrorExplorerProvider({\n options,\n children,\n}: {\n options: ReactErrorExplorerOptions;\n children: ReactNode;\n}) {\n const [isInitialized, setIsInitialized] = useState(false);\n\n // Initialize on mount\n useEffect(() => {\n if (!ErrorExplorer.isInitialized()) {\n ErrorExplorer.init(options);\n setIsInitialized(true);\n } else {\n setIsInitialized(true);\n }\n\n // Cleanup on unmount\n return () => {\n // Don't close on unmount as other components might still need it\n // ErrorExplorer.close();\n };\n }, []); // Only run once on mount\n\n // Create stable context value\n const contextValue = useMemo<ErrorExplorerContextValue>(\n () => ({\n isInitialized,\n captureException: (error: Error, context?: CaptureContext) =>\n ErrorExplorer.captureException(error, context),\n captureMessage: (message: string, level?: 'debug' | 'info' | 'warning' | 'error' | 'critical') =>\n ErrorExplorer.captureMessage(message, level),\n addBreadcrumb: (breadcrumb: Breadcrumb) => ErrorExplorer.addBreadcrumb(breadcrumb),\n setUser: (user: UserContext) => ErrorExplorer.setUser(user),\n clearUser: () => ErrorExplorer.clearUser(),\n setTag: (key: string, value: string) => ErrorExplorer.setTag(key, value),\n setTags: (tags: Record<string, string>) => ErrorExplorer.setTags(tags),\n setExtra: (extra: Record<string, unknown>) => ErrorExplorer.setExtra(extra),\n setContext: (name: string, context: Record<string, unknown>) =>\n ErrorExplorer.setContext(name, context),\n flush: (timeout?: number) => ErrorExplorer.flush(timeout),\n close: (timeout?: number) => ErrorExplorer.close(timeout),\n }),\n [isInitialized]\n );\n\n return (\n <ErrorExplorerContext.Provider value={contextValue}>\n {children}\n </ErrorExplorerContext.Provider>\n );\n}\n\n/**\n * Initialize Error Explorer directly (without provider)\n *\n * Use this if you don't need the React Context and just want to initialize\n * the SDK globally.\n *\n * @example\n * ```tsx\n * // In your entry file (main.tsx)\n * import { initErrorExplorer } from '@error-explorer/react';\n *\n * initErrorExplorer({\n * token: 'ee_your_token',\n * project: 'my-react-app',\n * environment: 'production',\n * });\n *\n * ReactDOM.createRoot(root).render(<App />);\n * ```\n */\nexport function initErrorExplorer(options: ReactErrorExplorerOptions): void {\n if (!ErrorExplorer.isInitialized()) {\n ErrorExplorer.init(options);\n }\n}\n","/**\n * ErrorBoundary component for React\n * Catches errors in child components and reports them to Error Explorer\n */\n\nimport React, { Component, type ReactNode, type ComponentType } from 'react';\nimport { ErrorExplorer } from '@error-explorer/browser';\nimport type {\n ErrorBoundaryProps,\n ErrorBoundaryState,\n FallbackProps,\n WithErrorBoundaryOptions,\n} from './types';\n\n/**\n * Default fallback component\n */\nconst DefaultFallback: React.FC<FallbackProps> = ({ error, resetErrorBoundary }) => (\n <div\n role=\"alert\"\n style={{\n padding: '20px',\n border: '1px solid #f5c6cb',\n borderRadius: '4px',\n backgroundColor: '#f8d7da',\n color: '#721c24',\n }}\n >\n <h2 style={{ margin: '0 0 10px 0' }}>Something went wrong</h2>\n <pre style={{\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n backgroundColor: 'rgba(0,0,0,0.1)',\n padding: '10px',\n borderRadius: '4px',\n fontSize: '14px',\n }}>\n {error.message}\n </pre>\n <button\n onClick={resetErrorBoundary}\n style={{\n marginTop: '10px',\n padding: '8px 16px',\n backgroundColor: '#721c24',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n Try again\n </button>\n </div>\n);\n\n/**\n * ErrorBoundary class component\n *\n * React Error Boundaries must be class components - there's no hook equivalent.\n *\n * @example\n * ```tsx\n * <ErrorBoundary fallback={<ErrorFallback />}>\n * <MyComponent />\n * </ErrorBoundary>\n * ```\n *\n * @example\n * With render prop fallback:\n * ```tsx\n * <ErrorBoundary\n * fallback={({ error, resetErrorBoundary }) => (\n * <div>\n * <p>Error: {error.message}</p>\n * <button onClick={resetErrorBoundary}>Retry</button>\n * </div>\n * )}\n * >\n * <MyComponent />\n * </ErrorBoundary>\n * ```\n */\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n static defaultProps = {\n capture: true,\n tags: {},\n context: {},\n };\n\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = {\n hasError: false,\n error: null,\n errorInfo: null,\n };\n }\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return {\n hasError: true,\n error,\n };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.setState({ errorInfo });\n\n const { capture = true, tags = {}, context = {}, onError } = this.props;\n\n // Call user's error handler\n if (onError) {\n onError(error, errorInfo);\n }\n\n // Capture to Error Explorer\n if (capture) {\n ErrorExplorer.captureException(error, {\n tags: {\n 'react.errorBoundary': 'true',\n ...tags,\n },\n extra: {\n componentStack: errorInfo.componentStack,\n ...context,\n },\n });\n }\n }\n\n componentDidUpdate(prevProps: ErrorBoundaryProps): void {\n const { resetKeys } = this.props;\n const { hasError } = this.state;\n\n // Reset if resetKeys changed\n if (hasError && resetKeys && prevProps.resetKeys) {\n const hasResetKeyChanged = resetKeys.some(\n (key, index) => key !== prevProps.resetKeys?.[index]\n );\n\n if (hasResetKeyChanged) {\n this.reset();\n }\n }\n }\n\n reset = (): void => {\n const { onReset } = this.props;\n\n this.setState({\n hasError: false,\n error: null,\n errorInfo: null,\n });\n\n if (onReset) {\n onReset();\n }\n };\n\n render(): ReactNode {\n const { hasError, error, errorInfo } = this.state;\n const { children, fallback } = this.props;\n\n if (hasError && error) {\n const fallbackProps: FallbackProps = {\n error,\n errorInfo,\n resetErrorBoundary: this.reset,\n };\n\n // Render function fallback\n if (typeof fallback === 'function') {\n return fallback(fallbackProps);\n }\n\n // Static fallback\n if (fallback) {\n return fallback;\n }\n\n // Default fallback\n return <DefaultFallback {...fallbackProps} />;\n }\n\n return children;\n }\n}\n\n/**\n * Higher-order component to wrap a component with ErrorBoundary\n *\n * @example\n * ```tsx\n * const SafeComponent = withErrorBoundary(MyComponent, {\n * fallback: <ErrorFallback />,\n * onError: (error) => console.error(error),\n * });\n * ```\n */\nexport function withErrorBoundary<P extends object>(\n Component: ComponentType<P>,\n options: WithErrorBoundaryOptions = {}\n): ComponentType<P> {\n const { fallback, onError, capture = true, tags = {}, context = {} } = options;\n\n const Wrapped: React.FC<P> = (props) => (\n <ErrorBoundary\n fallback={fallback}\n onError={onError}\n capture={capture}\n tags={tags}\n context={context}\n >\n <Component {...props} />\n </ErrorBoundary>\n );\n\n // Preserve display name for debugging\n const displayName = Component.displayName || Component.name || 'Component';\n Wrapped.displayName = `withErrorBoundary(${displayName})`;\n\n return Wrapped;\n}\n\n/**\n * useErrorBoundary hook for functional components\n *\n * Note: This doesn't create an error boundary - those must be class components.\n * Instead, this provides a way to show/trigger the nearest error boundary.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { showBoundary } = useErrorBoundary();\n *\n * const handleClick = async () => {\n * try {\n * await riskyOperation();\n * } catch (error) {\n * showBoundary(error);\n * }\n * };\n * }\n * ```\n */\nexport function useErrorBoundary() {\n const [error, setError] = React.useState<Error | null>(null);\n\n // If there's an error, throw it to be caught by the nearest error boundary\n if (error) {\n throw error;\n }\n\n return {\n /**\n * Trigger the nearest error boundary with the given error\n */\n showBoundary: (err: Error) => setError(err),\n\n /**\n * Reset the error state\n */\n resetBoundary: () => setError(null),\n };\n}\n","/**\n * React Hooks for Error Explorer\n */\n\nimport { useContext, useEffect, useCallback, useRef } from 'react';\nimport { ErrorExplorer } from '@error-explorer/browser';\nimport type { Breadcrumb, CaptureContext, UserContext } from '@error-explorer/browser';\nimport { ErrorExplorerContext } from './context';\n\n/**\n * Use Error Explorer instance\n *\n * Returns the Error Explorer SDK methods for capturing errors and managing context.\n *\n * @example\n * ```tsx\n * const { captureException, addBreadcrumb, setUser } = useErrorExplorer();\n *\n * try {\n * await riskyOperation();\n * } catch (error) {\n * captureException(error);\n * }\n * ```\n */\nexport function useErrorExplorer() {\n // Try to get from context first (if using provider)\n const contextValue = useContext(ErrorExplorerContext);\n\n // If context is available and initialized, use it\n if (contextValue?.isInitialized) {\n return contextValue;\n }\n\n // Fall back to singleton\n return {\n isInitialized: ErrorExplorer.isInitialized(),\n captureException: (error: Error, context?: CaptureContext) =>\n ErrorExplorer.captureException(error, context),\n captureMessage: (message: string, level?: 'debug' | 'info' | 'warning' | 'error' | 'critical') =>\n ErrorExplorer.captureMessage(message, level),\n addBreadcrumb: (breadcrumb: Breadcrumb) => ErrorExplorer.addBreadcrumb(breadcrumb),\n setUser: (user: UserContext) => ErrorExplorer.setUser(user),\n clearUser: () => ErrorExplorer.clearUser(),\n setTag: (key: string, value: string) => ErrorExplorer.setTag(key, value),\n setTags: (tags: Record<string, string>) => ErrorExplorer.setTags(tags),\n setExtra: (extra: Record<string, unknown>) => ErrorExplorer.setExtra(extra),\n setContext: (name: string, context: Record<string, unknown>) =>\n ErrorExplorer.setContext(name, context),\n flush: (timeout?: number) => ErrorExplorer.flush(timeout),\n close: (timeout?: number) => ErrorExplorer.close(timeout),\n };\n}\n\n/**\n * Error handler hook for async operations\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { handleError, wrapAsync } = useErrorHandler();\n *\n * // Option 1: Wrap async function\n * const safeSubmit = wrapAsync(async () => {\n * await api.submit(data);\n * });\n *\n * // Option 2: Manual handling\n * const handleClick = async () => {\n * try {\n * await riskyOperation();\n * } catch (error) {\n * handleError(error, { tags: { operation: 'risky' } });\n * }\n * };\n * }\n * ```\n */\nexport function useErrorHandler(defaultContext?: CaptureContext) {\n const { captureException } = useErrorExplorer();\n\n /**\n * Handle an error with optional context\n */\n const handleError = useCallback(\n (error: unknown, context?: CaptureContext): Error => {\n const err = error instanceof Error ? error : new Error(String(error));\n\n captureException(err, {\n ...defaultContext,\n ...context,\n tags: {\n ...defaultContext?.tags,\n ...context?.tags,\n },\n extra: {\n ...defaultContext?.extra,\n ...context?.extra,\n },\n });\n\n return err;\n },\n [captureException, defaultContext]\n );\n\n /**\n * Wrap an async function with error handling\n */\n const wrapAsync = useCallback(\n <T extends (...args: any[]) => Promise<any>>(\n fn: T,\n context?: CaptureContext\n ): ((...args: Parameters<T>) => Promise<Awaited<ReturnType<T>> | undefined>) => {\n return async (...args: Parameters<T>) => {\n try {\n return await fn(...args);\n } catch (error) {\n handleError(error, context);\n return undefined;\n }\n };\n },\n [handleError]\n );\n\n /**\n * Create a try-catch wrapper that captures errors\n */\n const tryCatch = useCallback(\n <T>(fn: () => T, context?: CaptureContext): T | undefined => {\n try {\n return fn();\n } catch (error) {\n handleError(error, context);\n return undefined;\n }\n },\n [handleError]\n );\n\n return {\n handleError,\n wrapAsync,\n tryCatch,\n };\n}\n\n/**\n * User context hook\n *\n * Sets the user context and cleans up on unmount.\n *\n * @example\n * ```tsx\n * function App() {\n * const user = useCurrentUser();\n *\n * useUserContext(user ? {\n * id: user.id,\n * email: user.email,\n * name: user.name,\n * } : null);\n *\n * return <MainContent />;\n * }\n * ```\n */\nexport function useUserContext(user: UserContext | null) {\n const { setUser, clearUser } = useErrorExplorer();\n const previousUser = useRef<UserContext | null>(null);\n\n useEffect(() => {\n // Only update if user changed\n if (JSON.stringify(user) !== JSON.stringify(previousUser.current)) {\n if (user) {\n setUser(user);\n } else {\n clearUser();\n }\n previousUser.current = user;\n }\n }, [user, setUser, clearUser]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n clearUser();\n };\n }, [clearUser]);\n\n return { setUser, clearUser };\n}\n\n/**\n * Action tracker hook for user interactions\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { trackAction, trackInteraction } = useActionTracker();\n *\n * const handleSubmit = () => {\n * trackAction('form_submitted', { formId: 'contact' });\n * // ... actual submit logic\n * };\n *\n * return (\n * <button\n * onClick={() => {\n * trackInteraction('submit-button', 'click');\n * handleSubmit();\n * }}\n * >\n * Submit\n * </button>\n * );\n * }\n * ```\n */\nexport function useActionTracker(componentName?: string) {\n const { addBreadcrumb } = useErrorExplorer();\n\n /**\n * Track a user action\n */\n const trackAction = useCallback(\n (action: string, data?: Record<string, unknown>) => {\n addBreadcrumb({\n type: 'user-action',\n category: 'action',\n message: action,\n level: 'info',\n data: {\n component: componentName,\n ...data,\n },\n });\n },\n [addBreadcrumb, componentName]\n );\n\n /**\n * Track a UI interaction\n */\n const trackInteraction = useCallback(\n (\n element: string,\n action: 'click' | 'input' | 'focus' | 'blur' | 'submit',\n data?: Record<string, unknown>\n ) => {\n addBreadcrumb({\n type: 'user-action',\n category: `ui.${action}`,\n message: `${action} on ${element}`,\n level: 'info',\n data: {\n component: componentName,\n element,\n ...data,\n },\n });\n },\n [addBreadcrumb, componentName]\n );\n\n return {\n trackAction,\n trackInteraction,\n };\n}\n\n/**\n * Component lifecycle tracking hook\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * useComponentBreadcrumbs('MyComponent');\n *\n * return <div>...</div>;\n * }\n * ```\n */\nexport function useComponentBreadcrumbs(componentName: string) {\n const { addBreadcrumb } = useErrorExplorer();\n\n useEffect(() => {\n addBreadcrumb({\n type: 'debug',\n category: 'react.lifecycle',\n message: `${componentName} mounted`,\n level: 'debug',\n });\n\n return () => {\n addBreadcrumb({\n type: 'debug',\n category: 'react.lifecycle',\n message: `${componentName} unmounted`,\n level: 'debug',\n });\n };\n }, [componentName, addBreadcrumb]);\n}\n","/**\n * @error-explorer/react\n * Error Explorer SDK for React - Automatic error tracking with React integration\n */\n\n// Import for default export\nimport { ErrorExplorerProvider as Provider } from './context';\n\n// Provider and initialization\nexport { ErrorExplorerProvider, ErrorExplorerContext, initErrorExplorer } from './context';\n\n// Error Boundary\nexport { ErrorBoundary, withErrorBoundary, useErrorBoundary } from './ErrorBoundary';\n\n// Hooks\nexport {\n useErrorExplorer,\n useErrorHandler,\n useUserContext,\n useActionTracker,\n useComponentBreadcrumbs,\n} from './hooks';\n\n// Types\nexport type {\n ReactErrorExplorerOptions,\n ReactComponentContext,\n ErrorBoundaryProps,\n ErrorBoundaryState,\n FallbackProps,\n ErrorExplorerProviderProps,\n ErrorExplorerContextValue,\n WithErrorBoundaryOptions,\n InitOptions,\n UserContext,\n Breadcrumb,\n CaptureContext,\n} from './types';\n\n// Re-export ErrorExplorer for direct access\nexport { ErrorExplorer } from '@error-explorer/browser';\n\n// Default export is the provider for convenience\nexport default Provider;\n"],"mappings":"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","names":["React","ErrorExplorer","jsx","Component","useEffect","ErrorExplorer","ErrorExplorer","useEffect","ErrorExplorer"]}
|
package/dist/router.cjs
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
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/router.tsx
|
|
21
|
+
var router_exports = {};
|
|
22
|
+
__export(router_exports, {
|
|
23
|
+
createNavigationListener: () => createNavigationListener,
|
|
24
|
+
useRouterBreadcrumbs: () => useRouterBreadcrumbs,
|
|
25
|
+
withRouterTracking: () => withRouterTracking
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(router_exports);
|
|
28
|
+
var import_react = require("react");
|
|
29
|
+
var import_browser = require("@error-explorer/browser");
|
|
30
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
31
|
+
var defaultOptions = {
|
|
32
|
+
trackNavigation: true,
|
|
33
|
+
trackParams: false,
|
|
34
|
+
trackQuery: false,
|
|
35
|
+
trackHash: false
|
|
36
|
+
};
|
|
37
|
+
function useRouterBreadcrumbs(location, options = {}) {
|
|
38
|
+
const opts = { ...defaultOptions, ...options };
|
|
39
|
+
const previousLocation = (0, import_react.useRef)(null);
|
|
40
|
+
(0, import_react.useEffect)(() => {
|
|
41
|
+
if (!opts.trackNavigation) return;
|
|
42
|
+
let url = location.pathname;
|
|
43
|
+
if (opts.trackQuery && location.search) {
|
|
44
|
+
url += location.search;
|
|
45
|
+
}
|
|
46
|
+
if (opts.trackHash && location.hash) {
|
|
47
|
+
url += location.hash;
|
|
48
|
+
}
|
|
49
|
+
if (previousLocation.current === url) return;
|
|
50
|
+
const from = previousLocation.current;
|
|
51
|
+
previousLocation.current = url;
|
|
52
|
+
import_browser.ErrorExplorer.addBreadcrumb({
|
|
53
|
+
type: "navigation",
|
|
54
|
+
category: "navigation",
|
|
55
|
+
message: from ? `Navigated to ${url}` : `Initial page: ${url}`,
|
|
56
|
+
level: "info",
|
|
57
|
+
data: {
|
|
58
|
+
from: from || void 0,
|
|
59
|
+
to: url
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}, [location.pathname, location.search, location.hash, opts]);
|
|
63
|
+
}
|
|
64
|
+
function createNavigationListener(router, options = {}) {
|
|
65
|
+
const opts = { ...defaultOptions, ...options };
|
|
66
|
+
let previousPath = null;
|
|
67
|
+
return router.subscribe((state) => {
|
|
68
|
+
if (!opts.trackNavigation) return;
|
|
69
|
+
const { pathname, search, hash } = state.location;
|
|
70
|
+
let url = pathname;
|
|
71
|
+
if (opts.trackQuery && search) {
|
|
72
|
+
url += search;
|
|
73
|
+
}
|
|
74
|
+
if (opts.trackHash && hash) {
|
|
75
|
+
url += hash;
|
|
76
|
+
}
|
|
77
|
+
if (previousPath === url) return;
|
|
78
|
+
const from = previousPath;
|
|
79
|
+
previousPath = url;
|
|
80
|
+
import_browser.ErrorExplorer.addBreadcrumb({
|
|
81
|
+
type: "navigation",
|
|
82
|
+
category: "navigation",
|
|
83
|
+
message: from ? `Navigated to ${url}` : `Initial page: ${url}`,
|
|
84
|
+
level: "info",
|
|
85
|
+
data: {
|
|
86
|
+
from: from || void 0,
|
|
87
|
+
to: url
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function withRouterTracking(RouterComponent, options = {}) {
|
|
93
|
+
const Wrapped = (props) => {
|
|
94
|
+
(0, import_react.useEffect)(() => {
|
|
95
|
+
if (options.trackNavigation !== false) {
|
|
96
|
+
let url = window.location.pathname;
|
|
97
|
+
if (options.trackQuery) {
|
|
98
|
+
url += window.location.search;
|
|
99
|
+
}
|
|
100
|
+
if (options.trackHash) {
|
|
101
|
+
url += window.location.hash;
|
|
102
|
+
}
|
|
103
|
+
import_browser.ErrorExplorer.addBreadcrumb({
|
|
104
|
+
type: "navigation",
|
|
105
|
+
category: "navigation",
|
|
106
|
+
message: `Initial page: ${url}`,
|
|
107
|
+
level: "info",
|
|
108
|
+
data: {
|
|
109
|
+
to: url
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}, []);
|
|
114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RouterComponent, { ...props });
|
|
115
|
+
};
|
|
116
|
+
Wrapped.displayName = `withRouterTracking(${RouterComponent.displayName || RouterComponent.name || "Router"})`;
|
|
117
|
+
return Wrapped;
|
|
118
|
+
}
|
|
119
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
120
|
+
0 && (module.exports = {
|
|
121
|
+
createNavigationListener,
|
|
122
|
+
useRouterBreadcrumbs,
|
|
123
|
+
withRouterTracking
|
|
124
|
+
});
|
|
125
|
+
//# sourceMappingURL=router.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router.tsx"],"sourcesContent":["/**\n * React Router integration for Error Explorer\n *\n * Tracks navigation events as breadcrumbs.\n */\n\nimport React, { useEffect, useRef } from 'react';\nimport { ErrorExplorer } from '@error-explorer/browser';\n\n/**\n * Router integration options\n */\nexport interface RouterIntegrationOptions {\n /**\n * Track navigation events as breadcrumbs\n * @default true\n */\n trackNavigation?: boolean;\n\n /**\n * Include URL parameters in breadcrumbs\n * @default false (for privacy)\n */\n trackParams?: boolean;\n\n /**\n * Include query string in breadcrumbs\n * @default false (for privacy)\n */\n trackQuery?: boolean;\n\n /**\n * Include hash in breadcrumbs\n * @default false\n */\n trackHash?: boolean;\n}\n\nconst defaultOptions: Required<RouterIntegrationOptions> = {\n trackNavigation: true,\n trackParams: false,\n trackQuery: false,\n trackHash: false,\n};\n\n/**\n * Hook to track React Router navigation\n *\n * Compatible with React Router v6+\n *\n * @example\n * ```tsx\n * import { useLocation } from 'react-router-dom';\n * import { useRouterBreadcrumbs } from '@error-explorer/react/router';\n *\n * function App() {\n * const location = useLocation();\n * useRouterBreadcrumbs(location);\n *\n * return <Routes>...</Routes>;\n * }\n * ```\n */\nexport function useRouterBreadcrumbs(\n location: { pathname: string; search?: string; hash?: string },\n options: RouterIntegrationOptions = {}\n) {\n const opts = { ...defaultOptions, ...options };\n const previousLocation = useRef<string | null>(null);\n\n useEffect(() => {\n if (!opts.trackNavigation) return;\n\n // Build the URL to track\n let url = location.pathname;\n if (opts.trackQuery && location.search) {\n url += location.search;\n }\n if (opts.trackHash && location.hash) {\n url += location.hash;\n }\n\n // Skip if same as previous\n if (previousLocation.current === url) return;\n\n const from = previousLocation.current;\n previousLocation.current = url;\n\n // Add breadcrumb\n ErrorExplorer.addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: from ? `Navigated to ${url}` : `Initial page: ${url}`,\n level: 'info',\n data: {\n from: from || undefined,\n to: url,\n },\n });\n }, [location.pathname, location.search, location.hash, opts]);\n}\n\n/**\n * Create a navigation listener for React Router\n *\n * Use this with the router's subscribe/listen functionality.\n *\n * @example\n * ```tsx\n * import { createBrowserRouter } from 'react-router-dom';\n * import { createNavigationListener } from '@error-explorer/react/router';\n *\n * const router = createBrowserRouter([...routes]);\n * const unsubscribe = createNavigationListener(router);\n *\n * // Cleanup when needed\n * // unsubscribe();\n * ```\n */\nexport function createNavigationListener(\n router: { subscribe: (callback: (state: { location: { pathname: string; search: string; hash: string } }) => void) => () => void },\n options: RouterIntegrationOptions = {}\n): () => void {\n const opts = { ...defaultOptions, ...options };\n let previousPath: string | null = null;\n\n return router.subscribe((state) => {\n if (!opts.trackNavigation) return;\n\n const { pathname, search, hash } = state.location;\n\n // Build the URL to track\n let url = pathname;\n if (opts.trackQuery && search) {\n url += search;\n }\n if (opts.trackHash && hash) {\n url += hash;\n }\n\n // Skip if same as previous\n if (previousPath === url) return;\n\n const from = previousPath;\n previousPath = url;\n\n ErrorExplorer.addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: from ? `Navigated to ${url}` : `Initial page: ${url}`,\n level: 'info',\n data: {\n from: from || undefined,\n to: url,\n },\n });\n });\n}\n\n/**\n * Higher-order component to wrap router with breadcrumb tracking\n *\n * @example\n * ```tsx\n * import { BrowserRouter } from 'react-router-dom';\n * import { withRouterTracking } from '@error-explorer/react/router';\n *\n * const TrackedRouter = withRouterTracking(BrowserRouter);\n *\n * function App() {\n * return (\n * <TrackedRouter>\n * <Routes>...</Routes>\n * </TrackedRouter>\n * );\n * }\n * ```\n */\nexport function withRouterTracking<P extends object>(\n RouterComponent: React.ComponentType<P>,\n options: RouterIntegrationOptions = {}\n): React.FC<P & { children?: React.ReactNode }> {\n const Wrapped: React.FC<P & { children?: React.ReactNode }> = (props) => {\n // Track initial page load\n useEffect(() => {\n if (options.trackNavigation !== false) {\n let url = window.location.pathname;\n if (options.trackQuery) {\n url += window.location.search;\n }\n if (options.trackHash) {\n url += window.location.hash;\n }\n\n ErrorExplorer.addBreadcrumb({\n type: 'navigation',\n category: 'navigation',\n message: `Initial page: ${url}`,\n level: 'info',\n data: {\n to: url,\n },\n });\n }\n }, []);\n\n return <RouterComponent {...props} />;\n };\n\n Wrapped.displayName = `withRouterTracking(${RouterComponent.displayName || RouterComponent.name || 'Router'})`;\n\n return Wrapped;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,mBAAyC;AACzC,qBAA8B;AAuMnB;AAxKX,IAAM,iBAAqD;AAAA,EACzD,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,WAAW;AACb;AAoBO,SAAS,qBACd,UACA,UAAoC,CAAC,GACrC;AACA,QAAM,OAAO,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AAC7C,QAAM,uBAAmB,qBAAsB,IAAI;AAEnD,8BAAU,MAAM;AACd,QAAI,CAAC,KAAK,gBAAiB;AAG3B,QAAI,MAAM,SAAS;AACnB,QAAI,KAAK,cAAc,SAAS,QAAQ;AACtC,aAAO,SAAS;AAAA,IAClB;AACA,QAAI,KAAK,aAAa,SAAS,MAAM;AACnC,aAAO,SAAS;AAAA,IAClB;AAGA,QAAI,iBAAiB,YAAY,IAAK;AAEtC,UAAM,OAAO,iBAAiB;AAC9B,qBAAiB,UAAU;AAG3B,iCAAc,cAAc;AAAA,MAC1B,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS,OAAO,gBAAgB,GAAG,KAAK,iBAAiB,GAAG;AAAA,MAC5D,OAAO;AAAA,MACP,MAAM;AAAA,QACJ,MAAM,QAAQ;AAAA,QACd,IAAI;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,SAAS,UAAU,SAAS,QAAQ,SAAS,MAAM,IAAI,CAAC;AAC9D;AAmBO,SAAS,yBACd,QACA,UAAoC,CAAC,GACzB;AACZ,QAAM,OAAO,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AAC7C,MAAI,eAA8B;AAElC,SAAO,OAAO,UAAU,CAAC,UAAU;AACjC,QAAI,CAAC,KAAK,gBAAiB;AAE3B,UAAM,EAAE,UAAU,QAAQ,KAAK,IAAI,MAAM;AAGzC,QAAI,MAAM;AACV,QAAI,KAAK,cAAc,QAAQ;AAC7B,aAAO;AAAA,IACT;AACA,QAAI,KAAK,aAAa,MAAM;AAC1B,aAAO;AAAA,IACT;AAGA,QAAI,iBAAiB,IAAK;AAE1B,UAAM,OAAO;AACb,mBAAe;AAEf,iCAAc,cAAc;AAAA,MAC1B,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS,OAAO,gBAAgB,GAAG,KAAK,iBAAiB,GAAG;AAAA,MAC5D,OAAO;AAAA,MACP,MAAM;AAAA,QACJ,MAAM,QAAQ;AAAA,QACd,IAAI;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAqBO,SAAS,mBACd,iBACA,UAAoC,CAAC,GACS;AAC9C,QAAM,UAAwD,CAAC,UAAU;AAEvE,gCAAU,MAAM;AACd,UAAI,QAAQ,oBAAoB,OAAO;AACrC,YAAI,MAAM,OAAO,SAAS;AAC1B,YAAI,QAAQ,YAAY;AACtB,iBAAO,OAAO,SAAS;AAAA,QACzB;AACA,YAAI,QAAQ,WAAW;AACrB,iBAAO,OAAO,SAAS;AAAA,QACzB;AAEA,qCAAc,cAAc;AAAA,UAC1B,MAAM;AAAA,UACN,UAAU;AAAA,UACV,SAAS,iBAAiB,GAAG;AAAA,UAC7B,OAAO;AAAA,UACP,MAAM;AAAA,YACJ,IAAI;AAAA,UACN;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,GAAG,CAAC,CAAC;AAEL,WAAO,4CAAC,mBAAiB,GAAG,OAAO;AAAA,EACrC;AAEA,UAAQ,cAAc,sBAAsB,gBAAgB,eAAe,gBAAgB,QAAQ,QAAQ;AAE3G,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* React Router integration for Error Explorer
|
|
5
|
+
*
|
|
6
|
+
* Tracks navigation events as breadcrumbs.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Router integration options
|
|
11
|
+
*/
|
|
12
|
+
interface RouterIntegrationOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Track navigation events as breadcrumbs
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
trackNavigation?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Include URL parameters in breadcrumbs
|
|
20
|
+
* @default false (for privacy)
|
|
21
|
+
*/
|
|
22
|
+
trackParams?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Include query string in breadcrumbs
|
|
25
|
+
* @default false (for privacy)
|
|
26
|
+
*/
|
|
27
|
+
trackQuery?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Include hash in breadcrumbs
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
trackHash?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Hook to track React Router navigation
|
|
36
|
+
*
|
|
37
|
+
* Compatible with React Router v6+
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* import { useLocation } from 'react-router-dom';
|
|
42
|
+
* import { useRouterBreadcrumbs } from '@error-explorer/react/router';
|
|
43
|
+
*
|
|
44
|
+
* function App() {
|
|
45
|
+
* const location = useLocation();
|
|
46
|
+
* useRouterBreadcrumbs(location);
|
|
47
|
+
*
|
|
48
|
+
* return <Routes>...</Routes>;
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function useRouterBreadcrumbs(location: {
|
|
53
|
+
pathname: string;
|
|
54
|
+
search?: string;
|
|
55
|
+
hash?: string;
|
|
56
|
+
}, options?: RouterIntegrationOptions): void;
|
|
57
|
+
/**
|
|
58
|
+
* Create a navigation listener for React Router
|
|
59
|
+
*
|
|
60
|
+
* Use this with the router's subscribe/listen functionality.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* import { createBrowserRouter } from 'react-router-dom';
|
|
65
|
+
* import { createNavigationListener } from '@error-explorer/react/router';
|
|
66
|
+
*
|
|
67
|
+
* const router = createBrowserRouter([...routes]);
|
|
68
|
+
* const unsubscribe = createNavigationListener(router);
|
|
69
|
+
*
|
|
70
|
+
* // Cleanup when needed
|
|
71
|
+
* // unsubscribe();
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare function createNavigationListener(router: {
|
|
75
|
+
subscribe: (callback: (state: {
|
|
76
|
+
location: {
|
|
77
|
+
pathname: string;
|
|
78
|
+
search: string;
|
|
79
|
+
hash: string;
|
|
80
|
+
};
|
|
81
|
+
}) => void) => () => void;
|
|
82
|
+
}, options?: RouterIntegrationOptions): () => void;
|
|
83
|
+
/**
|
|
84
|
+
* Higher-order component to wrap router with breadcrumb tracking
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```tsx
|
|
88
|
+
* import { BrowserRouter } from 'react-router-dom';
|
|
89
|
+
* import { withRouterTracking } from '@error-explorer/react/router';
|
|
90
|
+
*
|
|
91
|
+
* const TrackedRouter = withRouterTracking(BrowserRouter);
|
|
92
|
+
*
|
|
93
|
+
* function App() {
|
|
94
|
+
* return (
|
|
95
|
+
* <TrackedRouter>
|
|
96
|
+
* <Routes>...</Routes>
|
|
97
|
+
* </TrackedRouter>
|
|
98
|
+
* );
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare function withRouterTracking<P extends object>(RouterComponent: React.ComponentType<P>, options?: RouterIntegrationOptions): React.FC<P & {
|
|
103
|
+
children?: React.ReactNode;
|
|
104
|
+
}>;
|
|
105
|
+
|
|
106
|
+
export { type RouterIntegrationOptions, createNavigationListener, useRouterBreadcrumbs, withRouterTracking };
|