error-monitor-web 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/LICENSE +21 -0
- package/README.md +323 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.mjs +567 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Error Monitor SDK
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# error-monitor-web
|
|
2
|
+
|
|
3
|
+
Web error monitoring SDK - Browser-specific error tracking capabilities built on top of error-monitor-core.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🌐 **Browser Error Capture**: Automatically captures JavaScript errors, Promise rejections, network errors, and resource loading errors
|
|
8
|
+
- 🖥️ **Blank Screen Detection**: Intelligent detection of white screen issues
|
|
9
|
+
- 📡 **Request Interception**: Built-in fetch and XMLHttpRequest interception
|
|
10
|
+
- 🎨 **Context Collection**: Automatic collection of browser context information (user agent, URL, viewport)
|
|
11
|
+
- 🔗 **Easy Integration**: Simple setup with automatic browser API hooking
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install error-monitor-web
|
|
17
|
+
# or
|
|
18
|
+
pnpm install error-monitor-web
|
|
19
|
+
# or
|
|
20
|
+
yarn add error-monitor-web
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { ErrorMonitorWeb } from 'error-monitor-web'
|
|
27
|
+
|
|
28
|
+
// Initialize the monitor
|
|
29
|
+
const monitor = new ErrorMonitorWeb({
|
|
30
|
+
appId: 'your-app-id',
|
|
31
|
+
dsn: 'https://your-error-server.com/collect',
|
|
32
|
+
enabled: true,
|
|
33
|
+
|
|
34
|
+
// Auto-capture options (all enabled by default)
|
|
35
|
+
autoCapture: {
|
|
36
|
+
js: true, // JavaScript errors
|
|
37
|
+
promise: true, // Promise rejections
|
|
38
|
+
network: true, // Network errors (fetch/XHR)
|
|
39
|
+
resource: true // Resource loading errors
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Start monitoring
|
|
44
|
+
monitor.init()
|
|
45
|
+
|
|
46
|
+
// The monitor will now automatically capture:
|
|
47
|
+
// - Unhandled JavaScript errors
|
|
48
|
+
// - Unhandled Promise rejections
|
|
49
|
+
// - Failed fetch requests
|
|
50
|
+
// - Failed XMLHttpRequests
|
|
51
|
+
// - Failed resource loading (images, scripts, stylesheets, etc.)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
All options from `error-monitor-core` plus web-specific options:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
interface WebConfig extends Config {
|
|
60
|
+
// Auto-capture switches
|
|
61
|
+
autoCapture?: {
|
|
62
|
+
js?: boolean // JavaScript errors (default: true)
|
|
63
|
+
promise?: boolean // Promise rejections (default: true)
|
|
64
|
+
network?: boolean // Network errors (default: true)
|
|
65
|
+
resource?: boolean // Resource loading errors (default: true)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Blank screen detection
|
|
69
|
+
blankScreenDetection?: {
|
|
70
|
+
enabled?: boolean // Enable blank screen detection (default: false)
|
|
71
|
+
detectionDelay?: number // Delay before first check (ms, default: 3000)
|
|
72
|
+
minElements?: number // Minimum DOM elements to consider not blank (default: 10)
|
|
73
|
+
checkInterval?: number // Check interval (ms, default: 1000)
|
|
74
|
+
maxChecks?: number // Maximum number of checks (default: 5)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Automatic Error Capture
|
|
80
|
+
|
|
81
|
+
### JavaScript Errors
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// Automatically captured when enabled
|
|
85
|
+
// Error includes:
|
|
86
|
+
// - Error message and stack trace
|
|
87
|
+
// - File name, line number, column number
|
|
88
|
+
// - Browser context (user agent, URL, viewport)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Promise Rejections
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// Automatically captured when enabled
|
|
95
|
+
// Captures unhandled promise rejections
|
|
96
|
+
// Includes rejection reason and stack trace
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Network Errors
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// Fetch errors are automatically intercepted
|
|
103
|
+
fetch('https://api.example.com/data')
|
|
104
|
+
.then(res => res.json())
|
|
105
|
+
.catch(error => {
|
|
106
|
+
// Error is captured automatically
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// XMLHttpRequest errors are also intercepted
|
|
110
|
+
const xhr = new XMLHttpRequest()
|
|
111
|
+
xhr.open('GET', 'https://api.example.com/data')
|
|
112
|
+
xhr.send()
|
|
113
|
+
// If this fails, the error is captured
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Resource Loading Errors
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// Resource loading failures are captured
|
|
120
|
+
// <img src="missing-image.png" />
|
|
121
|
+
// If this fails to load, the error is captured
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Manual Error Capture
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Capture errors manually
|
|
128
|
+
try {
|
|
129
|
+
// Your code
|
|
130
|
+
} catch (error) {
|
|
131
|
+
monitor.captureError(error, {
|
|
132
|
+
level: 'error',
|
|
133
|
+
tags: { module: 'checkout' },
|
|
134
|
+
extra: { cartId: '12345' }
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Capture custom messages
|
|
139
|
+
monitor.captureMessage('Payment failed', 'warning', {
|
|
140
|
+
extra: { reason: 'Insufficient funds', amount: 100 }
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Blank Screen Detection
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const monitor = new ErrorMonitorWeb({
|
|
148
|
+
appId: 'your-app-id',
|
|
149
|
+
dsn: 'https://your-error-server.com/collect',
|
|
150
|
+
blankScreenDetection: {
|
|
151
|
+
enabled: true,
|
|
152
|
+
detectionDelay: 5000, // Start checking after 5 seconds
|
|
153
|
+
minElements: 15, // Need at least 15 DOM elements
|
|
154
|
+
checkInterval: 1000, // Check every second
|
|
155
|
+
maxChecks: 5 // Check 5 times max
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
monitor.init()
|
|
160
|
+
|
|
161
|
+
// Blank screen detection will:
|
|
162
|
+
// - Monitor DOM element count
|
|
163
|
+
// - Check if body has content
|
|
164
|
+
// - Use Performance API for additional metrics
|
|
165
|
+
// - Report blank screen if detected
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Breadcrumbs
|
|
169
|
+
|
|
170
|
+
Track user actions leading up to errors:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// Add navigation breadcrumbs
|
|
174
|
+
monitor.addBreadcrumb({
|
|
175
|
+
type: 'navigation',
|
|
176
|
+
message: 'User navigated to checkout',
|
|
177
|
+
data: { from: '/cart', to: '/checkout' }
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// Add user action breadcrumbs
|
|
181
|
+
monitor.addBreadcrumb({
|
|
182
|
+
type: 'user',
|
|
183
|
+
message: 'User clicked submit button',
|
|
184
|
+
data: { buttonId: 'submit-payment' }
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
// Add custom breadcrumbs
|
|
188
|
+
monitor.addBreadcrumb({
|
|
189
|
+
type: 'custom',
|
|
190
|
+
message: 'API call started',
|
|
191
|
+
data: { endpoint: '/api/payment' }
|
|
192
|
+
})
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## User Information
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Set user information
|
|
199
|
+
monitor.setUser({
|
|
200
|
+
id: 'user-123',
|
|
201
|
+
username: 'john_doe',
|
|
202
|
+
email: 'john@example.com',
|
|
203
|
+
plan: 'premium'
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
// User info is included in all error reports
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Tags
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// Add tags to categorize errors
|
|
213
|
+
monitor.setTags({
|
|
214
|
+
environment: 'production',
|
|
215
|
+
version: '1.0.0',
|
|
216
|
+
framework: 'react',
|
|
217
|
+
build: '2024-01-29'
|
|
218
|
+
})
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Context Information
|
|
222
|
+
|
|
223
|
+
Automatically collected context:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
{
|
|
227
|
+
userAgent: string // Browser user agent
|
|
228
|
+
url: string // Current page URL
|
|
229
|
+
viewport: {
|
|
230
|
+
width: number // Viewport width
|
|
231
|
+
height: number // Viewport height
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Sampling
|
|
237
|
+
|
|
238
|
+
Control error reporting rate:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// Set overall sampling rate (capture 10% of all events)
|
|
242
|
+
monitor.setSampleRate(0.1)
|
|
243
|
+
|
|
244
|
+
// Set error-specific sampling rate
|
|
245
|
+
monitor.setErrorSampleRate(0.5) // Capture 50% of errors
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Filtering
|
|
249
|
+
|
|
250
|
+
Filter out unwanted errors:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
// Filter by error message pattern
|
|
254
|
+
monitor.addFilter(/Script error/i) // Ignore all script errors
|
|
255
|
+
monitor.addFilter(/_追踪/) // Ignore errors containing "_追踪"
|
|
256
|
+
|
|
257
|
+
// Errors matching patterns won't be captured
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Error Report Format
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
{
|
|
264
|
+
appId: 'your-app-id',
|
|
265
|
+
timestamp: 1234567890,
|
|
266
|
+
sessionId: 'session-123',
|
|
267
|
+
eventId: 'event-456',
|
|
268
|
+
|
|
269
|
+
type: 'js', // 'js', 'promise', 'network', 'resource', 'custom'
|
|
270
|
+
level: 'error',
|
|
271
|
+
message: 'Uncaught Error: Something went wrong',
|
|
272
|
+
stack: 'Error: Something went wrong\\n at...',
|
|
273
|
+
|
|
274
|
+
context: {
|
|
275
|
+
userAgent: 'Mozilla/5.0...',
|
|
276
|
+
url: 'https://example.com/page',
|
|
277
|
+
viewport: { width: 1920, height: 1080 },
|
|
278
|
+
userId: 'user-123',
|
|
279
|
+
tags: { environment: 'production', version: '1.0.0' }
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
breadcrumbs: [
|
|
283
|
+
{
|
|
284
|
+
timestamp: 1234567880,
|
|
285
|
+
type: 'navigation',
|
|
286
|
+
message: 'User navigated to /checkout',
|
|
287
|
+
data: { from: '/cart' }
|
|
288
|
+
}
|
|
289
|
+
],
|
|
290
|
+
|
|
291
|
+
extra: {
|
|
292
|
+
customField: 'custom value'
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Cleanup
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
// When your app is unmounting or cleaning up
|
|
301
|
+
monitor.destroy()
|
|
302
|
+
|
|
303
|
+
// This will:
|
|
304
|
+
// - Remove all event listeners
|
|
305
|
+
// - Restore original fetch and XMLHttpRequest
|
|
306
|
+
// - Stop blank screen detection
|
|
307
|
+
// - Clear all timers
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Browser Support
|
|
311
|
+
|
|
312
|
+
- Chrome/Edge: ✅ Latest
|
|
313
|
+
- Firefox: ✅ Latest
|
|
314
|
+
- Safari: ✅ Latest
|
|
315
|
+
- Opera: ✅ Latest
|
|
316
|
+
|
|
317
|
+
## License
|
|
318
|
+
|
|
319
|
+
MIT
|
|
320
|
+
|
|
321
|
+
## Support
|
|
322
|
+
|
|
323
|
+
For issues and questions, please visit our GitHub repository.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});function b(){return`${Date.now()}-${Math.random().toString(36).substring(2,15)}`}function g(){return`${Date.now()}-${Math.random().toString(36).substring(2,15)}`}class p{constructor(e){this.isInitialized=!1,this.breadcrumbs=[],this.maxBreadcrumbs=50,this.plugins=[],this.sessionId=b(),this.config={autoCapture:{js:!0,promise:!0,network:!0,resource:!0,console:!1},filter:{ignoreErrors:[],ignoreUrls:[],minLevel:"info"},report:{delay:1e3,batchSize:10},sampleRate:1,errorSampleRate:1,enabled:!0,debug:!1,...e}}updateConfig(e){this.config={...this.config,...e},this.config.debug&&console.log("[ErrorMonitor] Config updated:",this.config)}enable(){this.config.enabled=!0,console.log("[ErrorMonitor] SDK enabled")}disable(){this.config.enabled=!1,console.log("[ErrorMonitor] SDK disabled")}addFilter(e){this.config.filter||(this.config.filter={}),this.config.filter.ignoreErrors||(this.config.filter.ignoreErrors=[]),this.config.filter.ignoreErrors.push(e)}removeFilter(e){var t;if(!((t=this.config.filter)!=null&&t.ignoreErrors))return;const n=this.config.filter.ignoreErrors.indexOf(e);n>-1&&this.config.filter.ignoreErrors.splice(n,1)}setSampleRate(e){this.config.sampleRate=Math.max(0,Math.min(1,e))}setErrorSampleRate(e){this.config.errorSampleRate=Math.max(0,Math.min(1,e))}init(){if(this.isInitialized){console.warn("[ErrorMonitor] Already initialized");return}this.isInitialized=!0,this.plugins.forEach(e=>{var t;(t=e.setup)==null||t.call(e,this)}),console.log("[ErrorMonitor] Initialized with appId:",this.config.appId)}use(e){var t;this.plugins.push(e),this.isInitialized&&((t=e.setup)==null||t.call(e,this))}capture(e,t){var n,i;if(!this.isInitialized){console.warn("[ErrorMonitor] Not initialized");return}if(this.config.enabled===!1)return;const o=e instanceof Error?{type:"custom",message:e.message,stack:e.stack,context:{}}:e,r={level:"error",tags:{},extra:{},user:{},skipSampling:!1,skipFilter:!1,...t};if(!r.skipFilter&&this.shouldFilter(o)){this.config.debug&&console.log("[ErrorMonitor] Error filtered:",o.message);return}if(!r.skipSampling&&this.config.errorSampleRate!==void 0&&Math.random()>this.config.errorSampleRate)return;let s=o;for(const l of this.plugins){const a=(n=l.beforeCapture)==null?void 0:n.call(l,o);if(a===null)return;a!==void 0&&(s=a)}const c={appId:this.config.appId,timestamp:Date.now(),sessionId:this.sessionId,eventId:g(),type:s.type,level:r.level,message:s.message,stack:s.stack,context:{userAgent:typeof navigator<"u"?navigator.userAgent:"",url:typeof location<"u"?location.href:"",viewport:{width:typeof window<"u"?window.innerWidth:0,height:typeof window<"u"?window.innerHeight:0},userId:r.user.id||this.config.userId,tags:{...this.config.tags,...r.tags}},breadcrumbs:[...this.breadcrumbs],extra:{...s.context,...r.extra}};for(const l of this.plugins){const a=(i=l.afterCapture)==null?void 0:i.call(l,c);a!==void 0&&Object.assign(c,a)}this.report(c)}shouldFilter(e){var t;if(!this.config.filter)return!1;const{ignoreErrors:n,ignoreUrls:i,minLevel:o}=this.config.filter;if(n&&n.length>0){for(const r of n)if(r.test(e.message))return!0}if(i&&i.length>0&&(t=e.context)!=null&&t.url){for(const r of i)if(r.test(e.context.url))return!0}return!1}captureError(e,t){this.capture(e,t)}captureMessage(e,t="info",n){this.capture({type:"custom",message:e,context:{}},{...n,level:t})}report(e){var t;let n=e;for(const i of this.plugins){const o=(t=i.beforeReport)==null?void 0:t.call(i,e);o!==void 0&&(n=o)}this.sendToServer(n)}addBreadcrumb(e){this.breadcrumbs.push({timestamp:e.timestamp||Date.now(),type:e.type,message:e.message,data:e.data}),this.breadcrumbs.length>this.maxBreadcrumbs&&this.breadcrumbs.shift()}generateId(){return g()}setUser(e){this.config.userId=e.id,this.config.tags={...this.config.tags,...e}}sendToServer(e){if(typeof navigator>"u")return;const t=JSON.stringify(e);if(navigator.sendBeacon){const n=new Blob([t],{type:"application/json"});navigator.sendBeacon(this.config.dsn,n);return}typeof fetch<"u"&&fetch(this.config.dsn,{method:"POST",body:t,keepalive:!0,headers:{"Content-Type":"application/json"}}).catch(n=>{console.error("[ErrorMonitor] Failed to send report:",n)})}destroy(){this.plugins.forEach(e=>{var t;(t=e.teardown)==null||t.call(e)}),this.plugins=[],this.breadcrumbs=[],this.isInitialized=!1,console.log("[ErrorMonitor] Destroyed")}}class m{constructor(e={}){this.checkCount=0,this.timerId=null,this.isBlankScreen=!1,this.config={detectionDelay:e.detectionDelay||3e3,minElements:e.minElements||10,checkInterval:e.checkInterval||1e3,maxChecks:e.maxChecks||5,checkPerformance:e.checkPerformance!==!1,customCheck:e.customCheck||(()=>!1)}}start(e){console.log("[BlankScreenDetector] Starting blank screen detection..."),console.log("[BlankScreenDetector] Config:",this.config),setTimeout(()=>{console.log("[BlankScreenDetector] Detection delay passed, starting first check..."),this.performCheck(e)},this.config.detectionDelay)}performCheck(e){this.checkCount++,console.log(`[BlankScreenDetector] Check #${this.checkCount}/${this.config.maxChecks}`);const t=this.checkIfBlank();if(console.log("[BlankScreenDetector] Is blank screen?",t),t&&!this.isBlankScreen){console.log("[BlankScreenDetector] Blank screen detected for the first time!"),this.isBlankScreen=!0;const n=this.generateReport();console.log("[BlankScreenDetector] Generated report:",n),e(n)}this.checkCount<this.config.maxChecks&&!t?(this.timerId=window.setTimeout(()=>{this.performCheck(e)},this.config.checkInterval),console.log(`[BlankScreenDetector] Scheduling next check in ${this.config.checkInterval}ms`)):console.log("[BlankScreenDetector] Stopping checks. Count:",this.checkCount,"Is blank:",t)}checkIfBlank(){if(this.config.customCheck())return console.log("[BlankScreenDetector] Custom check returned true"),!0;const e=this.checkDOMElements();if(console.log("[BlankScreenDetector] DOM check result:",e),e.isBlank)return console.log("[BlankScreenDetector] DOM check indicates blank screen"),!0;if(this.config.checkPerformance){const t=this.checkPerformanceTiming();if(console.log("[BlankScreenDetector] Performance check result:",t),t.isBlank)return console.log("[BlankScreenDetector] Performance check indicates blank screen"),!0}return console.log("[BlankScreenDetector] All checks passed, not a blank screen"),!1}checkDOMElements(){var a;const e=document.querySelectorAll("*").length,t=((a=document.body)==null?void 0:a.children.length)||0,n=!!document.body,i=t>0,o=document.querySelectorAll("#blank-page, #minimal-page, #temp-status").length,r=document.querySelectorAll("script").length,s=e-o-r,c=!n||s<this.config.minElements||!i,l={totalElements:e,bodyElements:t,hasBody:n,hasContent:i,testElements:o,scriptElements:r,elementsWithoutTestAndScripts:s,minElements:this.config.minElements};return console.log("[BlankScreenDetector] 详细DOM信息:",l),{isBlank:c,info:l}}checkPerformanceTiming(){var l;if(!window.performance||!window.performance.timing)return{isBlank:!1};const e=window.performance.timing,t=e.navigationStart,n=e.domContentLoadedEventEnd-t,i=e.loadEventEnd-t;let o,r;const s=(l=performance.getEntriesByType)==null?void 0:l.call(performance,"paint");if(s){const a=s.find(f=>f.name==="first-paint"),u=s.find(f=>f.name==="first-contentful-paint");o=a==null?void 0:a.startTime,r=u==null?void 0:u.startTime}return{isBlank:i>0&&(o===void 0||r===void 0)&&n>5e3,timing:{domContentLoaded:n,loadComplete:i,firstPaint:o,firstContentfulPaint:r}}}generateReport(){var n;const e=this.checkDOMElements(),t=this.config.checkPerformance?this.checkPerformanceTiming():{};return{type:"blank-screen",message:"检测到白屏:页面加载后无内容渲染",context:{timestamp:Date.now(),url:window.location.href,domElements:document.querySelectorAll("*").length,bodyElements:((n=document.body)==null?void 0:n.children.length)||0,hasContent:e.info.hasContent,performanceTiming:t.timing}}}stop(){console.log("[BlankScreenDetector] Stopping blank screen detection..."),this.timerId!==null&&(window.clearTimeout(this.timerId),this.timerId=null,console.log("[BlankScreenDetector] Cleared timeout timer")),console.log("[BlankScreenDetector] Blank screen detection stopped")}reset(){this.stop(),this.checkCount=0,this.isBlankScreen=!1}}function k(h){return new m(h)}class d extends p{constructor(e){super(e),this.originalFetch=null,this.originalXHR=null,this.blankScreenDetector=null,this.config=e}init(){var o,r,s,c;if(super.init(),typeof window>"u"){console.warn("[ErrorMonitorWeb] Not in browser environment");return}const e=((o=this.config.autoCapture)==null?void 0:o.js)!==!1&&this.config.captureJsErrors!==!1,t=((r=this.config.autoCapture)==null?void 0:r.promise)!==!1&&this.config.capturePromiseErrors!==!1,n=((s=this.config.autoCapture)==null?void 0:s.network)!==!1&&this.config.captureNetworkErrors!==!1,i=((c=this.config.autoCapture)==null?void 0:c.resource)!==!1&&this.config.captureResourceErrors!==!1;e&&this.setupJsErrorHandler(),t&&this.setupPromiseErrorHandler(),n&&this.setupNetworkErrorHandler(),i&&this.setupResourceErrorHandler(),this.config.blankScreenDetection&&this.setupBlankScreenDetection(),console.log("[ErrorMonitorWeb] Web handlers initialized")}setupJsErrorHandler(){window.addEventListener("error",e=>{var t;this.capture({type:"js",message:e.message,stack:(t=e.error)==null?void 0:t.stack,context:{filename:e.filename,lineno:e.lineno,colno:e.colno}})})}setupPromiseErrorHandler(){window.addEventListener("unhandledrejection",e=>{var t,n;this.capture({type:"promise",message:((t=e.reason)==null?void 0:t.message)||String(e.reason),stack:(n=e.reason)==null?void 0:n.stack,context:{reason:e.reason}})})}setupNetworkErrorHandler(){if(typeof window.fetch<"u"){this.originalFetch=window.fetch;const e=this;window.fetch=function(...t){return e.originalFetch.apply(this,t).catch(n=>{var r;const i=typeof t[0]=="string"?t[0]:String(t[0]),o=((r=t[1])==null?void 0:r.method)||"GET";throw e.capture({type:"network",message:`Network error: ${o} ${i}`,context:{url:i,method:o,error:n.message}}),n})}}if(typeof window.XMLHttpRequest<"u"){this.originalXHR=window.XMLHttpRequest;const e=this,t=this.originalXHR;window.XMLHttpRequest=function(){const n=new t,i=n.open,o=n.send;let r="",s="";return n.open=function(...c){return s=c[0]||"GET",r=String(c[1]||""),i.apply(this,c)},n.send=function(...c){return n.addEventListener("error",()=>{e.capture({type:"network",message:`XHR error: ${s} ${r}`,context:{url:r,method:s,status:n.status}})}),o.apply(this,c)},n}}}setupResourceErrorHandler(){window.addEventListener("error",e=>{if(e.target!==window){const t=e.target;this.capture({type:"resource",message:`Resource load error: ${t.tagName}`,context:{tagName:t.tagName,src:t.src||t.href}})}},!0)}setupBlankScreenDetection(){console.log("[ErrorMonitorWeb] Setting up blank screen detection...");const e=typeof this.config.blankScreenDetection=="boolean"?{}:this.config.blankScreenDetection;console.log("[ErrorMonitorWeb] Blank screen config:",e),this.blankScreenDetector=k(e),this.blankScreenDetector.start(t=>{console.log("[ErrorMonitorWeb] Blank screen detected!",t),this.capture({type:t.type,message:t.message,context:t.context})}),console.log("[ErrorMonitorWeb] Blank screen detection started")}captureError(e,t){this.capture({type:"custom",message:e.message,stack:e.stack,context:t})}captureMessage(e,t="info"){this.capture({type:"custom",message:e,context:{level:t}})}destroy(){console.log("[ErrorMonitorWeb] Destroying instance..."),this.blankScreenDetector&&(console.log("[ErrorMonitorWeb] Stopping blank screen detector..."),this.blankScreenDetector.stop(),this.blankScreenDetector=null),this.originalFetch&&window.fetch!==this.originalFetch&&(window.fetch=this.originalFetch),this.originalXHR&&window.XMLHttpRequest!==this.originalXHR&&(window.XMLHttpRequest=this.originalXHR),super.destroy(),console.log("[ErrorMonitorWeb] Instance destroyed")}}function w(h){return new d(h)}exports.BlankScreenDetector=m;exports.ErrorMonitor=p;exports.ErrorMonitorWeb=d;exports.createBlankScreenDetector=k;exports.createErrorMonitorWeb=w;exports.default=d;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../core/dist/index.mjs","../src/blank-screen-detector.ts","../src/index.ts"],"sourcesContent":["function h() {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\nfunction l() {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\nclass g {\n constructor(e) {\n this.isInitialized = !1, this.breadcrumbs = [], this.maxBreadcrumbs = 50, this.plugins = [], this.sessionId = h(), this.config = {\n autoCapture: {\n js: !0,\n promise: !0,\n network: !0,\n resource: !0,\n console: !1\n },\n filter: {\n ignoreErrors: [],\n ignoreUrls: [],\n minLevel: \"info\"\n },\n report: {\n delay: 1e3,\n batchSize: 10\n },\n sampleRate: 1,\n errorSampleRate: 1,\n enabled: !0,\n debug: !1,\n ...e\n };\n }\n /**\n * 更新配置\n */\n updateConfig(e) {\n this.config = { ...this.config, ...e }, this.config.debug && console.log(\"[ErrorMonitor] Config updated:\", this.config);\n }\n /**\n * 启用SDK\n */\n enable() {\n this.config.enabled = !0, console.log(\"[ErrorMonitor] SDK enabled\");\n }\n /**\n * 禁用SDK\n */\n disable() {\n this.config.enabled = !1, console.log(\"[ErrorMonitor] SDK disabled\");\n }\n /**\n * 添加错误过滤器\n */\n addFilter(e) {\n this.config.filter || (this.config.filter = {}), this.config.filter.ignoreErrors || (this.config.filter.ignoreErrors = []), this.config.filter.ignoreErrors.push(e);\n }\n /**\n * 移除错误过滤器\n */\n removeFilter(e) {\n var r;\n if (!((r = this.config.filter) != null && r.ignoreErrors)) return;\n const t = this.config.filter.ignoreErrors.indexOf(e);\n t > -1 && this.config.filter.ignoreErrors.splice(t, 1);\n }\n /**\n * 设置采样率\n */\n setSampleRate(e) {\n this.config.sampleRate = Math.max(0, Math.min(1, e));\n }\n /**\n * 设置错误采样率\n */\n setErrorSampleRate(e) {\n this.config.errorSampleRate = Math.max(0, Math.min(1, e));\n }\n /**\n * 初始化监控\n */\n init() {\n if (this.isInitialized) {\n console.warn(\"[ErrorMonitor] Already initialized\");\n return;\n }\n this.isInitialized = !0, this.plugins.forEach((e) => {\n var t;\n (t = e.setup) == null || t.call(e, this);\n }), console.log(\"[ErrorMonitor] Initialized with appId:\", this.config.appId);\n }\n /**\n * 注册插件\n */\n use(e) {\n var t;\n this.plugins.push(e), this.isInitialized && ((t = e.setup) == null || t.call(e, this));\n }\n /**\n * 捕获错误(支持选项)\n */\n capture(e, t) {\n var c, d;\n if (!this.isInitialized) {\n console.warn(\"[ErrorMonitor] Not initialized\");\n return;\n }\n if (this.config.enabled === !1)\n return;\n const r = e instanceof Error ? {\n type: \"custom\",\n message: e.message,\n stack: e.stack,\n context: {}\n } : e, i = {\n level: \"error\",\n tags: {},\n extra: {},\n user: {},\n skipSampling: !1,\n skipFilter: !1,\n ...t\n };\n if (!i.skipFilter && this.shouldFilter(r)) {\n this.config.debug && console.log(\"[ErrorMonitor] Error filtered:\", r.message);\n return;\n }\n if (!i.skipSampling && this.config.errorSampleRate !== void 0 && Math.random() > this.config.errorSampleRate)\n return;\n let s = r;\n for (const n of this.plugins) {\n const a = (c = n.beforeCapture) == null ? void 0 : c.call(n, r);\n if (a === null)\n return;\n a !== void 0 && (s = a);\n }\n const o = {\n appId: this.config.appId,\n timestamp: Date.now(),\n sessionId: this.sessionId,\n eventId: l(),\n type: s.type,\n level: i.level,\n message: s.message,\n stack: s.stack,\n context: {\n userAgent: typeof navigator < \"u\" ? navigator.userAgent : \"\",\n url: typeof location < \"u\" ? location.href : \"\",\n viewport: {\n width: typeof window < \"u\" ? window.innerWidth : 0,\n height: typeof window < \"u\" ? window.innerHeight : 0\n },\n userId: i.user.id || this.config.userId,\n tags: { ...this.config.tags, ...i.tags }\n },\n breadcrumbs: [...this.breadcrumbs],\n extra: { ...s.context, ...i.extra }\n };\n for (const n of this.plugins) {\n const a = (d = n.afterCapture) == null ? void 0 : d.call(n, o);\n a !== void 0 && Object.assign(o, a);\n }\n this.report(o);\n }\n /**\n * 检查是否应该过滤此错误\n */\n shouldFilter(e) {\n var s;\n if (!this.config.filter) return !1;\n const { ignoreErrors: t, ignoreUrls: r, minLevel: i } = this.config.filter;\n if (t && t.length > 0) {\n for (const o of t)\n if (o.test(e.message))\n return !0;\n }\n if (r && r.length > 0 && ((s = e.context) != null && s.url)) {\n for (const o of r)\n if (o.test(e.context.url))\n return !0;\n }\n return !1;\n }\n /**\n * 手动上报错误(简化的API)\n */\n captureError(e, t) {\n this.capture(e, t);\n }\n /**\n * 手动上报消息\n */\n captureMessage(e, t = \"info\", r) {\n this.capture({\n type: \"custom\",\n message: e,\n context: {}\n }, { ...r, level: t });\n }\n /**\n * 上报错误\n */\n report(e) {\n var r;\n let t = e;\n for (const i of this.plugins) {\n const s = (r = i.beforeReport) == null ? void 0 : r.call(i, e);\n s !== void 0 && (t = s);\n }\n this.sendToServer(t);\n }\n /**\n * 添加面包屑\n */\n addBreadcrumb(e) {\n this.breadcrumbs.push({\n timestamp: e.timestamp || Date.now(),\n type: e.type,\n message: e.message,\n data: e.data\n }), this.breadcrumbs.length > this.maxBreadcrumbs && this.breadcrumbs.shift();\n }\n /**\n * 生成ID\n */\n generateId() {\n return l();\n }\n /**\n * 设置用户信息\n */\n setUser(e) {\n this.config.userId = e.id, this.config.tags = { ...this.config.tags, ...e };\n }\n /**\n * 发送到服务端\n */\n sendToServer(e) {\n if (typeof navigator > \"u\") return;\n const t = JSON.stringify(e);\n if (navigator.sendBeacon) {\n const r = new Blob([t], { type: \"application/json\" });\n navigator.sendBeacon(this.config.dsn, r);\n return;\n }\n typeof fetch < \"u\" && fetch(this.config.dsn, {\n method: \"POST\",\n body: t,\n keepalive: !0,\n headers: {\n \"Content-Type\": \"application/json\"\n }\n }).catch((r) => {\n console.error(\"[ErrorMonitor] Failed to send report:\", r);\n });\n }\n /**\n * 销毁实例\n */\n destroy() {\n this.plugins.forEach((e) => {\n var t;\n (t = e.teardown) == null || t.call(e);\n }), this.plugins = [], this.breadcrumbs = [], this.isInitialized = !1, console.log(\"[ErrorMonitor] Destroyed\");\n }\n}\nfunction u(f) {\n return new g(f);\n}\nexport {\n g as ErrorMonitor,\n u as createErrorMonitor\n};\n//# sourceMappingURL=index.mjs.map\n","/**\n * 白屏检测模块\n * 检测页面是否白屏(无内容渲染)\n */\n\nexport interface BlankScreenConfig {\n // 检测阈值:页面加载后多久开始检测(毫秒)\n detectionDelay?: number\n // 最小DOM元素数量阈值\n minElements?: number\n // 检测间隔(毫秒)\n checkInterval?: number\n // 最大检测次数\n maxChecks?: number\n // 是否检测Performance API\n checkPerformance?: boolean\n // 自定义检测函数\n customCheck?: () => boolean\n}\n\nexport interface BlankScreenReport {\n type: 'blank-screen'\n message: string\n context: {\n timestamp: number\n url: string\n domElements: number\n bodyElements: number\n hasContent: boolean\n performanceTiming?: {\n domContentLoaded?: number\n loadComplete?: number\n firstPaint?: number\n firstContentfulPaint?: number\n }\n }\n}\n\n/**\n * 白屏检测器类\n */\nexport class BlankScreenDetector {\n private config: Required<BlankScreenConfig>\n private checkCount: number = 0\n private timerId: number | null = null\n private isBlankScreen: boolean = false\n\n constructor(config: BlankScreenConfig = {}) {\n this.config = {\n detectionDelay: config.detectionDelay || 3000, // 3秒后开始检测\n minElements: config.minElements || 10, // 最少10个元素\n checkInterval: config.checkInterval || 1000, // 每秒检测一次\n maxChecks: config.maxChecks || 5, // 最多检测5次\n checkPerformance: config.checkPerformance !== false,\n customCheck: config.customCheck || (() => false)\n }\n }\n\n /**\n * 开始检测\n */\n start(callback: (report: BlankScreenReport) => void): void {\n console.log('[BlankScreenDetector] Starting blank screen detection...')\n console.log('[BlankScreenDetector] Config:', this.config)\n\n // 延迟开始检测,等待页面加载\n setTimeout(() => {\n console.log('[BlankScreenDetector] Detection delay passed, starting first check...')\n this.performCheck(callback)\n }, this.config.detectionDelay)\n }\n\n /**\n * 执行检测\n */\n private performCheck(callback: (report: BlankScreenReport) => void): void {\n this.checkCount++\n console.log(`[BlankScreenDetector] Check #${this.checkCount}/${this.config.maxChecks}`)\n\n const isBlank = this.checkIfBlank()\n console.log('[BlankScreenDetector] Is blank screen?', isBlank)\n\n if (isBlank && !this.isBlankScreen) {\n // 首次检测到白屏\n console.log('[BlankScreenDetector] Blank screen detected for the first time!')\n this.isBlankScreen = true\n const report = this.generateReport()\n console.log('[BlankScreenDetector] Generated report:', report)\n callback(report)\n }\n\n // 如果还未达到最大检测次数,继续检测\n if (this.checkCount < this.config.maxChecks && !isBlank) {\n this.timerId = window.setTimeout(() => {\n this.performCheck(callback)\n }, this.config.checkInterval)\n console.log(`[BlankScreenDetector] Scheduling next check in ${this.config.checkInterval}ms`)\n } else {\n console.log('[BlankScreenDetector] Stopping checks. Count:', this.checkCount, 'Is blank:', isBlank)\n }\n }\n\n /**\n * 检查是否白屏\n */\n private checkIfBlank(): boolean {\n // 1. 检查自定义检测函数\n if (this.config.customCheck()) {\n console.log('[BlankScreenDetector] Custom check returned true')\n return true\n }\n\n // 2. 检查DOM元素数量\n const domCheck = this.checkDOMElements()\n console.log('[BlankScreenDetector] DOM check result:', domCheck)\n if (domCheck.isBlank) {\n console.log('[BlankScreenDetector] DOM check indicates blank screen')\n return true\n }\n\n // 3. 检查Performance API\n if (this.config.checkPerformance) {\n const perfCheck = this.checkPerformanceTiming()\n console.log('[BlankScreenDetector] Performance check result:', perfCheck)\n if (perfCheck.isBlank) {\n console.log('[BlankScreenDetector] Performance check indicates blank screen')\n return true\n }\n }\n\n console.log('[BlankScreenDetector] All checks passed, not a blank screen')\n return false\n }\n\n /**\n * 检查DOM元素\n */\n private checkDOMElements(): { isBlank: boolean; info: any } {\n const totalElements = document.querySelectorAll('*').length\n const bodyElements = document.body?.children.length || 0\n\n // 检查body是否存在且不为空\n const hasBody = !!document.body\n const hasContent = bodyElements > 0\n\n // 排除测试相关的元素(blank-page, minimal-page, temp-status等)\n const testElements = document.querySelectorAll('#blank-page, #minimal-page, #temp-status').length\n\n // 排除script标签(测试时script标签不算作内容)\n const scriptElements = document.querySelectorAll('script').length\n\n const elementsWithoutTestAndScripts = totalElements - testElements - scriptElements\n\n // 改进的白屏判断:排除测试元素和script后仍然很少,才认为是白屏\n const isBlank = !hasBody || elementsWithoutTestAndScripts < this.config.minElements || !hasContent\n\n const info = {\n totalElements,\n bodyElements,\n hasBody,\n hasContent,\n testElements,\n scriptElements,\n elementsWithoutTestAndScripts,\n minElements: this.config.minElements\n }\n\n console.log('[BlankScreenDetector] 详细DOM信息:', info)\n\n return {\n isBlank,\n info\n }\n }\n\n /**\n * 检查Performance API\n */\n private checkPerformanceTiming(): { isBlank: boolean; timing?: any } {\n if (!window.performance || !window.performance.timing) {\n return { isBlank: false }\n }\n\n const timing = window.performance.timing\n const navigationStart = timing.navigationStart\n\n const domContentLoaded = timing.domContentLoadedEventEnd - navigationStart\n const loadComplete = timing.loadEventEnd - navigationStart\n\n // 获取首次绘制时间\n let firstPaint: number | undefined\n let firstContentfulPaint: number | undefined\n\n const perfEntries = performance.getEntriesByType?.('paint') as PerformanceEntry[]\n if (perfEntries) {\n const fp = perfEntries.find(e => e.name === 'first-paint')\n const fcp = perfEntries.find(e => e.name === 'first-contentful-paint')\n firstPaint = fp?.startTime\n firstContentfulPaint = fcp?.startTime\n }\n\n // 如果页面加载完成但没有任何绘制,可能是白屏\n const isBlank =\n loadComplete > 0 &&\n (firstPaint === undefined || firstContentfulPaint === undefined) &&\n domContentLoaded > 5000 // DOM加载超过5秒但没有绘制\n\n return {\n isBlank,\n timing: {\n domContentLoaded,\n loadComplete,\n firstPaint,\n firstContentfulPaint\n }\n }\n }\n\n /**\n * 生成报告\n */\n private generateReport(): BlankScreenReport {\n const domInfo = this.checkDOMElements()\n const perfInfo = this.config.checkPerformance ? this.checkPerformanceTiming() : {}\n\n return {\n type: 'blank-screen',\n message: '检测到白屏:页面加载后无内容渲染',\n context: {\n timestamp: Date.now(),\n url: window.location.href,\n domElements: document.querySelectorAll('*').length,\n bodyElements: document.body?.children.length || 0,\n hasContent: domInfo.info.hasContent,\n performanceTiming: perfInfo.timing\n }\n }\n }\n\n /**\n * 停止检测\n */\n stop(): void {\n console.log('[BlankScreenDetector] Stopping blank screen detection...')\n if (this.timerId !== null) {\n window.clearTimeout(this.timerId)\n this.timerId = null\n console.log('[BlankScreenDetector] Cleared timeout timer')\n }\n console.log('[BlankScreenDetector] Blank screen detection stopped')\n }\n\n /**\n * 重置检测器\n */\n reset(): void {\n this.stop()\n this.checkCount = 0\n this.isBlankScreen = false\n }\n}\n\n/**\n * 创建白屏检测器实例\n */\nexport function createBlankScreenDetector(config?: BlankScreenConfig): BlankScreenDetector {\n return new BlankScreenDetector(config)\n}\n","/**\n * Error Monitor Web\n * Web端错误监控模块\n */\n\nimport { ErrorMonitor, Config } from 'error-monitor-core'\nimport {\n BlankScreenDetector,\n BlankScreenConfig,\n createBlankScreenDetector\n} from './blank-screen-detector'\n\n// 导出核心\nexport { ErrorMonitor } from 'error-monitor-core'\nexport type { Config, Plugin, Breadcrumb } from 'error-monitor-core'\n\n// 导出白屏检测\nexport { BlankScreenDetector, createBlankScreenDetector }\nexport type { BlankScreenConfig, BlankScreenReport } from './blank-screen-detector'\n\n/**\n * Web端配置\n */\nexport interface WebConfig extends Config {\n // 是否自动捕获全局错误 (已弃用,请使用 autoCapture)\n captureJsErrors?: boolean\n // 是否捕获Promise错误 (已弃用,请使用 autoCapture)\n capturePromiseErrors?: boolean\n // 是否捕获网络错误 (已弃用,请使用 autoCapture)\n captureNetworkErrors?: boolean\n // 是否捕获资源加载错误 (已弃用,请使用 autoCapture)\n captureResourceErrors?: boolean\n // 是否启用白屏检测\n blankScreenDetection?: boolean | BlankScreenConfig\n // 自定义上报函数\n customReporter?: (data: any) => void\n}\n\n/**\n * Web端错误监控类\n */\nexport class ErrorMonitorWeb extends ErrorMonitor {\n protected config: WebConfig\n private originalFetch: typeof fetch | null = null\n private originalXHR: typeof XMLHttpRequest | null = null\n private blankScreenDetector: BlankScreenDetector | null = null\n\n constructor(config: WebConfig) {\n super(config)\n this.config = config\n }\n\n /**\n * 初始化Web端监控\n */\n init(): void {\n super.init()\n\n if (typeof window === 'undefined') {\n console.warn('[ErrorMonitorWeb] Not in browser environment')\n return\n }\n\n // 支持新旧两种配置格式\n // 新格式: autoCapture.js\n // 旧格式: captureJsErrors\n const captureJs = this.config.autoCapture?.js !== false && this.config.captureJsErrors !== false\n const capturePromise = this.config.autoCapture?.promise !== false && this.config.capturePromiseErrors !== false\n const captureNetwork = this.config.autoCapture?.network !== false && this.config.captureNetworkErrors !== false\n const captureResource = this.config.autoCapture?.resource !== false && this.config.captureResourceErrors !== false\n\n // 自动捕获各种错误\n if (captureJs) {\n this.setupJsErrorHandler()\n }\n\n if (capturePromise) {\n this.setupPromiseErrorHandler()\n }\n\n if (captureNetwork) {\n this.setupNetworkErrorHandler()\n }\n\n if (captureResource) {\n this.setupResourceErrorHandler()\n }\n\n // 初始化白屏检测\n if (this.config.blankScreenDetection) {\n this.setupBlankScreenDetection()\n }\n\n console.log('[ErrorMonitorWeb] Web handlers initialized')\n }\n\n /**\n * JavaScript错误处理\n */\n private setupJsErrorHandler(): void {\n window.addEventListener('error', (event) => {\n this.capture({\n type: 'js',\n message: event.message,\n stack: event.error?.stack,\n context: {\n filename: event.filename,\n lineno: event.lineno,\n colno: event.colno\n }\n })\n })\n }\n\n /**\n * Promise错误处理\n */\n private setupPromiseErrorHandler(): void {\n window.addEventListener('unhandledrejection', (event) => {\n this.capture({\n type: 'promise',\n message: event.reason?.message || String(event.reason),\n stack: event.reason?.stack,\n context: {\n reason: event.reason\n }\n })\n })\n }\n\n /**\n * 网络请求错误处理\n */\n private setupNetworkErrorHandler(): void {\n // 拦截fetch\n if (typeof window.fetch !== 'undefined') {\n this.originalFetch = window.fetch\n const self = this\n\n window.fetch = function (...args: Parameters<typeof fetch>) {\n return self.originalFetch!\n .apply(this, args as any)\n .catch((error) => {\n const url = typeof args[0] === 'string' ? args[0] : String(args[0])\n const method = args[1]?.method || 'GET'\n\n self.capture({\n type: 'network',\n message: `Network error: ${method} ${url}`,\n context: {\n url,\n method,\n error: error.message\n }\n })\n\n throw error\n })\n }\n }\n\n // 拦截XMLHttpRequest(简化版)\n if (typeof window.XMLHttpRequest !== 'undefined') {\n this.originalXHR = window.XMLHttpRequest\n const self = this\n\n const OriginalXHR = this.originalXHR\n window.XMLHttpRequest = function () {\n const xhr = new OriginalXHR()\n const originalOpen = xhr.open\n const originalSend = xhr.send\n let url = ''\n let method = ''\n\n xhr.open = function (...args: any[]) {\n method = args[0] || 'GET'\n url = String(args[1] || '')\n return originalOpen.apply(this, args as any)\n }\n\n xhr.send = function (...args: any[]) {\n xhr.addEventListener('error', () => {\n self.capture({\n type: 'network',\n message: `XHR error: ${method} ${url}`,\n context: {\n url,\n method,\n status: xhr.status\n }\n })\n })\n\n return originalSend.apply(this, args as any)\n }\n\n return xhr\n } as any\n }\n }\n\n /**\n * 资源加载错误处理\n */\n private setupResourceErrorHandler(): void {\n window.addEventListener('error', (event) => {\n if (event.target !== window) {\n const target = event.target as HTMLElement\n this.capture({\n type: 'resource',\n message: `Resource load error: ${target.tagName}`,\n context: {\n tagName: target.tagName,\n src: (target as any).src || (target as any).href\n }\n })\n }\n }, true)\n }\n\n /**\n * 白屏检测\n */\n private setupBlankScreenDetection(): void {\n console.log('[ErrorMonitorWeb] Setting up blank screen detection...')\n const config =\n typeof this.config.blankScreenDetection === 'boolean'\n ? {}\n : this.config.blankScreenDetection\n\n console.log('[ErrorMonitorWeb] Blank screen config:', config)\n this.blankScreenDetector = createBlankScreenDetector(config)\n\n this.blankScreenDetector.start((report) => {\n console.log('[ErrorMonitorWeb] Blank screen detected!', report)\n this.capture({\n type: report.type,\n message: report.message,\n context: report.context\n })\n })\n\n console.log('[ErrorMonitorWeb] Blank screen detection started')\n }\n\n /**\n * 手动上报错误\n */\n captureError(error: Error, context?: Record<string, any>): void {\n this.capture({\n type: 'custom',\n message: error.message,\n stack: error.stack,\n context\n })\n }\n\n /**\n * 手动上报消息\n */\n captureMessage(message: string, level: string = 'info'): void {\n this.capture({\n type: 'custom',\n message,\n context: { level }\n })\n }\n\n /**\n * 销毁实例\n */\n destroy(): void {\n console.log('[ErrorMonitorWeb] Destroying instance...')\n\n // 停止白屏检测\n if (this.blankScreenDetector) {\n console.log('[ErrorMonitorWeb] Stopping blank screen detector...')\n this.blankScreenDetector.stop()\n this.blankScreenDetector = null\n }\n\n // 恢复原生方法\n if (this.originalFetch && window.fetch !== this.originalFetch) {\n window.fetch = this.originalFetch\n }\n\n if (this.originalXHR && window.XMLHttpRequest !== this.originalXHR) {\n window.XMLHttpRequest = this.originalXHR\n }\n\n super.destroy()\n\n console.log('[ErrorMonitorWeb] Instance destroyed')\n }\n}\n\n/**\n * 创建Web端实例工厂函数\n */\nexport function createErrorMonitorWeb(config: WebConfig): ErrorMonitorWeb {\n return new ErrorMonitorWeb(config)\n}\n\n// 默认导出\nexport default ErrorMonitorWeb\n"],"names":["h","l","g","r","t","c","d","i","n","o","s","BlankScreenDetector","config","callback","isBlank","report","domCheck","perfCheck","totalElements","bodyElements","_a","hasBody","hasContent","testElements","scriptElements","elementsWithoutTestAndScripts","info","timing","navigationStart","domContentLoaded","loadComplete","firstPaint","firstContentfulPaint","perfEntries","fp","e","fcp","domInfo","perfInfo","createBlankScreenDetector","ErrorMonitorWeb","ErrorMonitor","captureJs","capturePromise","_b","captureNetwork","_c","captureResource","_d","event","self","args","error","url","method","OriginalXHR","xhr","originalOpen","originalSend","target","context","message","level","createErrorMonitorWeb"],"mappings":"4GAAA,SAASA,GAAI,CACX,MAAO,GAAG,KAAK,IAAG,CAAE,IAAI,KAAK,OAAM,EAAG,SAAS,EAAE,EAAE,UAAU,EAAG,EAAE,CAAC,EACrE,CACA,SAASC,GAAI,CACX,MAAO,GAAG,KAAK,IAAG,CAAE,IAAI,KAAK,OAAM,EAAG,SAAS,EAAE,EAAE,UAAU,EAAG,EAAE,CAAC,EACrE,CACA,MAAMC,CAAE,CACN,YAAY,EAAG,CACb,KAAK,cAAgB,GAAI,KAAK,YAAc,CAAA,EAAI,KAAK,eAAiB,GAAI,KAAK,QAAU,CAAA,EAAI,KAAK,UAAYF,EAAC,EAAI,KAAK,OAAS,CAC/H,YAAa,CACX,GAAI,GACJ,QAAS,GACT,QAAS,GACT,SAAU,GACV,QAAS,EACjB,EACM,OAAQ,CACN,aAAc,CAAA,EACd,WAAY,CAAA,EACZ,SAAU,MAClB,EACM,OAAQ,CACN,MAAO,IACP,UAAW,EACnB,EACM,WAAY,EACZ,gBAAiB,EACjB,QAAS,GACT,MAAO,GACP,GAAG,CACT,CACE,CAIA,aAAa,EAAG,CACd,KAAK,OAAS,CAAE,GAAG,KAAK,OAAQ,GAAG,CAAC,EAAI,KAAK,OAAO,OAAS,QAAQ,IAAI,iCAAkC,KAAK,MAAM,CACxH,CAIA,QAAS,CACP,KAAK,OAAO,QAAU,GAAI,QAAQ,IAAI,4BAA4B,CACpE,CAIA,SAAU,CACR,KAAK,OAAO,QAAU,GAAI,QAAQ,IAAI,6BAA6B,CACrE,CAIA,UAAU,EAAG,CACX,KAAK,OAAO,SAAW,KAAK,OAAO,OAAS,CAAA,GAAK,KAAK,OAAO,OAAO,eAAiB,KAAK,OAAO,OAAO,aAAe,IAAK,KAAK,OAAO,OAAO,aAAa,KAAK,CAAC,CACpK,CAIA,aAAa,EAAG,CACd,IAAIG,EACJ,GAAI,GAAGA,EAAI,KAAK,OAAO,SAAW,MAAQA,EAAE,cAAe,OAC3D,MAAMC,EAAI,KAAK,OAAO,OAAO,aAAa,QAAQ,CAAC,EACnDA,EAAI,IAAM,KAAK,OAAO,OAAO,aAAa,OAAOA,EAAG,CAAC,CACvD,CAIA,cAAc,EAAG,CACf,KAAK,OAAO,WAAa,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,CAAC,CAAC,CACrD,CAIA,mBAAmB,EAAG,CACpB,KAAK,OAAO,gBAAkB,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,CAAC,CAAC,CAC1D,CAIA,MAAO,CACL,GAAI,KAAK,cAAe,CACtB,QAAQ,KAAK,oCAAoC,EACjD,MACF,CACA,KAAK,cAAgB,GAAI,KAAK,QAAQ,QAAS,GAAM,CACnD,IAAI,GACH,EAAI,EAAE,QAAU,MAAQ,EAAE,KAAK,EAAG,IAAI,CACzC,CAAC,EAAG,QAAQ,IAAI,yCAA0C,KAAK,OAAO,KAAK,CAC7E,CAIA,IAAI,EAAG,CACL,IAAI,EACJ,KAAK,QAAQ,KAAK,CAAC,EAAG,KAAK,iBAAmB,EAAI,EAAE,QAAU,MAAQ,EAAE,KAAK,EAAG,IAAI,EACtF,CAIA,QAAQ,EAAG,EAAG,CACZ,IAAIC,EAAGC,EACP,GAAI,CAAC,KAAK,cAAe,CACvB,QAAQ,KAAK,gCAAgC,EAC7C,MACF,CACA,GAAI,KAAK,OAAO,UAAY,GAC1B,OACF,MAAMH,EAAI,aAAa,MAAQ,CAC7B,KAAM,SACN,QAAS,EAAE,QACX,MAAO,EAAE,MACT,QAAS,CAAA,CACf,EAAQ,EAAGI,EAAI,CACT,MAAO,QACP,KAAM,CAAA,EACN,MAAO,CAAA,EACP,KAAM,CAAA,EACN,aAAc,GACd,WAAY,GACZ,GAAG,CACT,EACI,GAAI,CAACA,EAAE,YAAc,KAAK,aAAaJ,CAAC,EAAG,CACzC,KAAK,OAAO,OAAS,QAAQ,IAAI,iCAAkCA,EAAE,OAAO,EAC5E,MACF,CACA,GAAI,CAACI,EAAE,cAAgB,KAAK,OAAO,kBAAoB,QAAU,KAAK,OAAM,EAAK,KAAK,OAAO,gBAC3F,OACF,IAAI,EAAIJ,EACR,UAAWK,KAAK,KAAK,QAAS,CAC5B,MAAM,GAAKH,EAAIG,EAAE,gBAAkB,KAAO,OAASH,EAAE,KAAKG,EAAGL,CAAC,EAC9D,GAAI,IAAM,KACR,OACF,IAAM,SAAW,EAAI,EACvB,CACA,MAAMM,EAAI,CACR,MAAO,KAAK,OAAO,MACnB,UAAW,KAAK,IAAG,EACnB,UAAW,KAAK,UAChB,QAASR,EAAC,EACV,KAAM,EAAE,KACR,MAAOM,EAAE,MACT,QAAS,EAAE,QACX,MAAO,EAAE,MACT,QAAS,CACP,UAAW,OAAO,UAAY,IAAM,UAAU,UAAY,GAC1D,IAAK,OAAO,SAAW,IAAM,SAAS,KAAO,GAC7C,SAAU,CACR,MAAO,OAAO,OAAS,IAAM,OAAO,WAAa,EACjD,OAAQ,OAAO,OAAS,IAAM,OAAO,YAAc,CAC7D,EACQ,OAAQA,EAAE,KAAK,IAAM,KAAK,OAAO,OACjC,KAAM,CAAE,GAAG,KAAK,OAAO,KAAM,GAAGA,EAAE,IAAI,CAC9C,EACM,YAAa,CAAC,GAAG,KAAK,WAAW,EACjC,MAAO,CAAE,GAAG,EAAE,QAAS,GAAGA,EAAE,KAAK,CACvC,EACI,UAAWC,KAAK,KAAK,QAAS,CAC5B,MAAM,GAAKF,EAAIE,EAAE,eAAiB,KAAO,OAASF,EAAE,KAAKE,EAAGC,CAAC,EAC7D,IAAM,QAAU,OAAO,OAAOA,EAAG,CAAC,CACpC,CACA,KAAK,OAAOA,CAAC,CACf,CAIA,aAAa,EAAG,CACd,IAAIC,EACJ,GAAI,CAAC,KAAK,OAAO,OAAQ,MAAO,GAChC,KAAM,CAAE,aAAcN,EAAG,WAAYD,EAAG,SAAUI,CAAC,EAAK,KAAK,OAAO,OACpE,GAAIH,GAAKA,EAAE,OAAS,GAClB,UAAWK,KAAKL,EACd,GAAIK,EAAE,KAAK,EAAE,OAAO,EAClB,MAAO,GAEb,GAAIN,GAAKA,EAAE,OAAS,IAAOO,EAAI,EAAE,UAAY,MAAQA,EAAE,KACrD,UAAWD,KAAKN,EACd,GAAIM,EAAE,KAAK,EAAE,QAAQ,GAAG,EACtB,MAAO,GAEb,MAAO,EACT,CAIA,aAAa,EAAG,EAAG,CACjB,KAAK,QAAQ,EAAG,CAAC,CACnB,CAIA,eAAe,EAAG,EAAI,OAAQN,EAAG,CAC/B,KAAK,QAAQ,CACX,KAAM,SACN,QAAS,EACT,QAAS,CAAA,CACf,EAAO,CAAE,GAAGA,EAAG,MAAO,CAAC,CAAE,CACvB,CAIA,OAAO,EAAG,CACR,IAAIA,EACJ,IAAIC,EAAI,EACR,UAAW,KAAK,KAAK,QAAS,CAC5B,MAAMM,GAAKP,EAAI,EAAE,eAAiB,KAAO,OAASA,EAAE,KAAK,EAAG,CAAC,EAC7DO,IAAM,SAAWN,EAAIM,EACvB,CACA,KAAK,aAAaN,CAAC,CACrB,CAIA,cAAc,EAAG,CACf,KAAK,YAAY,KAAK,CACpB,UAAW,EAAE,WAAa,KAAK,IAAG,EAClC,KAAM,EAAE,KACR,QAAS,EAAE,QACX,KAAM,EAAE,IACd,CAAK,EAAG,KAAK,YAAY,OAAS,KAAK,gBAAkB,KAAK,YAAY,MAAK,CAC7E,CAIA,YAAa,CACX,OAAOH,EAAC,CACV,CAIA,QAAQ,EAAG,CACT,KAAK,OAAO,OAAS,EAAE,GAAI,KAAK,OAAO,KAAO,CAAE,GAAG,KAAK,OAAO,KAAM,GAAG,CAAC,CAC3E,CAIA,aAAa,EAAG,CACd,GAAI,OAAO,UAAY,IAAK,OAC5B,MAAM,EAAI,KAAK,UAAU,CAAC,EAC1B,GAAI,UAAU,WAAY,CACxB,MAAME,EAAI,IAAI,KAAK,CAAC,CAAC,EAAG,CAAE,KAAM,mBAAoB,EACpD,UAAU,WAAW,KAAK,OAAO,IAAKA,CAAC,EACvC,MACF,CACA,OAAO,MAAQ,KAAO,MAAM,KAAK,OAAO,IAAK,CAC3C,OAAQ,OACR,KAAM,EACN,UAAW,GACX,QAAS,CACP,eAAgB,kBACxB,CACA,CAAK,EAAE,MAAOA,GAAM,CACd,QAAQ,MAAM,wCAAyCA,CAAC,CAC1D,CAAC,CACH,CAIA,SAAU,CACR,KAAK,QAAQ,QAAS,GAAM,CAC1B,IAAI,GACH,EAAI,EAAE,WAAa,MAAQ,EAAE,KAAK,CAAC,CACtC,CAAC,EAAG,KAAK,QAAU,CAAA,EAAI,KAAK,YAAc,GAAI,KAAK,cAAgB,GAAI,QAAQ,IAAI,0BAA0B,CAC/G,CACF,CC/NO,MAAMQ,CAAoB,CAM/B,YAAYC,EAA4B,GAAI,CAJ5C,KAAQ,WAAqB,EAC7B,KAAQ,QAAyB,KACjC,KAAQ,cAAyB,GAG/B,KAAK,OAAS,CACZ,eAAgBA,EAAO,gBAAkB,IACzC,YAAaA,EAAO,aAAe,GACnC,cAAeA,EAAO,eAAiB,IACvC,UAAWA,EAAO,WAAa,EAC/B,iBAAkBA,EAAO,mBAAqB,GAC9C,YAAaA,EAAO,cAAgB,IAAM,GAAA,CAE9C,CAKA,MAAMC,EAAqD,CACzD,QAAQ,IAAI,0DAA0D,EACtE,QAAQ,IAAI,gCAAiC,KAAK,MAAM,EAGxD,WAAW,IAAM,CACf,QAAQ,IAAI,uEAAuE,EACnF,KAAK,aAAaA,CAAQ,CAC5B,EAAG,KAAK,OAAO,cAAc,CAC/B,CAKQ,aAAaA,EAAqD,CACxE,KAAK,aACL,QAAQ,IAAI,gCAAgC,KAAK,UAAU,IAAI,KAAK,OAAO,SAAS,EAAE,EAEtF,MAAMC,EAAU,KAAK,aAAA,EAGrB,GAFA,QAAQ,IAAI,yCAA0CA,CAAO,EAEzDA,GAAW,CAAC,KAAK,cAAe,CAElC,QAAQ,IAAI,iEAAiE,EAC7E,KAAK,cAAgB,GACrB,MAAMC,EAAS,KAAK,eAAA,EACpB,QAAQ,IAAI,0CAA2CA,CAAM,EAC7DF,EAASE,CAAM,CACjB,CAGI,KAAK,WAAa,KAAK,OAAO,WAAa,CAACD,GAC9C,KAAK,QAAU,OAAO,WAAW,IAAM,CACrC,KAAK,aAAaD,CAAQ,CAC5B,EAAG,KAAK,OAAO,aAAa,EAC5B,QAAQ,IAAI,kDAAkD,KAAK,OAAO,aAAa,IAAI,GAE3F,QAAQ,IAAI,gDAAiD,KAAK,WAAY,YAAaC,CAAO,CAEtG,CAKQ,cAAwB,CAE9B,GAAI,KAAK,OAAO,cACd,eAAQ,IAAI,kDAAkD,EACvD,GAIT,MAAME,EAAW,KAAK,iBAAA,EAEtB,GADA,QAAQ,IAAI,0CAA2CA,CAAQ,EAC3DA,EAAS,QACX,eAAQ,IAAI,wDAAwD,EAC7D,GAIT,GAAI,KAAK,OAAO,iBAAkB,CAChC,MAAMC,EAAY,KAAK,uBAAA,EAEvB,GADA,QAAQ,IAAI,kDAAmDA,CAAS,EACpEA,EAAU,QACZ,eAAQ,IAAI,gEAAgE,EACrE,EAEX,CAEA,eAAQ,IAAI,6DAA6D,EAClE,EACT,CAKQ,kBAAoD,OAC1D,MAAMC,EAAgB,SAAS,iBAAiB,GAAG,EAAE,OAC/CC,IAAeC,EAAA,SAAS,OAAT,YAAAA,EAAe,SAAS,SAAU,EAGjDC,EAAU,CAAC,CAAC,SAAS,KACrBC,EAAaH,EAAe,EAG5BI,EAAe,SAAS,iBAAiB,0CAA0C,EAAE,OAGrFC,EAAiB,SAAS,iBAAiB,QAAQ,EAAE,OAErDC,EAAgCP,EAAgBK,EAAeC,EAG/DV,EAAU,CAACO,GAAWI,EAAgC,KAAK,OAAO,aAAe,CAACH,EAElFI,EAAO,CACX,cAAAR,EACA,aAAAC,EACA,QAAAE,EACA,WAAAC,EACA,aAAAC,EACA,eAAAC,EACA,8BAAAC,EACA,YAAa,KAAK,OAAO,WAAA,EAG3B,eAAQ,IAAI,iCAAkCC,CAAI,EAE3C,CACL,QAAAZ,EACA,KAAAY,CAAA,CAEJ,CAKQ,wBAA6D,OACnE,GAAI,CAAC,OAAO,aAAe,CAAC,OAAO,YAAY,OAC7C,MAAO,CAAE,QAAS,EAAA,EAGpB,MAAMC,EAAS,OAAO,YAAY,OAC5BC,EAAkBD,EAAO,gBAEzBE,EAAmBF,EAAO,yBAA2BC,EACrDE,EAAeH,EAAO,aAAeC,EAG3C,IAAIG,EACAC,EAEJ,MAAMC,GAAcb,EAAA,YAAY,mBAAZ,YAAAA,EAAA,iBAA+B,SACnD,GAAIa,EAAa,CACf,MAAMC,EAAKD,EAAY,KAAKE,GAAKA,EAAE,OAAS,aAAa,EACnDC,EAAMH,EAAY,KAAKE,GAAKA,EAAE,OAAS,wBAAwB,EACrEJ,EAAaG,GAAA,YAAAA,EAAI,UACjBF,EAAuBI,GAAA,YAAAA,EAAK,SAC9B,CAQA,MAAO,CACL,QALAN,EAAe,IACdC,IAAe,QAAaC,IAAyB,SACtDH,EAAmB,IAInB,OAAQ,CACN,iBAAAA,EACA,aAAAC,EACA,WAAAC,EACA,qBAAAC,CAAA,CACF,CAEJ,CAKQ,gBAAoC,OAC1C,MAAMK,EAAU,KAAK,iBAAA,EACfC,EAAW,KAAK,OAAO,iBAAmB,KAAK,uBAAA,EAA2B,CAAA,EAEhF,MAAO,CACL,KAAM,eACN,QAAS,mBACT,QAAS,CACP,UAAW,KAAK,IAAA,EAChB,IAAK,OAAO,SAAS,KACrB,YAAa,SAAS,iBAAiB,GAAG,EAAE,OAC5C,eAAclB,EAAA,SAAS,OAAT,YAAAA,EAAe,SAAS,SAAU,EAChD,WAAYiB,EAAQ,KAAK,WACzB,kBAAmBC,EAAS,MAAA,CAC9B,CAEJ,CAKA,MAAa,CACX,QAAQ,IAAI,0DAA0D,EAClE,KAAK,UAAY,OACnB,OAAO,aAAa,KAAK,OAAO,EAChC,KAAK,QAAU,KACf,QAAQ,IAAI,6CAA6C,GAE3D,QAAQ,IAAI,sDAAsD,CACpE,CAKA,OAAc,CACZ,KAAK,KAAA,EACL,KAAK,WAAa,EAClB,KAAK,cAAgB,EACvB,CACF,CAKO,SAASC,EAA0B3B,EAAiD,CACzF,OAAO,IAAID,EAAoBC,CAAM,CACvC,CClOO,MAAM4B,UAAwBC,CAAa,CAMhD,YAAY7B,EAAmB,CAC7B,MAAMA,CAAM,EALd,KAAQ,cAAqC,KAC7C,KAAQ,YAA4C,KACpD,KAAQ,oBAAkD,KAIxD,KAAK,OAASA,CAChB,CAKA,MAAa,aAGX,GAFA,MAAM,KAAA,EAEF,OAAO,OAAW,IAAa,CACjC,QAAQ,KAAK,8CAA8C,EAC3D,MACF,CAKA,MAAM8B,IAAYtB,EAAA,KAAK,OAAO,cAAZ,YAAAA,EAAyB,MAAO,IAAS,KAAK,OAAO,kBAAoB,GACrFuB,IAAiBC,EAAA,KAAK,OAAO,cAAZ,YAAAA,EAAyB,WAAY,IAAS,KAAK,OAAO,uBAAyB,GACpGC,IAAiBC,EAAA,KAAK,OAAO,cAAZ,YAAAA,EAAyB,WAAY,IAAS,KAAK,OAAO,uBAAyB,GACpGC,IAAkBC,EAAA,KAAK,OAAO,cAAZ,YAAAA,EAAyB,YAAa,IAAS,KAAK,OAAO,wBAA0B,GAGzGN,GACF,KAAK,oBAAA,EAGHC,GACF,KAAK,yBAAA,EAGHE,GACF,KAAK,yBAAA,EAGHE,GACF,KAAK,0BAAA,EAIH,KAAK,OAAO,sBACd,KAAK,0BAAA,EAGP,QAAQ,IAAI,4CAA4C,CAC1D,CAKQ,qBAA4B,CAClC,OAAO,iBAAiB,QAAUE,GAAU,OAC1C,KAAK,QAAQ,CACX,KAAM,KACN,QAASA,EAAM,QACf,OAAO7B,EAAA6B,EAAM,QAAN,YAAA7B,EAAa,MACpB,QAAS,CACP,SAAU6B,EAAM,SAChB,OAAQA,EAAM,OACd,MAAOA,EAAM,KAAA,CACf,CACD,CACH,CAAC,CACH,CAKQ,0BAAiC,CACvC,OAAO,iBAAiB,qBAAuBA,GAAU,SACvD,KAAK,QAAQ,CACX,KAAM,UACN,UAAS7B,EAAA6B,EAAM,SAAN,YAAA7B,EAAc,UAAW,OAAO6B,EAAM,MAAM,EACrD,OAAOL,EAAAK,EAAM,SAAN,YAAAL,EAAc,MACrB,QAAS,CACP,OAAQK,EAAM,MAAA,CAChB,CACD,CACH,CAAC,CACH,CAKQ,0BAAiC,CAEvC,GAAI,OAAO,OAAO,MAAU,IAAa,CACvC,KAAK,cAAgB,OAAO,MAC5B,MAAMC,EAAO,KAEb,OAAO,MAAQ,YAAaC,EAAgC,CAC1D,OAAOD,EAAK,cACT,MAAM,KAAMC,CAAW,EACvB,MAAOC,GAAU,OAChB,MAAMC,EAAM,OAAOF,EAAK,CAAC,GAAM,SAAWA,EAAK,CAAC,EAAI,OAAOA,EAAK,CAAC,CAAC,EAC5DG,IAASlC,EAAA+B,EAAK,CAAC,IAAN,YAAA/B,EAAS,SAAU,MAElC,MAAA8B,EAAK,QAAQ,CACX,KAAM,UACN,QAAS,kBAAkBI,CAAM,IAAID,CAAG,GACxC,QAAS,CACP,IAAAA,EACA,OAAAC,EACA,MAAOF,EAAM,OAAA,CACf,CACD,EAEKA,CACR,CAAC,CACL,CACF,CAGA,GAAI,OAAO,OAAO,eAAmB,IAAa,CAChD,KAAK,YAAc,OAAO,eAC1B,MAAMF,EAAO,KAEPK,EAAc,KAAK,YACzB,OAAO,eAAiB,UAAY,CAClC,MAAMC,EAAM,IAAID,EACVE,EAAeD,EAAI,KACnBE,EAAeF,EAAI,KACzB,IAAIH,EAAM,GACNC,EAAS,GAEb,OAAAE,EAAI,KAAO,YAAaL,EAAa,CACnC,OAAAG,EAASH,EAAK,CAAC,GAAK,MACpBE,EAAM,OAAOF,EAAK,CAAC,GAAK,EAAE,EACnBM,EAAa,MAAM,KAAMN,CAAW,CAC7C,EAEAK,EAAI,KAAO,YAAaL,EAAa,CACnC,OAAAK,EAAI,iBAAiB,QAAS,IAAM,CAClCN,EAAK,QAAQ,CACX,KAAM,UACN,QAAS,cAAcI,CAAM,IAAID,CAAG,GACpC,QAAS,CACP,IAAAA,EACA,OAAAC,EACA,OAAQE,EAAI,MAAA,CACd,CACD,CACH,CAAC,EAEME,EAAa,MAAM,KAAMP,CAAW,CAC7C,EAEOK,CACT,CACF,CACF,CAKQ,2BAAkC,CACxC,OAAO,iBAAiB,QAAUP,GAAU,CAC1C,GAAIA,EAAM,SAAW,OAAQ,CAC3B,MAAMU,EAASV,EAAM,OACrB,KAAK,QAAQ,CACX,KAAM,WACN,QAAS,wBAAwBU,EAAO,OAAO,GAC/C,QAAS,CACP,QAASA,EAAO,QAChB,IAAMA,EAAe,KAAQA,EAAe,IAAA,CAC9C,CACD,CACH,CACF,EAAG,EAAI,CACT,CAKQ,2BAAkC,CACxC,QAAQ,IAAI,wDAAwD,EACpE,MAAM/C,EACJ,OAAO,KAAK,OAAO,sBAAyB,UACxC,CAAA,EACA,KAAK,OAAO,qBAElB,QAAQ,IAAI,yCAA0CA,CAAM,EAC5D,KAAK,oBAAsB2B,EAA0B3B,CAAM,EAE3D,KAAK,oBAAoB,MAAOG,GAAW,CACzC,QAAQ,IAAI,2CAA4CA,CAAM,EAC9D,KAAK,QAAQ,CACX,KAAMA,EAAO,KACb,QAASA,EAAO,QAChB,QAASA,EAAO,OAAA,CACjB,CACH,CAAC,EAED,QAAQ,IAAI,kDAAkD,CAChE,CAKA,aAAaqC,EAAcQ,EAAqC,CAC9D,KAAK,QAAQ,CACX,KAAM,SACN,QAASR,EAAM,QACf,MAAOA,EAAM,MACb,QAAAQ,CAAA,CACD,CACH,CAKA,eAAeC,EAAiBC,EAAgB,OAAc,CAC5D,KAAK,QAAQ,CACX,KAAM,SACN,QAAAD,EACA,QAAS,CAAE,MAAAC,CAAA,CAAM,CAClB,CACH,CAKA,SAAgB,CACd,QAAQ,IAAI,0CAA0C,EAGlD,KAAK,sBACP,QAAQ,IAAI,qDAAqD,EACjE,KAAK,oBAAoB,KAAA,EACzB,KAAK,oBAAsB,MAIzB,KAAK,eAAiB,OAAO,QAAU,KAAK,gBAC9C,OAAO,MAAQ,KAAK,eAGlB,KAAK,aAAe,OAAO,iBAAmB,KAAK,cACrD,OAAO,eAAiB,KAAK,aAG/B,MAAM,QAAA,EAEN,QAAQ,IAAI,sCAAsC,CACpD,CACF,CAKO,SAASC,EAAsBnD,EAAoC,CACxE,OAAO,IAAI4B,EAAgB5B,CAAM,CACnC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Breadcrumb } from 'error-monitor-core';
|
|
2
|
+
import { Config } from 'error-monitor-core';
|
|
3
|
+
import { ErrorMonitor } from 'error-monitor-core';
|
|
4
|
+
import { Plugin as Plugin_2 } from 'error-monitor-core';
|
|
5
|
+
|
|
6
|
+
export declare interface BlankScreenConfig {
|
|
7
|
+
detectionDelay?: number;
|
|
8
|
+
minElements?: number;
|
|
9
|
+
checkInterval?: number;
|
|
10
|
+
maxChecks?: number;
|
|
11
|
+
checkPerformance?: boolean;
|
|
12
|
+
customCheck?: () => boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export declare class BlankScreenDetector {
|
|
16
|
+
private config;
|
|
17
|
+
private checkCount;
|
|
18
|
+
private timerId;
|
|
19
|
+
private isBlankScreen;
|
|
20
|
+
constructor(config?: BlankScreenConfig);
|
|
21
|
+
start(callback: (report: BlankScreenReport) => void): void;
|
|
22
|
+
private performCheck;
|
|
23
|
+
private checkIfBlank;
|
|
24
|
+
private checkDOMElements;
|
|
25
|
+
private checkPerformanceTiming;
|
|
26
|
+
private generateReport;
|
|
27
|
+
stop(): void;
|
|
28
|
+
reset(): void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare interface BlankScreenReport {
|
|
32
|
+
type: 'blank-screen';
|
|
33
|
+
message: string;
|
|
34
|
+
context: {
|
|
35
|
+
timestamp: number;
|
|
36
|
+
url: string;
|
|
37
|
+
domElements: number;
|
|
38
|
+
bodyElements: number;
|
|
39
|
+
hasContent: boolean;
|
|
40
|
+
performanceTiming?: {
|
|
41
|
+
domContentLoaded?: number;
|
|
42
|
+
loadComplete?: number;
|
|
43
|
+
firstPaint?: number;
|
|
44
|
+
firstContentfulPaint?: number;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { Breadcrumb }
|
|
50
|
+
|
|
51
|
+
export { Config }
|
|
52
|
+
|
|
53
|
+
export declare function createBlankScreenDetector(config?: BlankScreenConfig): BlankScreenDetector;
|
|
54
|
+
|
|
55
|
+
export declare function createErrorMonitorWeb(config: WebConfig): ErrorMonitorWeb;
|
|
56
|
+
|
|
57
|
+
export { ErrorMonitor }
|
|
58
|
+
|
|
59
|
+
declare class ErrorMonitorWeb extends ErrorMonitor {
|
|
60
|
+
protected config: WebConfig;
|
|
61
|
+
private originalFetch;
|
|
62
|
+
private originalXHR;
|
|
63
|
+
private blankScreenDetector;
|
|
64
|
+
constructor(config: WebConfig);
|
|
65
|
+
init(): void;
|
|
66
|
+
private setupJsErrorHandler;
|
|
67
|
+
private setupPromiseErrorHandler;
|
|
68
|
+
private setupNetworkErrorHandler;
|
|
69
|
+
private setupResourceErrorHandler;
|
|
70
|
+
private setupBlankScreenDetection;
|
|
71
|
+
captureError(error: Error, context?: Record<string, any>): void;
|
|
72
|
+
captureMessage(message: string, level?: string): void;
|
|
73
|
+
destroy(): void;
|
|
74
|
+
}
|
|
75
|
+
export { ErrorMonitorWeb }
|
|
76
|
+
export default ErrorMonitorWeb;
|
|
77
|
+
|
|
78
|
+
export { Plugin_2 as Plugin }
|
|
79
|
+
|
|
80
|
+
export declare interface WebConfig extends Config {
|
|
81
|
+
captureJsErrors?: boolean;
|
|
82
|
+
capturePromiseErrors?: boolean;
|
|
83
|
+
captureNetworkErrors?: boolean;
|
|
84
|
+
captureResourceErrors?: boolean;
|
|
85
|
+
blankScreenDetection?: boolean | BlankScreenConfig;
|
|
86
|
+
customReporter?: (data: any) => void;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { }
|