dreaction-react 1.0.0
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 +255 -0
- package/lib/components/ConfigPanel.d.ts +12 -0
- package/lib/components/ConfigPanel.d.ts.map +1 -0
- package/lib/components/ConfigPanel.js +151 -0
- package/lib/dreaction.d.ts +32 -0
- package/lib/dreaction.d.ts.map +1 -0
- package/lib/dreaction.js +110 -0
- package/lib/hooks.d.ts +17 -0
- package/lib/hooks.d.ts.map +1 -0
- package/lib/hooks.js +111 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +23 -0
- package/lib/plugins/localStorage.d.ts +14 -0
- package/lib/plugins/localStorage.d.ts.map +1 -0
- package/lib/plugins/localStorage.js +85 -0
- package/lib/plugins/networking.d.ts +11 -0
- package/lib/plugins/networking.d.ts.map +1 -0
- package/lib/plugins/networking.js +263 -0
- package/lib/plugins/trackGlobalErrors.d.ts +25 -0
- package/lib/plugins/trackGlobalErrors.d.ts.map +1 -0
- package/lib/plugins/trackGlobalErrors.js +149 -0
- package/lib/plugins/trackGlobalLogs.d.ts +10 -0
- package/lib/plugins/trackGlobalLogs.d.ts.map +1 -0
- package/lib/plugins/trackGlobalLogs.js +42 -0
- package/package.json +35 -0
- package/src/components/ConfigPanel.tsx +247 -0
- package/src/dreaction.ts +181 -0
- package/src/hooks.ts +129 -0
- package/src/index.ts +17 -0
- package/src/plugins/localStorage.ts +100 -0
- package/src/plugins/networking.ts +333 -0
- package/src/plugins/trackGlobalErrors.ts +203 -0
- package/src/plugins/trackGlobalLogs.ts +53 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides a global error handler to report errors.
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
InferFeatures,
|
|
6
|
+
LoggerPlugin,
|
|
7
|
+
DReactionCore,
|
|
8
|
+
assertHasLoggerPlugin,
|
|
9
|
+
Plugin,
|
|
10
|
+
} from 'dreaction-client-core';
|
|
11
|
+
|
|
12
|
+
export interface ErrorStackFrame {
|
|
13
|
+
fileName: string;
|
|
14
|
+
functionName: string;
|
|
15
|
+
lineNumber: number;
|
|
16
|
+
columnNumber?: number | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TrackGlobalErrorsOptions {
|
|
20
|
+
veto?: (frame: ErrorStackFrame) => boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// defaults
|
|
24
|
+
const PLUGIN_DEFAULTS: TrackGlobalErrorsOptions = {
|
|
25
|
+
veto: undefined,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const objectifyError = (error: Error) => {
|
|
29
|
+
const objectifiedError = {} as Record<string, unknown>;
|
|
30
|
+
Object.getOwnPropertyNames(error).forEach((key) => {
|
|
31
|
+
objectifiedError[key] = (error as any)[key];
|
|
32
|
+
});
|
|
33
|
+
return objectifiedError;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Parse error stack trace
|
|
38
|
+
*/
|
|
39
|
+
const parseErrorStack = (error: Error): ErrorStackFrame[] => {
|
|
40
|
+
if (!error.stack) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const frames: ErrorStackFrame[] = [];
|
|
45
|
+
const lines = error.stack.split('\n');
|
|
46
|
+
|
|
47
|
+
// Skip the first line (error message)
|
|
48
|
+
for (let i = 1; i < lines.length; i++) {
|
|
49
|
+
const line = lines[i].trim();
|
|
50
|
+
|
|
51
|
+
// Try to match different stack trace formats
|
|
52
|
+
// Format: at functionName (fileName:lineNumber:columnNumber)
|
|
53
|
+
let match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
|
|
54
|
+
if (match) {
|
|
55
|
+
frames.push({
|
|
56
|
+
functionName: match[1],
|
|
57
|
+
fileName: match[2],
|
|
58
|
+
lineNumber: parseInt(match[3], 10),
|
|
59
|
+
columnNumber: parseInt(match[4], 10),
|
|
60
|
+
});
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Format: at fileName:lineNumber:columnNumber
|
|
65
|
+
match = line.match(/at\s+(.+?):(\d+):(\d+)/);
|
|
66
|
+
if (match) {
|
|
67
|
+
frames.push({
|
|
68
|
+
functionName: '<anonymous>',
|
|
69
|
+
fileName: match[1],
|
|
70
|
+
lineNumber: parseInt(match[2], 10),
|
|
71
|
+
columnNumber: parseInt(match[3], 10),
|
|
72
|
+
});
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Format: functionName@fileName:lineNumber:columnNumber (Firefox)
|
|
77
|
+
match = line.match(/(.+?)@(.+?):(\d+):(\d+)/);
|
|
78
|
+
if (match) {
|
|
79
|
+
frames.push({
|
|
80
|
+
functionName: match[1] || '<anonymous>',
|
|
81
|
+
fileName: match[2],
|
|
82
|
+
lineNumber: parseInt(match[3], 10),
|
|
83
|
+
columnNumber: parseInt(match[4], 10),
|
|
84
|
+
});
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return frames;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Track global errors and send them to DReaction logger.
|
|
94
|
+
*/
|
|
95
|
+
const trackGlobalErrors =
|
|
96
|
+
(options?: TrackGlobalErrorsOptions) => (dreaction: DReactionCore) => {
|
|
97
|
+
// make sure we have the logger plugin
|
|
98
|
+
assertHasLoggerPlugin(dreaction);
|
|
99
|
+
const client = dreaction as DReactionCore &
|
|
100
|
+
InferFeatures<DReactionCore, LoggerPlugin>;
|
|
101
|
+
|
|
102
|
+
// setup configuration
|
|
103
|
+
const config = Object.assign({}, PLUGIN_DEFAULTS, options || {});
|
|
104
|
+
|
|
105
|
+
let originalWindowOnError: OnErrorEventHandler;
|
|
106
|
+
let unhandledRejectionHandler:
|
|
107
|
+
| ((event: PromiseRejectionEvent) => void)
|
|
108
|
+
| null = null;
|
|
109
|
+
|
|
110
|
+
// manually fire an error
|
|
111
|
+
function reportError(error: Error, stack?: ErrorStackFrame[]) {
|
|
112
|
+
try {
|
|
113
|
+
let prettyStackFrames = stack || parseErrorStack(error);
|
|
114
|
+
|
|
115
|
+
// does the dev want us to keep each frame?
|
|
116
|
+
if (config.veto) {
|
|
117
|
+
prettyStackFrames = prettyStackFrames.filter((frame) =>
|
|
118
|
+
config?.veto?.(frame)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
client.error(error.message, prettyStackFrames);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
client.error('Unable to parse stack trace from error object', []);
|
|
125
|
+
client.debug(objectifyError(e as Error));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// the dreaction plugin interface
|
|
130
|
+
return {
|
|
131
|
+
onConnect: () => {
|
|
132
|
+
if (typeof window === 'undefined') return;
|
|
133
|
+
|
|
134
|
+
// Intercept window.onerror
|
|
135
|
+
originalWindowOnError = window.onerror;
|
|
136
|
+
window.onerror = function (
|
|
137
|
+
message: string | Event,
|
|
138
|
+
source?: string,
|
|
139
|
+
lineno?: number,
|
|
140
|
+
colno?: number,
|
|
141
|
+
error?: Error
|
|
142
|
+
) {
|
|
143
|
+
if (error) {
|
|
144
|
+
reportError(error);
|
|
145
|
+
} else if (typeof message === 'string') {
|
|
146
|
+
const syntheticError = new Error(message);
|
|
147
|
+
const frames: ErrorStackFrame[] = [];
|
|
148
|
+
if (source) {
|
|
149
|
+
frames.push({
|
|
150
|
+
fileName: source,
|
|
151
|
+
functionName: '<unknown>',
|
|
152
|
+
lineNumber: lineno || 0,
|
|
153
|
+
columnNumber: colno || 0,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
reportError(syntheticError, frames);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Call original handler
|
|
160
|
+
if (originalWindowOnError) {
|
|
161
|
+
return originalWindowOnError.apply(this, arguments as any);
|
|
162
|
+
}
|
|
163
|
+
return false;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// Intercept unhandled promise rejections
|
|
167
|
+
unhandledRejectionHandler = (event: PromiseRejectionEvent) => {
|
|
168
|
+
const error =
|
|
169
|
+
event.reason instanceof Error
|
|
170
|
+
? event.reason
|
|
171
|
+
: new Error(String(event.reason));
|
|
172
|
+
reportError(error);
|
|
173
|
+
};
|
|
174
|
+
window.addEventListener(
|
|
175
|
+
'unhandledrejection',
|
|
176
|
+
unhandledRejectionHandler
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
onDisconnect: () => {
|
|
181
|
+
if (typeof window === 'undefined') return;
|
|
182
|
+
|
|
183
|
+
// Restore original handlers
|
|
184
|
+
if (originalWindowOnError) {
|
|
185
|
+
window.onerror = originalWindowOnError;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (unhandledRejectionHandler) {
|
|
189
|
+
window.removeEventListener(
|
|
190
|
+
'unhandledrejection',
|
|
191
|
+
unhandledRejectionHandler
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
// attach these functions to the DReaction
|
|
197
|
+
features: {
|
|
198
|
+
reportError,
|
|
199
|
+
},
|
|
200
|
+
} satisfies Plugin<DReactionCore>;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export default trackGlobalErrors;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InferFeatures,
|
|
3
|
+
LoggerPlugin,
|
|
4
|
+
DReactionCore,
|
|
5
|
+
assertHasLoggerPlugin,
|
|
6
|
+
Plugin,
|
|
7
|
+
} from 'dreaction-client-core';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Track calls to console.log, console.warn, and console.debug and send them to DReaction logger
|
|
11
|
+
*/
|
|
12
|
+
const trackGlobalLogs = () => (dreaction: DReactionCore) => {
|
|
13
|
+
assertHasLoggerPlugin(dreaction);
|
|
14
|
+
const client = dreaction as DReactionCore &
|
|
15
|
+
InferFeatures<DReactionCore, LoggerPlugin>;
|
|
16
|
+
|
|
17
|
+
const originalConsoleLog = console.log;
|
|
18
|
+
const originalConsoleWarn = console.warn;
|
|
19
|
+
const originalConsoleDebug = console.debug;
|
|
20
|
+
const originalConsoleInfo = console.info;
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
onConnect: () => {
|
|
24
|
+
console.log = (...args: Parameters<typeof console.log>) => {
|
|
25
|
+
originalConsoleLog(...args);
|
|
26
|
+
client.log(...args);
|
|
27
|
+
};
|
|
28
|
+
console.info = (...args: Parameters<typeof console.info>) => {
|
|
29
|
+
originalConsoleInfo(...args);
|
|
30
|
+
client.log(...args);
|
|
31
|
+
};
|
|
32
|
+
console.warn = (...args: Parameters<typeof console.warn>) => {
|
|
33
|
+
originalConsoleWarn(...args);
|
|
34
|
+
client.warn(args[0]);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
console.debug = (...args: Parameters<typeof console.debug>) => {
|
|
38
|
+
originalConsoleDebug(...args);
|
|
39
|
+
client.debug(args[0]);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// console.error is taken care of by ./trackGlobalErrors.ts
|
|
43
|
+
},
|
|
44
|
+
onDisconnect: () => {
|
|
45
|
+
console.log = originalConsoleLog;
|
|
46
|
+
console.warn = originalConsoleWarn;
|
|
47
|
+
console.debug = originalConsoleDebug;
|
|
48
|
+
console.info = originalConsoleInfo;
|
|
49
|
+
},
|
|
50
|
+
} satisfies Plugin<DReactionCore>;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default trackGlobalLogs;
|