@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.
@@ -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 };
package/dist/router.js ADDED
@@ -0,0 +1,98 @@
1
+ // src/router.tsx
2
+ import { useEffect, useRef } from "react";
3
+ import { ErrorExplorer } from "@error-explorer/browser";
4
+ import { jsx } from "react/jsx-runtime";
5
+ var defaultOptions = {
6
+ trackNavigation: true,
7
+ trackParams: false,
8
+ trackQuery: false,
9
+ trackHash: false
10
+ };
11
+ function useRouterBreadcrumbs(location, options = {}) {
12
+ const opts = { ...defaultOptions, ...options };
13
+ const previousLocation = useRef(null);
14
+ useEffect(() => {
15
+ if (!opts.trackNavigation) return;
16
+ let url = location.pathname;
17
+ if (opts.trackQuery && location.search) {
18
+ url += location.search;
19
+ }
20
+ if (opts.trackHash && location.hash) {
21
+ url += location.hash;
22
+ }
23
+ if (previousLocation.current === url) return;
24
+ const from = previousLocation.current;
25
+ previousLocation.current = url;
26
+ ErrorExplorer.addBreadcrumb({
27
+ type: "navigation",
28
+ category: "navigation",
29
+ message: from ? `Navigated to ${url}` : `Initial page: ${url}`,
30
+ level: "info",
31
+ data: {
32
+ from: from || void 0,
33
+ to: url
34
+ }
35
+ });
36
+ }, [location.pathname, location.search, location.hash, opts]);
37
+ }
38
+ function createNavigationListener(router, options = {}) {
39
+ const opts = { ...defaultOptions, ...options };
40
+ let previousPath = null;
41
+ return router.subscribe((state) => {
42
+ if (!opts.trackNavigation) return;
43
+ const { pathname, search, hash } = state.location;
44
+ let url = pathname;
45
+ if (opts.trackQuery && search) {
46
+ url += search;
47
+ }
48
+ if (opts.trackHash && hash) {
49
+ url += hash;
50
+ }
51
+ if (previousPath === url) return;
52
+ const from = previousPath;
53
+ previousPath = url;
54
+ ErrorExplorer.addBreadcrumb({
55
+ type: "navigation",
56
+ category: "navigation",
57
+ message: from ? `Navigated to ${url}` : `Initial page: ${url}`,
58
+ level: "info",
59
+ data: {
60
+ from: from || void 0,
61
+ to: url
62
+ }
63
+ });
64
+ });
65
+ }
66
+ function withRouterTracking(RouterComponent, options = {}) {
67
+ const Wrapped = (props) => {
68
+ useEffect(() => {
69
+ if (options.trackNavigation !== false) {
70
+ let url = window.location.pathname;
71
+ if (options.trackQuery) {
72
+ url += window.location.search;
73
+ }
74
+ if (options.trackHash) {
75
+ url += window.location.hash;
76
+ }
77
+ ErrorExplorer.addBreadcrumb({
78
+ type: "navigation",
79
+ category: "navigation",
80
+ message: `Initial page: ${url}`,
81
+ level: "info",
82
+ data: {
83
+ to: url
84
+ }
85
+ });
86
+ }
87
+ }, []);
88
+ return /* @__PURE__ */ jsx(RouterComponent, { ...props });
89
+ };
90
+ Wrapped.displayName = `withRouterTracking(${RouterComponent.displayName || RouterComponent.name || "Router"})`;
91
+ return Wrapped;
92
+ }
93
+ export {
94
+ createNavigationListener,
95
+ useRouterBreadcrumbs,
96
+ withRouterTracking
97
+ };
98
+ //# sourceMappingURL=router.js.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":";AAMA,SAAgB,WAAW,cAAc;AACzC,SAAS,qBAAqB;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,mBAAmB,OAAsB,IAAI;AAEnD,YAAU,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,kBAAc,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,kBAAc,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,cAAU,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,sBAAc,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,oBAAC,mBAAiB,GAAG,OAAO;AAAA,EACrC;AAEA,UAAQ,cAAc,sBAAsB,gBAAgB,eAAe,gBAAgB,QAAQ,QAAQ;AAE3G,SAAO;AACT;","names":[]}
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@error-explorer/react",
3
+ "version": "1.1.1",
4
+ "description": "Error Explorer SDK for React - Automatic error tracking with React integration",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./router": {
16
+ "types": "./dist/router.d.ts",
17
+ "import": "./dist/router.js",
18
+ "require": "./dist/router.cjs"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "dev": "tsup --watch",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "test:coverage": "vitest run --coverage",
31
+ "typecheck": "tsc --noEmit",
32
+ "lint": "eslint src --ext .ts,.tsx",
33
+ "clean": "rm -rf dist"
34
+ },
35
+ "peerDependencies": {
36
+ "react": "^18.0.0 || ^19.0.0",
37
+ "react-dom": "^18.0.0 || ^19.0.0",
38
+ "react-router-dom": "^6.0.0 || ^7.0.0"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "react-router-dom": {
42
+ "optional": true
43
+ }
44
+ },
45
+ "dependencies": {
46
+ "@error-explorer/browser": "file:../../core/browser"
47
+ },
48
+ "devDependencies": {
49
+ "@testing-library/jest-dom": "^6.1.0",
50
+ "@testing-library/react": "^14.0.0",
51
+ "@types/node": "^20.10.0",
52
+ "@types/react": "^18.2.0",
53
+ "@types/react-dom": "^18.2.0",
54
+ "happy-dom": "^12.10.0",
55
+ "react": "^18.2.0",
56
+ "react-dom": "^18.2.0",
57
+ "react-router-dom": "^6.20.0",
58
+ "tsup": "^8.0.0",
59
+ "typescript": "^5.3.0",
60
+ "vitest": "^1.0.0"
61
+ },
62
+ "keywords": [
63
+ "error-explorer",
64
+ "react",
65
+ "error-tracking",
66
+ "error-monitoring",
67
+ "error-boundary",
68
+ "breadcrumbs",
69
+ "debugging"
70
+ ],
71
+ "author": "Error Explorer",
72
+ "license": "MIT",
73
+ "repository": {
74
+ "type": "git",
75
+ "url": "https://github.com/Error-Explorer/SDKs.git",
76
+ "directory": "frameworks/react"
77
+ },
78
+ "bugs": {
79
+ "url": "https://github.com/Error-Explorer/SDKs/issues"
80
+ },
81
+ "homepage": "https://github.com/Error-Explorer/SDKs/tree/main/frameworks/react#readme",
82
+ "engines": {
83
+ "node": ">=18.0.0"
84
+ }
85
+ }