@open-kingdom/shared-frontend-feature-error-autologger 0.0.2-14 → 0.0.2-16
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 +148 -3
- package/dist/index.js +55 -60
- package/dist/lib/middlewares/rtk-error.middleware.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,7 +1,152 @@
|
|
|
1
1
|
# @open-kingdom/shared-frontend-feature-error-autologger
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React feature library that automatically captures uncaught errors, unhandled promise rejections, and RTK Query rejected actions, routing them to configurable logger and notification callbacks.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Exports
|
|
8
|
+
|
|
9
|
+
| Export | Type | Description |
|
|
10
|
+
| ------------------------------- | ------------------ | --------------------------------------------------------------------------------------------- |
|
|
11
|
+
| `ErrorBoundary` | `class Component` | React error boundary — catches render errors and calls logger/notification handlers |
|
|
12
|
+
| `useGlobalErrorListener` | hook | Attaches `window.error` and `unhandledrejection` listeners on mount; cleans up on unmount |
|
|
13
|
+
| `useErrorReporter` | hook | Returns a stable `report(error, options?)` function for manual error reporting |
|
|
14
|
+
| `createReduxRTKErrorMiddleware` | middleware factory | Redux middleware that intercepts `/rejected` RTK actions and dispatches Redux action creators |
|
|
15
|
+
| `createRTKErrorMiddleware` | middleware factory | Redux middleware variant that calls plain callbacks instead of dispatching action creators |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
### `ErrorBoundaryProps`
|
|
22
|
+
|
|
23
|
+
| Property | Type | Required | Default | Description |
|
|
24
|
+
| --------------------- | ---------------------------------------------- | -------- | ------------------------------------------- | ------------------------------------------------------- |
|
|
25
|
+
| `children` | `ReactNode` | Yes | — | Content to render |
|
|
26
|
+
| `fallback` | `ReactNode \| ((error: Error) => ReactNode)` | No | — | Rendered when an error is caught; accepts a render prop |
|
|
27
|
+
| `logger` | `(message: string) => void` | No | — | Called with the error message on catch |
|
|
28
|
+
| `notificationHandler` | `(message: string) => void` | No | — | Called with the user-facing message on catch |
|
|
29
|
+
| `userMessage` | `string` | No | `'Something went wrong. Please try again.'` | Message passed to `notificationHandler` |
|
|
30
|
+
| `notify` | `boolean` | No | `true` | Whether to call `notificationHandler` |
|
|
31
|
+
| `log` | `boolean` | No | `true` | Whether to call `logger` |
|
|
32
|
+
| `onError` | `(error: Error, errorInfo: ErrorInfo) => void` | No | — | Additional callback after the error is reported |
|
|
33
|
+
|
|
34
|
+
### `ErrorListenerConfig` (for `useGlobalErrorListener`)
|
|
35
|
+
|
|
36
|
+
| Property | Type | Required | Default | Description |
|
|
37
|
+
| --------------------- | --------------------------- | -------- | -------------------------------- | -------------------------------------- |
|
|
38
|
+
| `logger` | `(message: string) => void` | No | — | Called with the error message |
|
|
39
|
+
| `notificationHandler` | `(message: string) => void` | No | — | Called with the user-facing message |
|
|
40
|
+
| `notify` | `boolean` | No | `true` | Whether to call `notificationHandler` |
|
|
41
|
+
| `log` | `boolean` | No | `true` | Whether to call `logger` |
|
|
42
|
+
| `defaultMessage` | `string` | No | `'An unexpected error occurred'` | Fallback when the error has no message |
|
|
43
|
+
|
|
44
|
+
### `HandleErrorOptions` (per-call options for `useErrorReporter`)
|
|
45
|
+
|
|
46
|
+
| Property | Type | Required | Default | Description |
|
|
47
|
+
| ------------- | ------------------------- | -------- | ------- | ---------------------------------------- |
|
|
48
|
+
| `notify` | `boolean` | No | `true` | Whether to call `notificationHandler` |
|
|
49
|
+
| `log` | `boolean` | No | `true` | Whether to call `logger` |
|
|
50
|
+
| `userMessage` | `string` | No | — | Override the user-facing message |
|
|
51
|
+
| `context` | `Record<string, unknown>` | No | — | Additional context attached to the error |
|
|
52
|
+
|
|
53
|
+
### `ReduxRTKErrorMiddlewareConfig` (for `createReduxRTKErrorMiddleware`)
|
|
54
|
+
|
|
55
|
+
| Property | Type | Required | Default | Description |
|
|
56
|
+
| ---------------- | ---------------------------------------------------------- | -------- | ------- | ------------------------------------------------------ |
|
|
57
|
+
| `logAction` | `(payload: { message: string; level: 'error' }) => Action` | Yes | — | Action creator dispatched for logging |
|
|
58
|
+
| `notifyAction` | `(message: string) => Action` | Yes | — | Action creator dispatched for notifications |
|
|
59
|
+
| `notify` | `boolean` | No | `true` | Whether to dispatch `notifyAction` |
|
|
60
|
+
| `log` | `boolean` | No | `true` | Whether to dispatch `logAction` |
|
|
61
|
+
| `defaultMessage` | `string` | No | — | Fallback message for errors without one |
|
|
62
|
+
| `shouldHandle` | `(action: unknown) => boolean` | No | — | Predicate to filter which rejected actions are handled |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
### ErrorBoundary
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { ErrorBoundary } from '@open-kingdom/shared-frontend-feature-error-autologger';
|
|
72
|
+
|
|
73
|
+
function App() {
|
|
74
|
+
const dispatch = useDispatch();
|
|
75
|
+
return (
|
|
76
|
+
<ErrorBoundary logger={(msg) => dispatch(logError(msg))} notificationHandler={(msg) => dispatch(showErrorNotification(msg))} fallback={(error) => <div>Something went wrong: {error.message}</div>}>
|
|
77
|
+
<YourAppContent />
|
|
78
|
+
</ErrorBoundary>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### useGlobalErrorListener
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { useGlobalErrorListener } from '@open-kingdom/shared-frontend-feature-error-autologger';
|
|
87
|
+
|
|
88
|
+
function AppRoot() {
|
|
89
|
+
const dispatch = useDispatch();
|
|
90
|
+
useGlobalErrorListener({
|
|
91
|
+
logger: (msg) => dispatch(logError(msg)),
|
|
92
|
+
notificationHandler: (msg) => dispatch(showErrorNotification(msg)),
|
|
93
|
+
});
|
|
94
|
+
return <App />;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### useErrorReporter
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { useErrorReporter } from '@open-kingdom/shared-frontend-feature-error-autologger';
|
|
102
|
+
|
|
103
|
+
function DataFetcher() {
|
|
104
|
+
const dispatch = useDispatch();
|
|
105
|
+
const report = useErrorReporter({
|
|
106
|
+
logger: (msg) => dispatch(logError(msg)),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const fetchData = async () => {
|
|
110
|
+
try {
|
|
111
|
+
await api.getData();
|
|
112
|
+
} catch (err) {
|
|
113
|
+
report(err, { notify: false, context: { component: 'DataFetcher' } });
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### createReduxRTKErrorMiddleware (recommended for Redux apps)
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { createReduxRTKErrorMiddleware } from '@open-kingdom/shared-frontend-feature-error-autologger';
|
|
123
|
+
|
|
124
|
+
configureStore({
|
|
125
|
+
middleware: (getDefault) =>
|
|
126
|
+
getDefault().concat(
|
|
127
|
+
createReduxRTKErrorMiddleware({
|
|
128
|
+
logAction: ({ message }) => logError(message),
|
|
129
|
+
notifyAction: (message) => showErrorNotification(message),
|
|
130
|
+
})
|
|
131
|
+
),
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### createRTKErrorMiddleware (callback-based)
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { createRTKErrorMiddleware } from '@open-kingdom/shared-frontend-feature-error-autologger';
|
|
139
|
+
|
|
140
|
+
const middleware = createRTKErrorMiddleware({
|
|
141
|
+
logger: (msg) => console.error('[RTK Error]', msg),
|
|
142
|
+
notificationHandler: (msg) => alert(msg),
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Testing
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
nx test shared-frontend-feature-error-autologger
|
|
152
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Component as
|
|
2
|
-
class
|
|
1
|
+
import { Component as p, useMemo as h, useCallback as m, useEffect as y } from "react";
|
|
2
|
+
class E {
|
|
3
3
|
adapt(e, r) {
|
|
4
4
|
return e instanceof Error ? {
|
|
5
5
|
message: e.message,
|
|
@@ -60,27 +60,27 @@ class M {
|
|
|
60
60
|
return "Request failed";
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
const
|
|
64
|
-
class
|
|
63
|
+
const w = (n) => console.error("[Error]", n), M = (n) => console.warn("[Notification]", n);
|
|
64
|
+
class c {
|
|
65
65
|
logger;
|
|
66
66
|
notificationHandler;
|
|
67
67
|
adapter;
|
|
68
68
|
constructor(e = {}) {
|
|
69
|
-
this.logger = e.logger ??
|
|
69
|
+
this.logger = e.logger ?? w, this.notificationHandler = e.notificationHandler ?? M, this.adapter = e.adapter ?? new E();
|
|
70
70
|
}
|
|
71
71
|
report(e, r = {}) {
|
|
72
|
-
const { notify: t = !0, log: o = !0, userMessage: i, context:
|
|
72
|
+
const { notify: t = !0, log: o = !0, userMessage: i, context: a } = r, l = this.adapter.adapt(e, a), s = i || l.message;
|
|
73
73
|
if (o) {
|
|
74
|
-
const
|
|
75
|
-
this.logger(
|
|
74
|
+
const u = a ? `${l.message} | Context: ${JSON.stringify(a)}` : l.message;
|
|
75
|
+
this.logger(u);
|
|
76
76
|
}
|
|
77
|
-
t && this.notificationHandler(
|
|
77
|
+
t && this.notificationHandler(s);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
class
|
|
80
|
+
class b extends p {
|
|
81
81
|
reporter;
|
|
82
82
|
constructor(e) {
|
|
83
|
-
super(e), this.state = { hasError: !1, error: null }, this.reporter = new
|
|
83
|
+
super(e), this.state = { hasError: !1, error: null }, this.reporter = new c({
|
|
84
84
|
logger: e.logger,
|
|
85
85
|
notificationHandler: e.notificationHandler
|
|
86
86
|
});
|
|
@@ -96,11 +96,11 @@ class A extends m {
|
|
|
96
96
|
onError: t,
|
|
97
97
|
userMessage: o = "Something went wrong. Please try again.",
|
|
98
98
|
notify: i = !0,
|
|
99
|
-
log:
|
|
99
|
+
log: a = !0
|
|
100
100
|
} = this.props;
|
|
101
101
|
this.reporter.report(e, {
|
|
102
102
|
notify: i,
|
|
103
|
-
log:
|
|
103
|
+
log: a,
|
|
104
104
|
userMessage: o,
|
|
105
105
|
context: {
|
|
106
106
|
type: "error-boundary",
|
|
@@ -113,17 +113,17 @@ class A extends m {
|
|
|
113
113
|
return e && r ? typeof o == "function" ? o(r) : o ?? null : t;
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
function
|
|
117
|
-
const { logger: e, notificationHandler: r, adapter: t } = n, o =
|
|
118
|
-
() => new
|
|
116
|
+
function x(n = {}) {
|
|
117
|
+
const { logger: e, notificationHandler: r, adapter: t } = n, o = h(
|
|
118
|
+
() => new c({ logger: e, notificationHandler: r, adapter: t }),
|
|
119
119
|
[e, r, t]
|
|
120
120
|
);
|
|
121
|
-
return
|
|
122
|
-
(i,
|
|
121
|
+
return m(
|
|
122
|
+
(i, a = {}) => o.report(i, a),
|
|
123
123
|
[o]
|
|
124
124
|
);
|
|
125
125
|
}
|
|
126
|
-
class
|
|
126
|
+
class j {
|
|
127
127
|
reporter;
|
|
128
128
|
notify;
|
|
129
129
|
log;
|
|
@@ -134,9 +134,9 @@ class b {
|
|
|
134
134
|
notificationHandler: t,
|
|
135
135
|
notify: o = !0,
|
|
136
136
|
log: i = !0,
|
|
137
|
-
defaultMessage:
|
|
137
|
+
defaultMessage: a = "An unexpected error occurred"
|
|
138
138
|
} = e;
|
|
139
|
-
this.reporter = new
|
|
139
|
+
this.reporter = new c({ logger: r, notificationHandler: t }), this.notify = o, this.log = i, this.defaultMessage = a;
|
|
140
140
|
}
|
|
141
141
|
attach() {
|
|
142
142
|
const e = (t) => {
|
|
@@ -164,8 +164,8 @@ class b {
|
|
|
164
164
|
};
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
|
-
function
|
|
168
|
-
|
|
167
|
+
function k(n = {}) {
|
|
168
|
+
y(() => new j(n).attach(), [
|
|
169
169
|
n.logger,
|
|
170
170
|
n.notificationHandler,
|
|
171
171
|
n.notify,
|
|
@@ -173,20 +173,19 @@ function S(n = {}) {
|
|
|
173
173
|
n.defaultMessage
|
|
174
174
|
]);
|
|
175
175
|
}
|
|
176
|
-
|
|
177
|
-
function f(n) {
|
|
176
|
+
function g(n) {
|
|
178
177
|
if (typeof n != "object" || n === null)
|
|
179
178
|
return !1;
|
|
180
179
|
const e = n;
|
|
181
180
|
return typeof e.type == "string" && (e.type.endsWith("/rejected") || e.meta?.rejectedWithValue === !0);
|
|
182
181
|
}
|
|
183
|
-
function
|
|
182
|
+
function d(n) {
|
|
184
183
|
return {
|
|
185
184
|
type: "rtk-query",
|
|
186
185
|
endpoint: n.meta?.arg?.endpointName || "unknown"
|
|
187
186
|
};
|
|
188
187
|
}
|
|
189
|
-
function
|
|
188
|
+
function f(n) {
|
|
190
189
|
return n.payload || n.error;
|
|
191
190
|
}
|
|
192
191
|
function R(n = {}) {
|
|
@@ -195,59 +194,55 @@ function R(n = {}) {
|
|
|
195
194
|
notificationHandler: r,
|
|
196
195
|
notify: t = !0,
|
|
197
196
|
log: o = !0,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
u.report(h(a), {
|
|
197
|
+
shouldHandle: i
|
|
198
|
+
} = n, a = new c({ logger: e, notificationHandler: r });
|
|
199
|
+
return () => (l) => (s) => {
|
|
200
|
+
if (g(s)) {
|
|
201
|
+
if (i && !i(s))
|
|
202
|
+
return l(s);
|
|
203
|
+
a.report(f(s), {
|
|
206
204
|
notify: t,
|
|
207
205
|
log: o,
|
|
208
|
-
|
|
209
|
-
context: p(a)
|
|
206
|
+
context: d(s)
|
|
210
207
|
});
|
|
211
208
|
}
|
|
212
|
-
return l(
|
|
209
|
+
return l(s);
|
|
213
210
|
};
|
|
214
211
|
}
|
|
215
|
-
function
|
|
212
|
+
function A(n) {
|
|
216
213
|
const {
|
|
217
214
|
logAction: e,
|
|
218
215
|
notifyAction: r,
|
|
219
216
|
notify: t = !0,
|
|
220
217
|
log: o = !0,
|
|
221
|
-
|
|
222
|
-
shouldHandle: s
|
|
218
|
+
shouldHandle: i
|
|
223
219
|
} = n;
|
|
224
|
-
return ({ dispatch:
|
|
225
|
-
const l = new
|
|
226
|
-
logger: (
|
|
227
|
-
notificationHandler: (
|
|
220
|
+
return ({ dispatch: a }) => {
|
|
221
|
+
const l = new c({
|
|
222
|
+
logger: (s) => a(e({ message: s, level: "error" })),
|
|
223
|
+
notificationHandler: (s) => a(r(s))
|
|
228
224
|
});
|
|
229
|
-
return (
|
|
230
|
-
if (
|
|
231
|
-
if (
|
|
232
|
-
return
|
|
233
|
-
l.report(
|
|
225
|
+
return (s) => (u) => {
|
|
226
|
+
if (g(u)) {
|
|
227
|
+
if (i && !i(u))
|
|
228
|
+
return s(u);
|
|
229
|
+
l.report(f(u), {
|
|
234
230
|
notify: t,
|
|
235
231
|
log: o,
|
|
236
|
-
|
|
237
|
-
context: p(c)
|
|
232
|
+
context: d(u)
|
|
238
233
|
});
|
|
239
234
|
}
|
|
240
|
-
return
|
|
235
|
+
return s(u);
|
|
241
236
|
};
|
|
242
237
|
};
|
|
243
238
|
}
|
|
244
239
|
export {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
240
|
+
E as ErrorAdapter,
|
|
241
|
+
b as ErrorBoundary,
|
|
242
|
+
c as ErrorReporter,
|
|
243
|
+
j as GlobalErrorListener,
|
|
249
244
|
R as createRTKErrorMiddleware,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
245
|
+
A as createReduxRTKErrorMiddleware,
|
|
246
|
+
x as useErrorReporter,
|
|
247
|
+
k as useGlobalErrorListener
|
|
253
248
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rtk-error.middleware.d.ts","sourceRoot":"","sources":["../../../src/lib/middlewares/rtk-error.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EACV,wBAAwB,EACxB,6BAA6B,EAC9B,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"rtk-error.middleware.d.ts","sourceRoot":"","sources":["../../../src/lib/middlewares/rtk-error.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EACV,wBAAwB,EACxB,6BAA6B,EAC9B,MAAM,2BAA2B,CAAC;AAsCnC,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,wBAA6B,GACpC,UAAU,CA0BZ;AAGD,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,6BAA6B,GACpC,UAAU,CA+BZ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-kingdom/shared-frontend-feature-error-autologger",
|
|
3
|
-
"version": "0.0.2-
|
|
3
|
+
"version": "0.0.2-16",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
|
+
"README.md",
|
|
21
22
|
"dist",
|
|
22
23
|
"!**/*.tsbuildinfo"
|
|
23
24
|
],
|