@w57124/exs-monitor-sdk 0.1.2 → 0.1.4

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 CHANGED
@@ -1,4 +1,4 @@
1
- # FE Monitor SDK
1
+ # EXS Monitor SDK
2
2
 
3
3
  前端监控 SDK:错误上报、性能指标、网络拦截。打包为 ESM/CJS/IIFE,支持浏览器直接注入与构建工具使用。
4
4
 
@@ -95,13 +95,13 @@ initMonitor({
95
95
  - `networkMaxBodyLength` 控制最大字符数,超出部分会被截断并添加 `...[truncated]` 标记
96
96
  - 设为 `0` 或负数可完全禁用 body 上报以节省带宽
97
97
 
98
- 浏览器直接使用(IIFE,全局变量 `FEMonitorSDK`)
98
+ 浏览器直接使用(IIFE,全局变量 `EXSMonitorSDK`)
99
99
 
100
100
  ```html
101
101
  <script src="/dist/index.global.js"></script>
102
102
  <script>
103
103
  // 方式一:直接调用导出函数
104
- const client = FEMonitorSDK.initMonitor({ dsn: 'https://...' })
104
+ const client = EXSMonitorSDK.initMonitor({ dsn: 'https://...' })
105
105
  client.capture('custom', { hello: 'world' })
106
106
 
107
107
  // 方式二:在 script 之前放置全局配置,可自动初始化
@@ -1,4 +1,4 @@
1
- var FEMonitorSDK=(function(exports){'use strict';var P=Object.defineProperty;var q=(t,e)=>()=>(t&&(e=t(t=0)),e);var V=(t,e)=>{for(var n in e)P(t,n,{get:e[n],enumerable:true});};var I={};V(I,{openEventViewer:()=>w});function F(){let t=document.createElement("div");return t.id="__femonitor_viewer__",t.style.position="fixed",t.style.top="0",t.style.left="0",t.style.right="0",t.style.bottom="0",t.style.background="rgba(0,0,0,0.5)",t.style.zIndex="99999",t.style.display="flex",t.style.alignItems="center",t.style.justifyContent="center",t}function A(t){let e=document.createElement("div");return e.style.width="80%",e.style.maxWidth="960px",e.style.maxHeight="80%",e.style.overflow="auto",e.style.background="#fff",e.style.borderRadius="8px",e.style.boxShadow="0 10px 30px rgba(0,0,0,0.2)",e.style.padding="16px",e.innerHTML=t,e}function w(t,e){if(typeof document>"u")return;let n=document.getElementById("__femonitor_viewer__");n&&n.remove();let o=F(),s=t.slice().reverse().map(l=>`<tr>
1
+ var EXSMonitorSDK=(function(exports){'use strict';var P=Object.defineProperty;var q=(t,e)=>()=>(t&&(e=t(t=0)),e);var V=(t,e)=>{for(var n in e)P(t,n,{get:e[n],enumerable:true});};var I={};V(I,{openEventViewer:()=>w});function F(){let t=document.createElement("div");return t.id="__femonitor_viewer__",t.style.position="fixed",t.style.top="0",t.style.left="0",t.style.right="0",t.style.bottom="0",t.style.background="rgba(0,0,0,0.5)",t.style.zIndex="99999",t.style.display="flex",t.style.alignItems="center",t.style.justifyContent="center",t}function A(t){let e=document.createElement("div");return e.style.width="80%",e.style.maxWidth="960px",e.style.maxHeight="80%",e.style.overflow="auto",e.style.background="#fff",e.style.borderRadius="8px",e.style.boxShadow="0 10px 30px rgba(0,0,0,0.2)",e.style.padding="16px",e.innerHTML=t,e}function w(t,e){if(typeof document>"u")return;let n=document.getElementById("__femonitor_viewer__");n&&n.remove();let o=F(),s=t.slice().reverse().map(l=>`<tr>
2
2
  <td style="white-space:nowrap">${new Date(l.timestamp).toLocaleString()}</td>
3
3
  <td>${l.type}</td>
4
4
  <td><pre style="margin:0;white-space:pre-wrap">${K(JSON.stringify(l.context??{},null,2))}</pre></td>
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ui/viewer.ts","../src/utils/uid.ts","../src/utils/env.ts","../src/core/Transport.ts","../src/core/Client.ts","../src/index.ts","../src/utils/hotkey.ts","../src/integrations/errors.ts","../src/integrations/perf.ts","../src/integrations/network.ts","../src/integrations/whitescreen.ts"],"names":["viewer_exports","__export","openEventViewer","createContainer","el","createPanel","html","panel","events","onClear","existing","container","rows","e","escapeHtml","btnClose","btnClear","str","init_viewer","__esmMin","createUid","c","r","getViewport","getPageUrl","DEFAULTS","Transport","options","event","payload","blob","flushWithBeacon","merged","raw","arr","MonitorClient","transportOptions","type","data","matchesHotkey","hotkey","parts","s","needCtrl","needShift","needAlt","keyPart","p","pressedKey","normalizeHotkey","bindViewerHotkey","open","openFallback","unbindViewerHotkey","finalHotkey","listener","prev","setupErrorIntegration","client","error","setupPerformanceIntegration","nav","po","list","entry","ls","setupNetworkIntegration","maxBodyLength","originalFetch","args","start","requestBody","body","truncateBody","text","res","end","url","isAllowedByHost","isUrlAllowedByPattern","responseBody","XHR","send","method","rest","meta","inputUrl","allow","block","host","rule","matchHost","suffix","testPattern","pattern","maxLength","marker","setupWhiteScreenIntegration","delay","minVisibleCount","minArea","sampleTimes","sampleInterval","run","multiSample","samples","worst","perf","getPerfSnapshot","countVisibleInViewport","viewportWidth","viewportHeight","count","nodes","isElementActuallyVisible","rect","style","times","interval","results","resolve","tick","left","fcp","lcpEntries","lcp","initMonitor","bindViewerHotkeyDefault","inst","key","mod","unbindViewerHotkeyDefault"],"mappings":"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","file":"index.global.js","sourcesContent":["import type { BaseEvent } from '../core/types'\n\n/** 创建遮罩容器 */\nfunction createContainer(): HTMLElement {\n const el = document.createElement('div')\n el.id = '__femonitor_viewer__'\n el.style.position = 'fixed'\n el.style.top = '0'\n el.style.left = '0'\n el.style.right = '0'\n el.style.bottom = '0'\n el.style.background = 'rgba(0,0,0,0.5)'\n el.style.zIndex = '99999'\n el.style.display = 'flex'\n el.style.alignItems = 'center'\n el.style.justifyContent = 'center'\n return el\n}\n\n/** 创建面板节点并填充 HTML */\nfunction createPanel(html: string): HTMLElement {\n const panel = document.createElement('div')\n panel.style.width = '80%'\n panel.style.maxWidth = '960px'\n panel.style.maxHeight = '80%'\n panel.style.overflow = 'auto'\n panel.style.background = '#fff'\n panel.style.borderRadius = '8px'\n panel.style.boxShadow = '0 10px 30px rgba(0,0,0,0.2)'\n panel.style.padding = '16px'\n panel.innerHTML = html\n return panel\n}\n\n/**\n * 打开事件查看器覆盖层\n * @param events 要展示的事件数组\n * @param onClear 点击清空后的回调\n */\nexport function openEventViewer(events: BaseEvent[], onClear?: () => void): void {\n if (typeof document === 'undefined') return\n const existing = document.getElementById('__femonitor_viewer__')\n if (existing) existing.remove()\n\n const container = createContainer()\n const rows = events\n .slice()\n .reverse()\n .map(e => `<tr>\n <td style=\"white-space:nowrap\">${new Date(e.timestamp).toLocaleString()}</td>\n <td>${e.type}</td>\n <td><pre style=\"margin:0;white-space:pre-wrap\">${escapeHtml(JSON.stringify(e.context ?? {}, null, 2))}</pre></td>\n </tr>`)\n .join('')\n\n const html = `\n <div style=\"display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:12px\">\n <h3 style=\"margin:0\">FE Monitor 本地事件 (${events.length})</h3>\n <div style=\"display:flex;gap:8px\">\n <button id=\"__fem_close__\">关闭</button>\n <button id=\"__fem_clear__\">清空</button>\n </div>\n </div>\n <table style=\"width:100%;border-collapse:collapse\">\n <thead>\n <tr>\n <th style=\"text-align:left;border-bottom:1px solid #eee;padding:8px 4px\">时间</th>\n <th style=\"text-align:left;border-bottom:1px solid #eee;padding:8px 4px\">类型</th>\n <th style=\"text-align:left;border-bottom:1px solid #eee;padding:8px 4px\">内容</th>\n </tr>\n </thead>\n <tbody>\n ${rows || '<tr><td colspan=\"3\" style=\"padding:12px 4px;color:#666\">暂无数据</td></tr>'}\n </tbody>\n </table>\n `\n\n const panel = createPanel(html)\n container.appendChild(panel)\n document.body.appendChild(container)\n\n container.addEventListener('click', (e) => {\n if (e.target === container) container.remove()\n })\n const btnClose = panel.querySelector('#__fem_close__') as HTMLButtonElement | null\n if (btnClose) btnClose.onclick = () => container.remove()\n\n const btnClear = panel.querySelector('#__fem_clear__') as HTMLButtonElement | null\n if (btnClear) btnClear.onclick = () => {\n onClear?.()\n container.remove()\n }\n}\n\n/** 简单的 HTML 转义 */\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n}\n\n\n","/** 生成简单唯一 ID(优先使用 crypto.randomUUID) */\nexport function createUid(): string {\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return crypto.randomUUID()\n }\n return 'xxxxxxxxyxxx'.replace(/[xy]/g, c => {\n const r = (Math.random() * 16) | 0\n const v = c === 'x' ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n\n\n","/** 获取窗口视口尺寸 */\nexport function getViewport(): { width: number; height: number } | undefined {\n if (typeof window === 'undefined') return undefined\n return { width: window.innerWidth, height: window.innerHeight }\n}\n\n/** 获取当前页面 URL */\nexport function getPageUrl(): string | undefined {\n if (typeof location === 'undefined') return undefined\n return location.href\n}\n\n\n","import type { BaseEvent, TransportOptions } from './types'\n\nconst DEFAULTS: Required<Pick<TransportOptions, 'batch' | 'batchSize' | 'flushIntervalMs'>> = {\n batch: true,\n batchSize: 20,\n flushIntervalMs: 5000\n}\n\n/**\n * 负责事件的缓存、批量与传输(HTTP/localStorage)\n */\nexport class Transport {\n private readonly endpoint: string\n private readonly headers: Record<string, string>\n private readonly batch: boolean\n private readonly batchSize: number\n private readonly flushIntervalMs: number\n private readonly mode: 'http' | 'local'\n private readonly localKey: string\n private readonly localMaxItems: number | undefined\n private readonly useBeacon: boolean\n private queue: BaseEvent[] = []\n private timer: number | undefined\n\n /**\n * @param options 传输层配置\n */\n constructor(options: TransportOptions) {\n this.endpoint = options.endpoint\n this.headers = options.headers ?? { 'Content-Type': 'application/json' }\n this.batch = options.batch ?? DEFAULTS.batch\n this.batchSize = options.batchSize ?? DEFAULTS.batchSize\n this.flushIntervalMs = options.flushIntervalMs ?? DEFAULTS.flushIntervalMs\n this.mode = options.mode ?? 'http'\n this.localKey = options.localKey ?? '__FEMONITOR_EVENTS__'\n this.localMaxItems = options.localMaxItems\n this.useBeacon = options.useBeacon ?? true\n if (this.batch) this.start()\n this.bindPageLifecycle()\n }\n\n /**\n * 入队一个事件;当非批量模式下立即发送\n */\n enqueue(event: BaseEvent): void {\n if (!this.batch) {\n void this.send([event])\n return\n }\n this.queue.push(event)\n if (this.queue.length >= this.batchSize) {\n void this.flush()\n }\n }\n\n /**\n * 发送并清空当前队列\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return\n const payload = this.queue.splice(0, this.queue.length)\n await this.send(payload)\n }\n\n private start(): void {\n this.stop()\n this.timer = (setInterval(() => {\n void this.flush()\n }, this.flushIntervalMs) as unknown) as number\n }\n\n private stop(): void {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = undefined\n }\n }\n\n /**\n * 实际发送逻辑:优先 local、其后 sendBeacon、最后 fetch\n */\n private async send(events: BaseEvent[]): Promise<void> {\n try {\n if (this.mode === 'local' || !this.endpoint) {\n this.appendToLocal(events)\n return\n }\n if (this.useBeacon && typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {\n const ok = this.sendViaBeacon(events)\n if (ok) return\n // 如果 sendBeacon 返回 false,回退到 fetch\n }\n await fetch(this.endpoint, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({ events })\n })\n } catch {\n // 忽略网络错误,避免影响业务\n }\n }\n\n /**\n * 使用 sendBeacon 发送;返回是否成功排队\n */\n private sendViaBeacon(events: BaseEvent[]): boolean {\n try {\n const payload = JSON.stringify({ events })\n const blob = new Blob([payload], { type: 'application/json' })\n // sendBeacon 不支持自定义 headers;若服务端依赖 headers,请在收端做兼容\n return navigator.sendBeacon(this.endpoint, blob)\n } catch {\n return false\n }\n }\n\n /**\n * 绑定页面生命周期,在隐藏/卸载时使用 sendBeacon flush\n */\n private bindPageLifecycle(): void {\n if (typeof window === 'undefined') return\n const flushWithBeacon = () => {\n if (this.mode !== 'http') return\n if (!this.useBeacon || typeof navigator === 'undefined' || typeof navigator.sendBeacon !== 'function') return\n if (this.queue.length === 0) return\n const payload = this.queue.splice(0, this.queue.length)\n this.sendViaBeacon(payload)\n }\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') flushWithBeacon()\n })\n window.addEventListener('pagehide', flushWithBeacon)\n window.addEventListener('beforeunload', flushWithBeacon)\n }\n\n /**\n * 追加事件到 localStorage(受最大条数限制)\n */\n private appendToLocal(events: BaseEvent[]): void {\n if (typeof localStorage === 'undefined') return\n const current = this.getLocal() \n let merged = current.concat(events)\n if (typeof this.localMaxItems === 'number' && this.localMaxItems > 0 && merged.length > this.localMaxItems) {\n merged = merged.slice(-this.localMaxItems)\n }\n try {\n localStorage.setItem(this.localKey, JSON.stringify(merged))\n } catch {}\n }\n\n /** 获取本地缓存事件 */\n private getLocal(): BaseEvent[] {\n if (typeof localStorage === 'undefined') return []\n const raw = localStorage.getItem(this.localKey)\n if (!raw) return []\n try {\n const arr = JSON.parse(raw)\n return Array.isArray(arr) ? arr : []\n } catch {\n return []\n }\n }\n\n /** 列出本地缓存事件(仅本地模式使用) */\n listStored(): BaseEvent[] {\n return this.getLocal()\n }\n\n /** 清空本地缓存事件 */\n clearStored(): void {\n if (typeof localStorage === 'undefined') return\n try { localStorage.removeItem(this.localKey) } catch {}\n }\n}\n\n\n","import { createUid } from '../utils/uid'\nimport { getPageUrl, getViewport } from '../utils/env'\nimport type { BaseEvent, MonitorClientOptions, TransportOptions } from './types'\nimport { Transport } from './Transport'\nimport { openEventViewer } from '../ui/viewer'\n\n/**\n * 监控客户端:负责构建事件与调用传输层上报\n */\nexport class MonitorClient {\n private readonly options: MonitorClientOptions\n private readonly transport: Transport\n\n /**\n * @param options SDK 初始化参数\n */\n constructor(options: MonitorClientOptions) {\n this.options = options\n const transportOptions: TransportOptions = {\n endpoint: options.dsn,\n ...options.transport\n } as TransportOptions\n this.transport = new Transport(transportOptions)\n }\n\n /**\n * 采集一个事件\n * @param type 事件类型\n * @param data 自定义上下文数据\n */\n capture(type: BaseEvent['type'], data?: Omit<BaseEvent, 'id' | 'type' | 'timestamp' | 'viewport' | 'page'>['context']): void {\n const event: BaseEvent = {\n id: createUid(),\n type,\n timestamp: Date.now(),\n appVersion: this.options.appVersion,\n viewport: getViewport(),\n page: getPageUrl(),\n context: data ?? {}\n }\n this.transport.enqueue(event)\n }\n\n /** 打开本地事件列表查看器 */\n openEventList(): void {\n const events = this.transport.listStored()\n openEventViewer(events, () => this.transport.clearStored())\n }\n\n /** 获取本地缓存事件(仅本地模式有效) */\n getStoredEvents(): BaseEvent[] {\n return this.transport.listStored()\n }\n\n /** 清空本地缓存事件(仅本地模式有效) */\n clearStoredEvents(): void {\n this.transport.clearStored()\n }\n}\n\n\n","export { MonitorClient } from './core/Client'\nexport type { MonitorClientOptions, BaseEvent, TransportOptions } from './core/types'\nexport { openEventViewer } from './ui/viewer'\nimport type { MonitorClientOptions as Options } from './core/types'\nimport { bindViewerHotkey, unbindViewerHotkey } from './utils/hotkey'\nimport { setupErrorIntegration } from './integrations/errors'\nimport { setupPerformanceIntegration } from './integrations/perf'\nimport { setupNetworkIntegration } from './integrations/network'\nimport { setupWhiteScreenIntegration } from './integrations/whitescreen'\nimport { MonitorClient } from './core/Client'\n\n/**\n * 初始化 SDK 并按配置启用集成\n */\nexport function initMonitor(options: Options): MonitorClient {\n const client = new MonitorClient(options)\n setupErrorIntegration(client, options)\n setupPerformanceIntegration(client, options)\n setupNetworkIntegration(client, options)\n setupWhiteScreenIntegration(client, options)\n return client\n}\n\n// 可选的全局自动初始化:当页面上提前定义 window.__FEMONITOR__ 时生效\ndeclare global {\n interface Window {\n __FEMONITOR__?: Options\n __FEMONITOR_INSTANCE__?: MonitorClient\n }\n}\n\nif (typeof window !== 'undefined' && window.__FEMONITOR__ && !window.__FEMONITOR_INSTANCE__) {\n try {\n window.__FEMONITOR_INSTANCE__ = initMonitor(window.__FEMONITOR__)\n } catch {}\n}\n\n\n// 手动绑定/解绑快捷键 API\n/**\n * 绑定默认的查看器快捷键处理(对外导出)\n * @param hotkey 自定义快捷键(如 'Alt+K'),不传则为默认\n */\nexport function bindViewerHotkeyDefault(hotkey?: string): void {\n if (typeof window === 'undefined') return\n bindViewerHotkey(\n () => {\n const inst = window.__FEMONITOR_INSTANCE__ as any\n if (inst && typeof inst.openEventList === 'function') inst.openEventList()\n },\n () => {\n const key = '__FEMONITOR_EVENTS__'\n const raw = typeof localStorage !== 'undefined' ? localStorage.getItem(key) : null\n const events = raw ? JSON.parse(raw) : []\n import('./ui/viewer').then(mod => {\n mod.openEventViewer(Array.isArray(events) ? events : [], () => {\n try { localStorage.removeItem(key) } catch {}\n })\n }).catch(() => {})\n },\n hotkey\n )\n}\n\n/** 解绑默认的查看器快捷键处理 */\nexport function unbindViewerHotkeyDefault(): void {\n unbindViewerHotkey()\n}\n\n","/**\n * 判断键盘事件是否匹配快捷键,如 'Ctrl+Shift+M'\n */\nexport function matchesHotkey(event: KeyboardEvent, hotkey: string): boolean {\n // 支持形如 'Ctrl+Shift+M'、'Alt+K'(大小写不敏感)\n const parts = hotkey.split('+').map(s => s.trim().toLowerCase())\n const needCtrl = parts.includes('ctrl') || parts.includes('control')\n const needShift = parts.includes('shift')\n const needAlt = parts.includes('alt')\n const keyPart = parts.find(p => p !== 'ctrl' && p !== 'control' && p !== 'shift' && p !== 'alt')\n const pressedKey = (event.key || '').toLowerCase()\n return (\n (!!needCtrl === !!event.ctrlKey) &&\n (!!needShift === !!event.shiftKey) &&\n (!!needAlt === !!event.altKey) &&\n (!!keyPart ? pressedKey === keyPart : true)\n )\n}\n\n/** 归一化快捷键(默认 'Ctrl+Shift+M') */\nexport function normalizeHotkey(hotkey?: string): string {\n return hotkey && hotkey.trim() ? hotkey : 'Ctrl+Shift+M'\n}\n\nexport type HotkeyListener = (e: KeyboardEvent) => void\n\ndeclare global {\n interface Window {\n __FEMONITOR_KB_LISTENER__?: HotkeyListener\n __FEMONITOR_HOTKEY__?: string\n }\n}\n\n/**\n * 绑定查看器快捷键\n * @param hotkey 自定义快捷键,不传则沿用上一次或默认\n * @param open 优先使用已有实例打开\n * @param openFallback 无实例时从本地读取并打开\n */\nexport function bindViewerHotkey(open: () => void, openFallback: () => void, hotkey?: string): void {\n if (typeof window === 'undefined') return\n unbindViewerHotkey()\n const finalHotkey = normalizeHotkey(hotkey || window.__FEMONITOR_HOTKEY__)\n window.__FEMONITOR_HOTKEY__ = finalHotkey\n const listener: HotkeyListener = (e) => {\n if (matchesHotkey(e, finalHotkey)) {\n try { open() } catch { openFallback() }\n }\n }\n window.addEventListener('keydown', listener)\n window.__FEMONITOR_KB_LISTENER__ = listener\n}\n\n/** 解绑查看器快捷键 */\nexport function unbindViewerHotkey(): void {\n if (typeof window === 'undefined') return\n const prev = window.__FEMONITOR_KB_LISTENER__\n if (prev) window.removeEventListener('keydown', prev)\n window.__FEMONITOR_KB_LISTENER__ = undefined\n}\n\n\n","import type { MonitorClientOptions } from '../core/types'\nimport { MonitorClient } from '../core/Client'\n\n/**\n * 错误与未捕获 Promise 监听\n */\nexport function setupErrorIntegration(client: MonitorClient, options: MonitorClientOptions): void {\n if (!options.enableErrors) return\n if (typeof window === 'undefined') return\n\n window.addEventListener('error', (event) => {\n const error = event.error || event.message\n client.capture('error', { error })\n }, true)\n\n window.addEventListener('unhandledrejection', (event) => {\n client.capture('unhandledrejection', { reason: (event as PromiseRejectionEvent).reason })\n })\n}\n\n\n","import type { MonitorClientOptions } from '../core/types'\nimport { MonitorClient } from '../core/Client'\n\n/**\n * 性能监控采集:navigation timing、LCP、CLS\n */\nexport function setupPerformanceIntegration(client: MonitorClient, options: MonitorClientOptions): void {\n if (!options.enablePerformance) return\n if (typeof window === 'undefined' || !('performance' in window)) return\n\n // 基础导航时间\n const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined\n if (nav) {\n client.capture('performance', {\n navigation: {\n domContentLoaded: nav.domContentLoadedEventEnd - nav.startTime,\n loadEvent: nav.loadEventEnd - nav.startTime,\n ttfb: nav.responseStart - nav.requestStart\n }\n })\n }\n\n // Web Vitals: LCP/CLS(尽量使用 PerformanceObserver)\n if ('PerformanceObserver' in window) {\n try {\n const po = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.entryType === 'largest-contentful-paint') {\n client.capture('performance', { lcp: entry.startTime })\n }\n if (entry.entryType === 'layout-shift') {\n const ls = entry as unknown as { value?: number; hadRecentInput?: boolean }\n if (ls && !ls.hadRecentInput && typeof ls.value === 'number') {\n client.capture('performance', { cls: ls.value })\n }\n }\n }\n })\n po.observe({ type: 'largest-contentful-paint', buffered: true as unknown as boolean })\n po.observe({ type: 'layout-shift', buffered: true as unknown as boolean })\n } catch {\n // 低版本浏览器忽略\n }\n }\n}\n\n\n","import type { MonitorClientOptions } from '../core/types'\nimport { MonitorClient } from '../core/Client'\n\n/**\n * 网络请求拦截:fetch 与 XHR,采集耗时与状态码\n */\nexport function setupNetworkIntegration(client: MonitorClient, options: MonitorClientOptions): void {\n if (!options.enableNetwork) return\n if (typeof window === 'undefined') return\n\n const maxBodyLength = options.networkMaxBodyLength ?? 1000\n\n // fetch 拦截\n const originalFetch = window.fetch\n window.fetch = async (...args: Parameters<typeof fetch>): Promise<Response> => {\n const start = performance.now()\n let requestBody: string | undefined\n try {\n // 尝试读取请求 body(不影响原始请求)\n if (args[1]?.body) {\n const body = args[1].body\n if (typeof body === 'string') {\n requestBody = truncateBody(body, maxBodyLength)\n } else if (body instanceof FormData || body instanceof URLSearchParams) {\n try {\n requestBody = truncateBody(String(body), maxBodyLength)\n } catch {}\n }\n } else if (!args[1] && typeof args[0] !== 'string' && (args[0] as Request).body) {\n try {\n const cloned = (args[0] as Request).clone()\n const text = await cloned.text()\n requestBody = truncateBody(text, maxBodyLength)\n } catch {}\n }\n const res = await originalFetch(...args)\n const end = performance.now()\n const url = typeof args[0] === 'string' ? args[0] : (args[0] as Request).url\n if (!isAllowedByHost(url, options)) return res\n if (!isUrlAllowedByPattern(url, options)) return res\n let responseBody: string | undefined\n try {\n const cloned = res.clone()\n const text = await cloned.text()\n responseBody = truncateBody(text, maxBodyLength)\n } catch {}\n client.capture('network', {\n fetch: {\n url,\n method: (args[1]?.method ?? (typeof args[0] !== 'string' ? (args[0] as Request).method : 'GET')),\n status: res.status,\n duration: end - start,\n requestBody,\n responseBody\n }\n })\n return res\n } catch (error) {\n const end = performance.now()\n const url = typeof args[0] === 'string' ? args[0] : (args[0] as Request).url\n if (!isAllowedByHost(url, options) || !isUrlAllowedByPattern(url, options)) throw error\n client.capture('network', {\n fetch: {\n url,\n method: (args[1]?.method ?? (typeof args[0] !== 'string' ? (args[0] as Request).method : 'GET')),\n status: -1,\n duration: end - start,\n error: String(error),\n requestBody\n }\n })\n throw error\n }\n }\n\n // XHR 拦截\n const XHR = window.XMLHttpRequest\n const open = XHR.prototype.open\n const send = XHR.prototype.send\n XHR.prototype.open = function(method: string, url: string, ...rest: any[]) {\n ;(this as any).__monitor__ = { method, url }\n return open.apply(this, [method, url, ...rest] as any)\n }\n XHR.prototype.send = function(body?: Document | XMLHttpRequestBodyInit | null) {\n const meta = (this as any).__monitor__ || {}\n let requestBody: string | undefined\n if (body) {\n if (typeof body === 'string') {\n requestBody = truncateBody(body, maxBodyLength)\n } else if (body instanceof FormData || body instanceof URLSearchParams) {\n try {\n requestBody = truncateBody(String(body), maxBodyLength)\n } catch {}\n } else if (body instanceof Blob) {\n // Blob 太大,通常只记录类型\n requestBody = truncateBody(`[Blob:${body.type},${body.size}]`, maxBodyLength)\n } else if (body instanceof Document) {\n requestBody = truncateBody(body.documentElement.outerHTML || '', maxBodyLength)\n }\n }\n const start = performance.now()\n this.addEventListener('loadend', () => {\n const end = performance.now()\n if (!isAllowedByHost(meta.url, options) || !isUrlAllowedByPattern(meta.url, options)) return\n let responseBody: string | undefined\n try {\n if (this.responseType === '' || this.responseType === 'text') {\n responseBody = truncateBody(this.responseText || '', maxBodyLength)\n } else if (this.response) {\n // 其他类型(json/blob等)转换为字符串\n responseBody = truncateBody(String(this.response), maxBodyLength)\n }\n } catch {}\n client.capture('network', {\n xhr: {\n url: meta.url,\n method: meta.method,\n status: this.status,\n duration: end - start,\n requestBody,\n responseBody\n }\n })\n })\n return send.call(this, body as any)\n }\n}\n\nfunction isAllowedByHost(inputUrl: string, options: MonitorClientOptions): boolean {\n const allow = options.networkHostsAllowlist\n const block = options.networkHostsBlocklist\n if (!allow || allow.length === 0) return true\n try {\n const u = new URL(inputUrl, typeof location !== 'undefined' ? location.href : 'http://localhost')\n const host = u.hostname\n if (block && block.some(rule => matchHost(host, rule))) return false\n return allow.some(rule => matchHost(host, rule))\n } catch {\n return false\n }\n}\n\nfunction matchHost(host: string, rule: string): boolean {\n if (!rule) return false\n if (rule.startsWith('*.')) {\n const suffix = rule.slice(1) // '.example.com'\n return host.endsWith(suffix)\n }\n return host === rule\n}\n\nfunction isUrlAllowedByPattern(inputUrl: string, options: MonitorClientOptions): boolean {\n const block = options.networkUrlBlockPatterns\n const allow = options.networkUrlAllowPatterns\n try {\n if (block && block.some(p => testPattern(inputUrl, p))) return false\n if (allow && allow.length > 0) {\n return allow.some(p => testPattern(inputUrl, p))\n }\n return true\n } catch {\n return false\n }\n}\n\nfunction testPattern(url: string, pattern: string | RegExp): boolean {\n if (typeof pattern === 'string') {\n // 将字符串作为正则源;默认不加锚,用户可自行提供 ^/$\n try { return new RegExp(pattern).test(url) } catch { return false }\n }\n return pattern.test(url)\n}\n\n/**\n * 截断 body 字符串,超出长度则截断并添加标记\n * @param body 原始 body 字符串\n * @param maxLength 最大长度,<=0 表示不上报\n * @returns 截断后的字符串,或 undefined(不上报)\n */\nfunction truncateBody(body: string, maxLength: number): string | undefined {\n if (maxLength <= 0 || !body) return undefined\n if (body.length <= maxLength) return body\n const marker = '...[truncated]'\n const truncated = body.slice(0, maxLength - marker.length)\n return truncated + marker\n}\n\n\n","import { MonitorClient } from '../core/Client'\nimport type { MonitorClientOptions } from '../core/types'\n\n/**\n * 白屏检测:在页面就绪后延迟一定时间,统计视口内可见元素数量\n * 若可见元素过少(阈值内),则认为存在白屏并上报。\n */\nexport function setupWhiteScreenIntegration(\n client: MonitorClient,\n options: MonitorClientOptions\n): void {\n if (!options.enableWhiteScreen) return\n if (typeof window === 'undefined' || typeof document === 'undefined') return\n\n const delay = options.whiteScreenOptions?.delayMs ?? 3000\n const minVisibleCount = options.whiteScreenOptions?.minVisibleCount ?? 2\n const minArea = options.whiteScreenOptions?.minArea ?? 50 * 50\n const sampleTimes = Math.max(1, options.whiteScreenOptions?.sampleTimes ?? 1)\n const sampleInterval = options.whiteScreenOptions?.sampleIntervalMs ?? 1000\n\n const run = () => {\n setTimeout(() => {\n try {\n multiSample(minArea, sampleTimes, sampleInterval).then(samples => {\n const worst = Math.min(...samples)\n if (worst <= minVisibleCount) {\n const perf = options.whiteScreenOptions?.includePerf === false ? undefined : getPerfSnapshot()\n client.capture('whitescreen', {\n visibleCount: worst,\n samples,\n readyState: document.readyState,\n url: location.href,\n perf\n })\n }\n }).catch(() => {})\n } catch {\n // ignore\n }\n }, delay)\n }\n\n if (document.readyState === 'complete') {\n run()\n } else {\n window.addEventListener('load', run, { once: true })\n }\n}\n\nfunction countVisibleInViewport(minArea: number): number {\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n let count = 0\n const nodes = document.body ? Array.from(document.body.querySelectorAll('*')) as HTMLElement[] : []\n for (const el of nodes) {\n if (!isElementActuallyVisible(el)) continue\n const rect = el.getBoundingClientRect()\n if (rect.width <= 0 || rect.height <= 0) continue\n if (rect.bottom < 0 || rect.right < 0 || rect.top > viewportHeight || rect.left > viewportWidth) continue\n const area = rect.width * rect.height\n if (area >= minArea) count++\n if (count > 10) break // 足够认为非白屏\n }\n return count\n}\n\nfunction isElementActuallyVisible(el: HTMLElement): boolean {\n const style = getComputedStyle(el)\n if (style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity || '1') === 0) return false\n if (el.tagName === 'SCRIPT' || el.tagName === 'STYLE' || el.tagName === 'LINK' || el.tagName === 'META') return false\n return true\n}\n\nfunction multiSample(minArea: number, times: number, interval: number): Promise<number[]> {\n const results: number[] = []\n return new Promise(resolve => {\n const tick = (left: number) => {\n results.push(countVisibleInViewport(minArea))\n if (left <= 1) return resolve(results)\n setTimeout(() => tick(left - 1), interval)\n }\n tick(times)\n })\n}\n\nfunction getPerfSnapshot(): Record<string, unknown> | undefined {\n if (typeof performance === 'undefined') return undefined\n const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined\n const paints = performance.getEntriesByType('paint') as PerformanceEntry[]\n const fcp = paints.find(p => p.name === 'first-contentful-paint')?.startTime\n const lcpEntries = (performance.getEntriesByType('largest-contentful-paint') as PerformanceEntry[]) || []\n const lcp = lcpEntries.length ? Math.max(...lcpEntries.map(e => e.startTime)) : undefined\n return {\n navigation: nav ? {\n ttfb: nav.responseStart - nav.requestStart,\n domContentLoaded: nav.domContentLoadedEventEnd - nav.startTime,\n loadEvent: nav.loadEventEnd - nav.startTime\n } : undefined,\n fcp,\n lcp\n }\n}\n\n\n"]}
1
+ {"version":3,"sources":["../src/ui/viewer.ts","../src/utils/uid.ts","../src/utils/env.ts","../src/core/Transport.ts","../src/core/Client.ts","../src/index.ts","../src/utils/hotkey.ts","../src/integrations/errors.ts","../src/integrations/perf.ts","../src/integrations/network.ts","../src/integrations/whitescreen.ts"],"names":["viewer_exports","__export","openEventViewer","createContainer","el","createPanel","html","panel","events","onClear","existing","container","rows","e","escapeHtml","btnClose","btnClear","str","init_viewer","__esmMin","createUid","c","r","getViewport","getPageUrl","DEFAULTS","Transport","options","event","payload","blob","flushWithBeacon","merged","raw","arr","MonitorClient","transportOptions","type","data","matchesHotkey","hotkey","parts","s","needCtrl","needShift","needAlt","keyPart","p","pressedKey","normalizeHotkey","bindViewerHotkey","open","openFallback","unbindViewerHotkey","finalHotkey","listener","prev","setupErrorIntegration","client","error","setupPerformanceIntegration","nav","po","list","entry","ls","setupNetworkIntegration","maxBodyLength","originalFetch","args","start","requestBody","body","truncateBody","text","res","end","url","isAllowedByHost","isUrlAllowedByPattern","responseBody","XHR","send","method","rest","meta","inputUrl","allow","block","host","rule","matchHost","suffix","testPattern","pattern","maxLength","marker","setupWhiteScreenIntegration","delay","minVisibleCount","minArea","sampleTimes","sampleInterval","run","multiSample","samples","worst","perf","getPerfSnapshot","countVisibleInViewport","viewportWidth","viewportHeight","count","nodes","isElementActuallyVisible","rect","style","times","interval","results","resolve","tick","left","fcp","lcpEntries","lcp","initMonitor","bindViewerHotkeyDefault","inst","key","mod","unbindViewerHotkeyDefault"],"mappings":"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","file":"index.global.js","sourcesContent":["import type { BaseEvent } from '../core/types'\n\n/** 创建遮罩容器 */\nfunction createContainer(): HTMLElement {\n const el = document.createElement('div')\n el.id = '__femonitor_viewer__'\n el.style.position = 'fixed'\n el.style.top = '0'\n el.style.left = '0'\n el.style.right = '0'\n el.style.bottom = '0'\n el.style.background = 'rgba(0,0,0,0.5)'\n el.style.zIndex = '99999'\n el.style.display = 'flex'\n el.style.alignItems = 'center'\n el.style.justifyContent = 'center'\n return el\n}\n\n/** 创建面板节点并填充 HTML */\nfunction createPanel(html: string): HTMLElement {\n const panel = document.createElement('div')\n panel.style.width = '80%'\n panel.style.maxWidth = '960px'\n panel.style.maxHeight = '80%'\n panel.style.overflow = 'auto'\n panel.style.background = '#fff'\n panel.style.borderRadius = '8px'\n panel.style.boxShadow = '0 10px 30px rgba(0,0,0,0.2)'\n panel.style.padding = '16px'\n panel.innerHTML = html\n return panel\n}\n\n/**\n * 打开事件查看器覆盖层\n * @param events 要展示的事件数组\n * @param onClear 点击清空后的回调\n */\nexport function openEventViewer(events: BaseEvent[], onClear?: () => void): void {\n if (typeof document === 'undefined') return\n const existing = document.getElementById('__femonitor_viewer__')\n if (existing) existing.remove()\n\n const container = createContainer()\n const rows = events\n .slice()\n .reverse()\n .map(e => `<tr>\n <td style=\"white-space:nowrap\">${new Date(e.timestamp).toLocaleString()}</td>\n <td>${e.type}</td>\n <td><pre style=\"margin:0;white-space:pre-wrap\">${escapeHtml(JSON.stringify(e.context ?? {}, null, 2))}</pre></td>\n </tr>`)\n .join('')\n\n const html = `\n <div style=\"display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:12px\">\n <h3 style=\"margin:0\">FE Monitor 本地事件 (${events.length})</h3>\n <div style=\"display:flex;gap:8px\">\n <button id=\"__fem_close__\">关闭</button>\n <button id=\"__fem_clear__\">清空</button>\n </div>\n </div>\n <table style=\"width:100%;border-collapse:collapse\">\n <thead>\n <tr>\n <th style=\"text-align:left;border-bottom:1px solid #eee;padding:8px 4px\">时间</th>\n <th style=\"text-align:left;border-bottom:1px solid #eee;padding:8px 4px\">类型</th>\n <th style=\"text-align:left;border-bottom:1px solid #eee;padding:8px 4px\">内容</th>\n </tr>\n </thead>\n <tbody>\n ${rows || '<tr><td colspan=\"3\" style=\"padding:12px 4px;color:#666\">暂无数据</td></tr>'}\n </tbody>\n </table>\n `\n\n const panel = createPanel(html)\n container.appendChild(panel)\n document.body.appendChild(container)\n\n container.addEventListener('click', (e) => {\n if (e.target === container) container.remove()\n })\n const btnClose = panel.querySelector('#__fem_close__') as HTMLButtonElement | null\n if (btnClose) btnClose.onclick = () => container.remove()\n\n const btnClear = panel.querySelector('#__fem_clear__') as HTMLButtonElement | null\n if (btnClear) btnClear.onclick = () => {\n onClear?.()\n container.remove()\n }\n}\n\n/** 简单的 HTML 转义 */\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n}\n\n\n","/** 生成简单唯一 ID(优先使用 crypto.randomUUID) */\nexport function createUid(): string {\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return crypto.randomUUID()\n }\n return 'xxxxxxxxyxxx'.replace(/[xy]/g, c => {\n const r = (Math.random() * 16) | 0\n const v = c === 'x' ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n\n\n","/** 获取窗口视口尺寸 */\nexport function getViewport(): { width: number; height: number } | undefined {\n if (typeof window === 'undefined') return undefined\n return { width: window.innerWidth, height: window.innerHeight }\n}\n\n/** 获取当前页面 URL */\nexport function getPageUrl(): string | undefined {\n if (typeof location === 'undefined') return undefined\n return location.href\n}\n\n\n","import type { BaseEvent, TransportOptions } from './types'\n\nconst DEFAULTS: Required<Pick<TransportOptions, 'batch' | 'batchSize' | 'flushIntervalMs'>> = {\n batch: true,\n batchSize: 20,\n flushIntervalMs: 5000\n}\n\n/**\n * 负责事件的缓存、批量与传输(HTTP/localStorage)\n */\nexport class Transport {\n private readonly endpoint: string\n private readonly headers: Record<string, string>\n private readonly batch: boolean\n private readonly batchSize: number\n private readonly flushIntervalMs: number\n private readonly mode: 'http' | 'local'\n private readonly localKey: string\n private readonly localMaxItems: number | undefined\n private readonly useBeacon: boolean\n private queue: BaseEvent[] = []\n private timer: number | undefined\n\n /**\n * @param options 传输层配置\n */\n constructor(options: TransportOptions) {\n this.endpoint = options.endpoint\n this.headers = options.headers ?? { 'Content-Type': 'application/json' }\n this.batch = options.batch ?? DEFAULTS.batch\n this.batchSize = options.batchSize ?? DEFAULTS.batchSize\n this.flushIntervalMs = options.flushIntervalMs ?? DEFAULTS.flushIntervalMs\n this.mode = options.mode ?? 'http'\n this.localKey = options.localKey ?? '__FEMONITOR_EVENTS__'\n this.localMaxItems = options.localMaxItems\n this.useBeacon = options.useBeacon ?? true\n if (this.batch) this.start()\n this.bindPageLifecycle()\n }\n\n /**\n * 入队一个事件;当非批量模式下立即发送\n */\n enqueue(event: BaseEvent): void {\n if (!this.batch) {\n void this.send([event])\n return\n }\n this.queue.push(event)\n if (this.queue.length >= this.batchSize) {\n void this.flush()\n }\n }\n\n /**\n * 发送并清空当前队列\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0) return\n const payload = this.queue.splice(0, this.queue.length)\n await this.send(payload)\n }\n\n private start(): void {\n this.stop()\n this.timer = (setInterval(() => {\n void this.flush()\n }, this.flushIntervalMs) as unknown) as number\n }\n\n private stop(): void {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = undefined\n }\n }\n\n /**\n * 实际发送逻辑:优先 local、其后 sendBeacon、最后 fetch\n */\n private async send(events: BaseEvent[]): Promise<void> {\n try {\n if (this.mode === 'local' || !this.endpoint) {\n this.appendToLocal(events)\n return\n }\n if (this.useBeacon && typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {\n const ok = this.sendViaBeacon(events)\n if (ok) return\n // 如果 sendBeacon 返回 false,回退到 fetch\n }\n await fetch(this.endpoint, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({ events })\n })\n } catch {\n // 忽略网络错误,避免影响业务\n }\n }\n\n /**\n * 使用 sendBeacon 发送;返回是否成功排队\n */\n private sendViaBeacon(events: BaseEvent[]): boolean {\n try {\n const payload = JSON.stringify({ events })\n const blob = new Blob([payload], { type: 'application/json' })\n // sendBeacon 不支持自定义 headers;若服务端依赖 headers,请在收端做兼容\n return navigator.sendBeacon(this.endpoint, blob)\n } catch {\n return false\n }\n }\n\n /**\n * 绑定页面生命周期,在隐藏/卸载时使用 sendBeacon flush\n */\n private bindPageLifecycle(): void {\n if (typeof window === 'undefined') return\n const flushWithBeacon = () => {\n if (this.mode !== 'http') return\n if (!this.useBeacon || typeof navigator === 'undefined' || typeof navigator.sendBeacon !== 'function') return\n if (this.queue.length === 0) return\n const payload = this.queue.splice(0, this.queue.length)\n this.sendViaBeacon(payload)\n }\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') flushWithBeacon()\n })\n window.addEventListener('pagehide', flushWithBeacon)\n window.addEventListener('beforeunload', flushWithBeacon)\n }\n\n /**\n * 追加事件到 localStorage(受最大条数限制)\n */\n private appendToLocal(events: BaseEvent[]): void {\n if (typeof localStorage === 'undefined') return\n const current = this.getLocal() \n let merged = current.concat(events)\n if (typeof this.localMaxItems === 'number' && this.localMaxItems > 0 && merged.length > this.localMaxItems) {\n merged = merged.slice(-this.localMaxItems)\n }\n try {\n localStorage.setItem(this.localKey, JSON.stringify(merged))\n } catch {}\n }\n\n /** 获取本地缓存事件 */\n private getLocal(): BaseEvent[] {\n if (typeof localStorage === 'undefined') return []\n const raw = localStorage.getItem(this.localKey)\n if (!raw) return []\n try {\n const arr = JSON.parse(raw)\n return Array.isArray(arr) ? arr : []\n } catch {\n return []\n }\n }\n\n /** 列出本地缓存事件(仅本地模式使用) */\n listStored(): BaseEvent[] {\n return this.getLocal()\n }\n\n /** 清空本地缓存事件 */\n clearStored(): void {\n if (typeof localStorage === 'undefined') return\n try { localStorage.removeItem(this.localKey) } catch {}\n }\n}\n\n\n","import { createUid } from '../utils/uid'\nimport { getPageUrl, getViewport } from '../utils/env'\nimport type { BaseEvent, MonitorClientOptions, TransportOptions } from './types'\nimport { Transport } from './Transport'\nimport { openEventViewer } from '../ui/viewer'\n\n/**\n * 监控客户端:负责构建事件与调用传输层上报\n */\nexport class MonitorClient {\n private readonly options: MonitorClientOptions\n private readonly transport: Transport\n\n /**\n * @param options SDK 初始化参数\n */\n constructor(options: MonitorClientOptions) {\n this.options = options\n const transportOptions: TransportOptions = {\n endpoint: options.dsn,\n ...options.transport\n } as TransportOptions\n this.transport = new Transport(transportOptions)\n }\n\n /**\n * 采集一个事件\n * @param type 事件类型\n * @param data 自定义上下文数据\n */\n capture(type: BaseEvent['type'], data?: Omit<BaseEvent, 'id' | 'type' | 'timestamp' | 'viewport' | 'page'>['context']): void {\n const event: BaseEvent = {\n id: createUid(),\n type,\n timestamp: Date.now(),\n appVersion: this.options.appVersion,\n viewport: getViewport(),\n page: getPageUrl(),\n context: data ?? {}\n }\n this.transport.enqueue(event)\n }\n\n /** 打开本地事件列表查看器 */\n openEventList(): void {\n const events = this.transport.listStored()\n openEventViewer(events, () => this.transport.clearStored())\n }\n\n /** 获取本地缓存事件(仅本地模式有效) */\n getStoredEvents(): BaseEvent[] {\n return this.transport.listStored()\n }\n\n /** 清空本地缓存事件(仅本地模式有效) */\n clearStoredEvents(): void {\n this.transport.clearStored()\n }\n}\n\n\n","export { MonitorClient } from './core/Client'\nexport type { MonitorClientOptions, BaseEvent, TransportOptions } from './core/types'\nexport { openEventViewer } from './ui/viewer'\nimport type { MonitorClientOptions as Options } from './core/types'\nimport { bindViewerHotkey, unbindViewerHotkey } from './utils/hotkey'\nimport { setupErrorIntegration } from './integrations/errors'\nimport { setupPerformanceIntegration } from './integrations/perf'\nimport { setupNetworkIntegration } from './integrations/network'\nimport { setupWhiteScreenIntegration } from './integrations/whitescreen'\nimport { MonitorClient } from './core/Client'\n\n/**\n * 初始化 SDK 并按配置启用集成\n */\nexport function initMonitor(options: Options): MonitorClient {\n const client = new MonitorClient(options)\n setupErrorIntegration(client, options)\n setupPerformanceIntegration(client, options)\n setupNetworkIntegration(client, options)\n setupWhiteScreenIntegration(client, options)\n return client\n}\n\n// 可选的全局自动初始化:当页面上提前定义 window.__FEMONITOR__ 时生效\ndeclare global {\n interface Window {\n __FEMONITOR__?: Options\n __FEMONITOR_INSTANCE__?: MonitorClient\n }\n}\n\nif (typeof window !== 'undefined' && window.__FEMONITOR__ && !window.__FEMONITOR_INSTANCE__) {\n try {\n window.__FEMONITOR_INSTANCE__ = initMonitor(window.__FEMONITOR__)\n } catch {}\n}\n\n\n// 手动绑定/解绑快捷键 API\n/**\n * 绑定默认的查看器快捷键处理(对外导出)\n * @param hotkey 自定义快捷键(如 'Alt+K'),不传则为默认\n */\nexport function bindViewerHotkeyDefault(hotkey?: string): void {\n if (typeof window === 'undefined') return\n bindViewerHotkey(\n () => {\n const inst = window.__FEMONITOR_INSTANCE__ as any\n if (inst && typeof inst.openEventList === 'function') inst.openEventList()\n },\n () => {\n const key = '__FEMONITOR_EVENTS__'\n const raw = typeof localStorage !== 'undefined' ? localStorage.getItem(key) : null\n const events = raw ? JSON.parse(raw) : []\n import('./ui/viewer').then(mod => {\n mod.openEventViewer(Array.isArray(events) ? events : [], () => {\n try { localStorage.removeItem(key) } catch {}\n })\n }).catch(() => {})\n },\n hotkey\n )\n}\n\n/** 解绑默认的查看器快捷键处理 */\nexport function unbindViewerHotkeyDefault(): void {\n unbindViewerHotkey()\n}\n\n","/**\n * 判断键盘事件是否匹配快捷键,如 'Ctrl+Shift+M'\n */\nexport function matchesHotkey(event: KeyboardEvent, hotkey: string): boolean {\n // 支持形如 'Ctrl+Shift+M'、'Alt+K'(大小写不敏感)\n const parts = hotkey.split('+').map(s => s.trim().toLowerCase())\n const needCtrl = parts.includes('ctrl') || parts.includes('control')\n const needShift = parts.includes('shift')\n const needAlt = parts.includes('alt')\n const keyPart = parts.find(p => p !== 'ctrl' && p !== 'control' && p !== 'shift' && p !== 'alt')\n const pressedKey = (event.key || '').toLowerCase()\n return (\n (!!needCtrl === !!event.ctrlKey) &&\n (!!needShift === !!event.shiftKey) &&\n (!!needAlt === !!event.altKey) &&\n (!!keyPart ? pressedKey === keyPart : true)\n )\n}\n\n/** 归一化快捷键(默认 'Ctrl+Shift+M') */\nexport function normalizeHotkey(hotkey?: string): string {\n return hotkey && hotkey.trim() ? hotkey : 'Ctrl+Shift+M'\n}\n\nexport type HotkeyListener = (e: KeyboardEvent) => void\n\ndeclare global {\n interface Window {\n __FEMONITOR_KB_LISTENER__?: HotkeyListener\n __FEMONITOR_HOTKEY__?: string\n }\n}\n\n/**\n * 绑定查看器快捷键\n * @param hotkey 自定义快捷键,不传则沿用上一次或默认\n * @param open 优先使用已有实例打开\n * @param openFallback 无实例时从本地读取并打开\n */\nexport function bindViewerHotkey(open: () => void, openFallback: () => void, hotkey?: string): void {\n if (typeof window === 'undefined') return\n unbindViewerHotkey()\n const finalHotkey = normalizeHotkey(hotkey || window.__FEMONITOR_HOTKEY__)\n window.__FEMONITOR_HOTKEY__ = finalHotkey\n const listener: HotkeyListener = (e) => {\n if (matchesHotkey(e, finalHotkey)) {\n try { open() } catch { openFallback() }\n }\n }\n window.addEventListener('keydown', listener)\n window.__FEMONITOR_KB_LISTENER__ = listener\n}\n\n/** 解绑查看器快捷键 */\nexport function unbindViewerHotkey(): void {\n if (typeof window === 'undefined') return\n const prev = window.__FEMONITOR_KB_LISTENER__\n if (prev) window.removeEventListener('keydown', prev)\n window.__FEMONITOR_KB_LISTENER__ = undefined\n}\n\n\n","import type { MonitorClientOptions } from '../core/types'\nimport { MonitorClient } from '../core/Client'\n\n/**\n * 错误与未捕获 Promise 监听\n */\nexport function setupErrorIntegration(client: MonitorClient, options: MonitorClientOptions): void {\n if (!options.enableErrors) return\n if (typeof window === 'undefined') return\n\n window.addEventListener('error', (event) => {\n const error = event.error || event.message\n client.capture('error', { error })\n }, true)\n\n window.addEventListener('unhandledrejection', (event) => {\n client.capture('unhandledrejection', { reason: (event as PromiseRejectionEvent).reason })\n })\n}\n\n\n","import type { MonitorClientOptions } from '../core/types'\nimport { MonitorClient } from '../core/Client'\n\n/**\n * 性能监控采集:navigation timing、LCP、CLS\n */\nexport function setupPerformanceIntegration(client: MonitorClient, options: MonitorClientOptions): void {\n if (!options.enablePerformance) return\n if (typeof window === 'undefined' || !('performance' in window)) return\n\n // 基础导航时间\n const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined\n if (nav) {\n client.capture('performance', {\n navigation: {\n domContentLoaded: nav.domContentLoadedEventEnd - nav.startTime,\n loadEvent: nav.loadEventEnd - nav.startTime,\n ttfb: nav.responseStart - nav.requestStart\n }\n })\n }\n\n // Web Vitals: LCP/CLS(尽量使用 PerformanceObserver)\n if ('PerformanceObserver' in window) {\n try {\n const po = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.entryType === 'largest-contentful-paint') {\n client.capture('performance', { lcp: entry.startTime })\n }\n if (entry.entryType === 'layout-shift') {\n const ls = entry as unknown as { value?: number; hadRecentInput?: boolean }\n if (ls && !ls.hadRecentInput && typeof ls.value === 'number') {\n client.capture('performance', { cls: ls.value })\n }\n }\n }\n })\n po.observe({ type: 'largest-contentful-paint', buffered: true as unknown as boolean })\n po.observe({ type: 'layout-shift', buffered: true as unknown as boolean })\n } catch {\n // 低版本浏览器忽略\n }\n }\n}\n\n\n","import type { MonitorClientOptions } from '../core/types'\nimport { MonitorClient } from '../core/Client'\n\n/**\n * 网络请求拦截:fetch 与 XHR,采集耗时与状态码\n */\nexport function setupNetworkIntegration(client: MonitorClient, options: MonitorClientOptions): void {\n if (!options.enableNetwork) return\n if (typeof window === 'undefined') return\n\n const maxBodyLength = options.networkMaxBodyLength ?? 1000\n\n // fetch 拦截\n const originalFetch = window.fetch\n window.fetch = async (...args: Parameters<typeof fetch>): Promise<Response> => {\n const start = performance.now()\n let requestBody: string | undefined\n try {\n // 尝试读取请求 body(不影响原始请求)\n if (args[1]?.body) {\n const body = args[1].body\n if (typeof body === 'string') {\n requestBody = truncateBody(body, maxBodyLength)\n } else if (body instanceof FormData || body instanceof URLSearchParams) {\n try {\n requestBody = truncateBody(String(body), maxBodyLength)\n } catch {}\n }\n } else if (!args[1] && typeof args[0] !== 'string' && (args[0] as Request).body) {\n try {\n const cloned = (args[0] as Request).clone()\n const text = await cloned.text()\n requestBody = truncateBody(text, maxBodyLength)\n } catch {}\n }\n const res = await originalFetch(...args)\n const end = performance.now()\n const url = typeof args[0] === 'string' ? args[0] : (args[0] as Request).url\n if (!isAllowedByHost(url, options)) return res\n if (!isUrlAllowedByPattern(url, options)) return res\n let responseBody: string | undefined\n try {\n const cloned = res.clone()\n const text = await cloned.text()\n responseBody = truncateBody(text, maxBodyLength)\n } catch {}\n client.capture('network', {\n fetch: {\n url,\n method: (args[1]?.method ?? (typeof args[0] !== 'string' ? (args[0] as Request).method : 'GET')),\n status: res.status,\n duration: end - start,\n requestBody,\n responseBody\n }\n })\n return res\n } catch (error) {\n const end = performance.now()\n const url = typeof args[0] === 'string' ? args[0] : (args[0] as Request).url\n if (!isAllowedByHost(url, options) || !isUrlAllowedByPattern(url, options)) throw error\n client.capture('network', {\n fetch: {\n url,\n method: (args[1]?.method ?? (typeof args[0] !== 'string' ? (args[0] as Request).method : 'GET')),\n status: -1,\n duration: end - start,\n error: String(error),\n requestBody\n }\n })\n throw error\n }\n }\n\n // XHR 拦截\n const XHR = window.XMLHttpRequest\n const open = XHR.prototype.open\n const send = XHR.prototype.send\n XHR.prototype.open = function(method: string, url: string, ...rest: any[]) {\n ;(this as any).__monitor__ = { method, url }\n return open.apply(this, [method, url, ...rest] as any)\n }\n XHR.prototype.send = function(body?: Document | XMLHttpRequestBodyInit | null) {\n const meta = (this as any).__monitor__ || {}\n let requestBody: string | undefined\n if (body) {\n if (typeof body === 'string') {\n requestBody = truncateBody(body, maxBodyLength)\n } else if (body instanceof FormData || body instanceof URLSearchParams) {\n try {\n requestBody = truncateBody(String(body), maxBodyLength)\n } catch {}\n } else if (body instanceof Blob) {\n // Blob 太大,通常只记录类型\n requestBody = truncateBody(`[Blob:${body.type},${body.size}]`, maxBodyLength)\n } else if (body instanceof Document) {\n requestBody = truncateBody(body.documentElement.outerHTML || '', maxBodyLength)\n }\n }\n const start = performance.now()\n this.addEventListener('loadend', () => {\n const end = performance.now()\n if (!isAllowedByHost(meta.url, options) || !isUrlAllowedByPattern(meta.url, options)) return\n let responseBody: string | undefined\n try {\n if (this.responseType === '' || this.responseType === 'text') {\n responseBody = truncateBody(this.responseText || '', maxBodyLength)\n } else if (this.response) {\n // 其他类型(json/blob等)转换为字符串\n responseBody = truncateBody(String(this.response), maxBodyLength)\n }\n } catch {}\n client.capture('network', {\n xhr: {\n url: meta.url,\n method: meta.method,\n status: this.status,\n duration: end - start,\n requestBody,\n responseBody\n }\n })\n })\n return send.call(this, body as any)\n }\n}\n\nfunction isAllowedByHost(inputUrl: string, options: MonitorClientOptions): boolean {\n const allow = options.networkHostsAllowlist\n const block = options.networkHostsBlocklist\n if (!allow || allow.length === 0) return true\n try {\n const u = new URL(inputUrl, typeof location !== 'undefined' ? location.href : 'http://localhost')\n const host = u.hostname\n if (block && block.some(rule => matchHost(host, rule))) return false\n return allow.some(rule => matchHost(host, rule))\n } catch {\n return false\n }\n}\n\nfunction matchHost(host: string, rule: string): boolean {\n if (!rule) return false\n if (rule.startsWith('*.')) {\n const suffix = rule.slice(1) // '.example.com'\n return host.endsWith(suffix)\n }\n return host === rule\n}\n\nfunction isUrlAllowedByPattern(inputUrl: string, options: MonitorClientOptions): boolean {\n const block = options.networkUrlBlockPatterns\n const allow = options.networkUrlAllowPatterns\n try {\n if (block && block.some(p => testPattern(inputUrl, p))) return false\n if (allow && allow.length > 0) {\n return allow.some(p => testPattern(inputUrl, p))\n }\n return true\n } catch {\n return false\n }\n}\n\nfunction testPattern(url: string, pattern: string | RegExp): boolean {\n if (typeof pattern === 'string') {\n // 将字符串作为正则源;默认不加锚,用户可自行提供 ^/$\n try { return new RegExp(pattern).test(url) } catch { return false }\n }\n return pattern.test(url)\n}\n\n/**\n * 截断 body 字符串,超出长度则截断并添加标记\n * @param body 原始 body 字符串\n * @param maxLength 最大长度,<=0 表示不上报\n * @returns 截断后的字符串,或 undefined(不上报)\n */\nfunction truncateBody(body: string, maxLength: number): string | undefined {\n if (maxLength <= 0 || !body) return undefined\n if (body.length <= maxLength) return body\n const marker = '...[truncated]'\n const truncated = body.slice(0, maxLength - marker.length)\n return truncated + marker\n}\n\n\n","import { MonitorClient } from '../core/Client'\nimport type { MonitorClientOptions } from '../core/types'\n\n/**\n * 白屏检测:在页面就绪后延迟一定时间,统计视口内可见元素数量\n * 若可见元素过少(阈值内),则认为存在白屏并上报。\n */\nexport function setupWhiteScreenIntegration(\n client: MonitorClient,\n options: MonitorClientOptions\n): void {\n if (!options.enableWhiteScreen) return\n if (typeof window === 'undefined' || typeof document === 'undefined') return\n\n const delay = options.whiteScreenOptions?.delayMs ?? 3000\n const minVisibleCount = options.whiteScreenOptions?.minVisibleCount ?? 2\n const minArea = options.whiteScreenOptions?.minArea ?? 50 * 50\n const sampleTimes = Math.max(1, options.whiteScreenOptions?.sampleTimes ?? 1)\n const sampleInterval = options.whiteScreenOptions?.sampleIntervalMs ?? 1000\n\n const run = () => {\n setTimeout(() => {\n try {\n multiSample(minArea, sampleTimes, sampleInterval).then(samples => {\n const worst = Math.min(...samples)\n if (worst <= minVisibleCount) {\n const perf = options.whiteScreenOptions?.includePerf === false ? undefined : getPerfSnapshot()\n client.capture('whitescreen', {\n visibleCount: worst,\n samples,\n readyState: document.readyState,\n url: location.href,\n perf\n })\n }\n }).catch(() => {})\n } catch {\n // ignore\n }\n }, delay)\n }\n\n if (document.readyState === 'complete') {\n run()\n } else {\n window.addEventListener('load', run, { once: true })\n }\n}\n\nfunction countVisibleInViewport(minArea: number): number {\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n let count = 0\n const nodes = document.body ? Array.from(document.body.querySelectorAll('*')) as HTMLElement[] : []\n for (const el of nodes) {\n if (!isElementActuallyVisible(el)) continue\n const rect = el.getBoundingClientRect()\n if (rect.width <= 0 || rect.height <= 0) continue\n if (rect.bottom < 0 || rect.right < 0 || rect.top > viewportHeight || rect.left > viewportWidth) continue\n const area = rect.width * rect.height\n if (area >= minArea) count++\n if (count > 10) break // 足够认为非白屏\n }\n return count\n}\n\nfunction isElementActuallyVisible(el: HTMLElement): boolean {\n const style = getComputedStyle(el)\n if (style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity || '1') === 0) return false\n if (el.tagName === 'SCRIPT' || el.tagName === 'STYLE' || el.tagName === 'LINK' || el.tagName === 'META') return false\n return true\n}\n\nfunction multiSample(minArea: number, times: number, interval: number): Promise<number[]> {\n const results: number[] = []\n return new Promise(resolve => {\n const tick = (left: number) => {\n results.push(countVisibleInViewport(minArea))\n if (left <= 1) return resolve(results)\n setTimeout(() => tick(left - 1), interval)\n }\n tick(times)\n })\n}\n\nfunction getPerfSnapshot(): Record<string, unknown> | undefined {\n if (typeof performance === 'undefined') return undefined\n const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined\n const paints = performance.getEntriesByType('paint') as PerformanceEntry[]\n const fcp = paints.find(p => p.name === 'first-contentful-paint')?.startTime\n const lcpEntries = (performance.getEntriesByType('largest-contentful-paint') as PerformanceEntry[]) || []\n const lcp = lcpEntries.length ? Math.max(...lcpEntries.map(e => e.startTime)) : undefined\n return {\n navigation: nav ? {\n ttfb: nav.responseStart - nav.requestStart,\n domContentLoaded: nav.domContentLoadedEventEnd - nav.startTime,\n loadEvent: nav.loadEventEnd - nav.startTime\n } : undefined,\n fcp,\n lcp\n }\n}\n\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@w57124/exs-monitor-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "前端监控 SDK:错误上报、性能指标、网络拦截",
5
5
  "keywords": [
6
6
  "monitoring",