{"_id":"@chenweikang/frontend-radar-sdk-core","_rev":"3-21aaa25d52e612a303f978c99a29459c","name":"@chenweikang/frontend-radar-sdk-core","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@chenweikang/frontend-radar-sdk-core","version":"0.1.0","keywords":["frontend-radar","observability","monitoring","error-tracking","typescript"],"license":"MIT","_id":"@chenweikang/frontend-radar-sdk-core@0.1.0","maintainers":[{"name":"chenweikang","email":"13400405244@163.com"}],"dist":{"shasum":"737b1883d22c9ccf2e873ef5548eb4e6a6d2c170","tarball":"https://registry.npmjs.org/@chenweikang/frontend-radar-sdk-core/-/frontend-radar-sdk-core-0.1.0.tgz","fileCount":79,"integrity":"sha512-LF1X1sYspoeYAeoZUxirI9XYjDvhGWfSwqNjig/80go4f52gFN4lNTs0MsXESX8ue4KIsncOrVslEInWA7LLew==","signatures":[{"sig":"MEUCICoU4NRgQVb0WoDOzFJtLB2CWPLibNnDQ7AQZmVXBsD0AiEAhn7pivMa1CLFNwZYuyqiAk2ot8pc3eYmewck49NYrpE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":152809},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint src tests","test":"tsx --test tests/sdk-core.test.ts tests/js-error-plugin.test.ts tests/breadcrumb.test.ts tests/network-monitor.test.ts tests/remote-config.test.ts","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit -p tsconfig.test.json"},"_npmUser":{"name":"chenweikang","email":"13400405244@163.com"},"description":"Frontend Radar 的框架无关前端可观测性 SDK。","directories":{},"sideEffects":false,"_nodeVersion":"24.18.1","dependencies":{"@chenweikang/frontend-radar-shared-types":"^0.1.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/frontend-radar-sdk-core_0.1.0_1787639242912_0.6262005421885175","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@chenweikang/frontend-radar-sdk-core","version":"0.2.0","keywords":["frontend-radar","observability","monitoring","error-tracking","typescript"],"license":"MIT","_id":"@chenweikang/frontend-radar-sdk-core@0.2.0","maintainers":[{"name":"chenweikang","email":"13400405244@163.com"}],"dist":{"shasum":"f6f81fcaeb02f37edd4e26533661295ad03dc160","tarball":"https://registry.npmjs.org/@chenweikang/frontend-radar-sdk-core/-/frontend-radar-sdk-core-0.2.0.tgz","fileCount":87,"integrity":"sha512-xpAb9yqzG3YqUSIubHNfAKvJsCZ+8JbDqtERZCB/2s5P79JL3pzpEY1VjBJxBx45MMKbrjNaOSON21wh9pZejA==","signatures":[{"sig":"MEYCIQDFnPlI4lj7zwvAmAIl2Puk+EpXbCoaxCOueYOIdMP5rgIhAMwH9xhBxty2kxgMZGUQ30WEZuDkRREAADowOmAzJJEH","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":203186},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"lint":"eslint src tests","test":"tsx --test tests/sdk-core.test.ts tests/js-error-plugin.test.ts tests/breadcrumb.test.ts tests/network-monitor.test.ts tests/remote-config.test.ts tests/dedupe.test.ts tests/white-screen-plugin.test.ts tests/web-vitals-plugin.test.ts","build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit -p tsconfig.test.json"},"_npmUser":{"name":"chenweikang","email":"13400405244@163.com"},"description":"Frontend Radar 的框架无关前端可观测性 SDK。","directories":{},"sideEffects":false,"_nodeVersion":"24.18.1","dependencies":{"@chenweikang/frontend-radar-shared-types":"^0.2.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/frontend-radar-sdk-core_0.2.0_1787651212964_0.23653608974701057","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@chenweikang/frontend-radar-sdk-core","version":"0.3.0","description":"Frontend Radar 的框架无关前端可观测性 SDK。","license":"MIT","keywords":["frontend-radar","observability","monitoring","error-tracking","typescript"],"type":"module","sideEffects":false,"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./package.json":"./package.json"},"dependencies":{"@chenweikang/frontend-radar-shared-types":"^0.3.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"scripts":{"build":"pnpm sync-version && tsc -p tsconfig.build.json","lint":"eslint src tests","sync-version":"node scripts/sync-version.mjs","test":"tsx --test tests/sdk-core.test.ts tests/js-error-plugin.test.ts tests/breadcrumb.test.ts tests/network-monitor.test.ts tests/remote-config.test.ts tests/dedupe.test.ts tests/white-screen-plugin.test.ts tests/web-vitals-plugin.test.ts tests/logger.test.ts","typecheck":"tsc --noEmit -p tsconfig.test.json"},"_nodeVersion":"24.18.1","_id":"@chenweikang/frontend-radar-sdk-core@0.3.0","dist":{"integrity":"sha512-MPWD4TXMctY39/SkYd1PCO0v1AWi/gwTSwq4FboFrqxoKbVV1kYgrArwLpd7pnQxU5zFwowYYseK5/f8JJQ71g==","shasum":"dc6faf3aa7513bea87b504bd964597ba5e4c0cc4","tarball":"https://registry.npmjs.org/@chenweikang/frontend-radar-sdk-core/-/frontend-radar-sdk-core-0.3.0.tgz","fileCount":95,"unpackedSize":217657,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIG4vPBWLKl4De0CIgqXDVEW2rlaVyLBEFiEXK2bXf3hhAiBPKZ30DPDcXc0gi8hMkc/M2+Pg756CFxTEXV2gslD0FQ=="}]},"_npmUser":{"name":"chenweikang","email":"13400405244@163.com"},"directories":{},"maintainers":[{"name":"chenweikang","email":"13400405244@163.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/frontend-radar-sdk-core_0.3.0_1787654514720_0.3192492958172879"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-25T06:27:22.723Z","modified":"2026-08-25T10:41:54.992Z","0.1.0":"2026-08-25T06:27:23.043Z","0.2.0":"2026-08-25T09:46:53.106Z","0.3.0":"2026-08-25T10:41:54.878Z"},"license":"MIT","keywords":["frontend-radar","observability","monitoring","error-tracking","typescript"],"description":"Frontend Radar 的框架无关前端可观测性 SDK。","maintainers":[{"name":"chenweikang","email":"13400405244@163.com"}],"readme":"# @chenweikang/frontend-radar-sdk-core\n\n与框架无关的 Frontend Radar SDK Core，支持初始化、手动捕获错误或消息、附加用户/标签/上下文和面包屑数据、采样、脱敏，以及批量异步上报事件。\n\n新项目推荐安装统一入口包 `@chenweikang/frontend-radar-sdk`，并从包根路径使用同一套 Core API；仅需要框架无关能力时，也可以继续单独安装本包。\n\n```ts\nimport Monitor, {\n  installBrowserBreadcrumbs,\n  installJsErrorPlugin,\n} from '@chenweikang/frontend-radar-sdk-core'\n\nawait Monitor.initWithRemoteConfig({\n  appId: 'energy-dashboard',\n  env: 'production',\n  release: '2.3.1',\n  endpoint: 'https://monitor.example.com/api/v1/envelope',\n  remoteConfigUrl: 'https://radar.example.com/api/v1/sdk-config',\n  sampleRate: 1,\n  breadcrumbLimit: 50,\n})\n\nMonitor.setUser({ id: 'user-10001' })\nMonitor.setTag('tenantId', 'tenant-a')\nMonitor.setContext('project', { region: 'east' })\nMonitor.captureException(new Error('example'))\n\nconst jsErrors = installJsErrorPlugin(Monitor)\nconst removeBrowserBreadcrumbs = installBrowserBreadcrumbs(Monitor)\nconst removeFetchMonitor = Monitor.installFetch()\n\n// 适用于兼容 Axios 的实例，SDK Core 无需直接依赖 Axios。\nconst removeAxiosMonitor = Monitor.installAxios(axiosInstance, {\n  isRequestSuccess: (response) => response.data?.code === 0,\n})\n\n// 宿主应用销毁时可选择执行清理。\njsErrors.uninstall()\nremoveBrowserBreadcrumbs()\nremoveFetchMonitor()\nremoveAxiosMonitor()\n```\n\n由于 MVP 事件协议没有通用的消息事件类型，`captureMessage()` 默认生成 `console_error` 事件。两种捕获方法都会在事件成功进入队列时返回 event ID；如果 SDK 尚未初始化、事件未被采样、命中忽略规则或因其他原因无法安全捕获，则返回 `undefined`。\n\n所有公开方法都会隔离内部故障。传输失败会被静默丢弃，不会无限重试。TASK-005 的 JavaScript 错误插件会监听运行时错误、未处理的 Promise rejection，以及 script/link/img/audio/video 资源错误，同时不会阻止浏览器的默认行为。\n\nTASK-007 使用内存环形缓冲区保存最近 50 条面包屑，并仅在捕获事件时附加这些记录。浏览器插件会记录 History API/popstate/hashchange 导航、有效的按钮/链接点击和 `console.error`，同时保持宿主应用原有行为。面包屑消息最大为 500 个字符，数据最大为 4 KiB，并会对敏感字段进行脱敏。\n\nTASK-008 的 Fetch 和 Axios 监控会将每个未被忽略的请求记录为 HTTP 面包屑，并将 HTTP 状态错误、网络故障、超时和显式业务失败捕获为 `request_error` 事件。默认识别响应头 `x-request-id`/`request-id` 和 `x-trace-id`/`trace-id`，也支持自定义响应头列表。配置的 Collector 地址和 `ignoreUrls` 永远不会被递归采集。\n\nFetch 业务状态检查需要显式启用。每个回调都会收到克隆后的 Response，因此读取响应体不会影响返回给应用的原始响应：\n\n```ts\nMonitor.installFetch({\n  isRequestSuccess: async (response) =>\n    ((await response.json()) as { code: number }).code === 0,\n  getBusinessCode: async (response) =>\n    ((await response.json()) as { code: number }).code,\n  getErrorMessage: async (response) =>\n    ((await response.json()) as { message?: string }).message,\n})\n```\n\n请求体和响应体不会被保留。记录面包屑或捕获事件前，系统会对凭据和 URL 中的敏感查询参数值进行脱敏。\n\nTASK-016 增加 `initWithRemoteConfig()`。它根据 `appId` 和 `env` 请求配置、校验完整响应，并默认在内存中缓存成功结果五分钟；可以使用 `remoteConfigCacheTtl` 修改缓存时间。远程接口不可用或返回无效数据时，初始化会使用本地配置且不会抛出错误。远程配置中的 `enabled`、`sampleRate`、`captureConsoleError`、`breadcrumbLimit` 和字符串数组 `ignoreUrls` 会生效；本地与远程 URL 忽略规则会合并。\n\n## 控制台输出与调试\n\nSDK 默认保持静默，仅在浏览器控制台输出两类\"接入反馈\"（不受 `debug` 开关限制）：初始化成功后的品牌横幅，以及初始化失败（配置非法）的警告。横幅示例：\n\n```\n[Frontend Radar] v0.2.0 监控已启动\nappId: energy-dashboard · 环境: production · 版本: 2.3.1 · 采样: 100% · 上报: https://monitor.example.com\n```\n\n第一行带品牌徽章和版本徽章（`%c` 样式），第二行是灰色小字的配置摘要，\"上报\"只显示 endpoint 的 origin。若远程配置的 `enabled: false` 命中 kill switch，横幅状态变为\"监控已停用（远程配置）\"，配置摘要照常展示。\n\n需要排查接入问题时，传入 `debug: true` 开启诊断日志（带灰色 `Radar` 短徽章，仅 debug 模式输出）：\n\n```ts\nMonitor.init({\n  // ...\n  debug: true,\n})\n```\n\n诊断日志含义：\n\n- `远程配置加载成功：<url>` / `远程配置加载失败，已回退到本地配置：<url>`（警告）：`initWithRemoteConfig` 的远程配置结果。\n- `事件已捕获 <type> <eventId>`：事件成功入队，以折叠分组展示完整事件对象。\n- `已忽略（URL 忽略规则）`：请求 URL 命中 `ignoreUrls` 或 Collector 地址，事件被丢弃。\n- `已丢弃（采样）` / `已丢弃（重复事件）`：事件未通过采样或去重判定。\n- `已发送 N 个事件` / `发送失败，已丢弃 N 个事件`（警告）：批次上报结果。\n\n所有控制台输出都做了环境门控与异常隔离：非浏览器环境（无 `window`）下 SDK 完全静默，打印自身抛错也不会影响宿主应用；SDK 不会使用 `console.error` 刷红宿主控制台。\n\n## 事件去重\n\nSDK 默认在客户端对重复事件做去重，避免轮询报错、循环触发等场景刷屏上报。去重 key 由事件类型和归一化消息构成：异常事件使用 `exception.name + message`，请求事件使用 `method + url + status`，消息事件使用消息内容。同一 key 在 2 秒窗口内重复出现时会被丢弃，窗口过期后正常上报；去重发生在采样判定之后、事件入队之前，不影响采样和 URL 忽略的现有语义。\n\n```ts\nMonitor.init({\n  // ...\n  dedupe: true, // 默认 true，设为 false 可关闭去重\n  dedupeWindowMs: 2_000, // 默认 2000ms\n})\n```\n\n## 白屏检测\n\n`installWhiteScreenPlugin` 会在 `window.load` 后延迟执行一次检测：在视口内做 3×3 网格采样，通过 `document.elementsFromPoint` 判断每个采样点命中的元素是否包含根容器（默认 `#app`、`#root`、`body`）内的有效内容。空白点比例达到阈值（默认 0.9）时上报一次 `white_screen` 事件（每页面最多一次），事件自动附带最近的面包屑，`extra` 中包含 `score`、页面 `url` 和每个采样点的明细。非浏览器环境下插件会安全地安装失败，不会影响宿主应用。\n\n```ts\nimport { installWhiteScreenPlugin } from '@chenweikang/frontend-radar-sdk-core'\n\nconst whiteScreen = installWhiteScreenPlugin(Monitor, {\n  delay: 3_000, // load 后延迟检测时间，默认 3000ms\n  threshold: 0.9, // 空白点比例阈值，默认 0.9\n  grid: 3, // 网格每轴采样点数，默认 3（共 9 个点）\n  rootSelectors: ['#app', '#root', 'body'], // 根容器选择器\n})\n\n// 宿主应用销毁时可选择执行清理，移除监听器并取消待执行的检测。\nwhiteScreen.uninstall()\n```\n\n## 性能监控（Web Vitals）\n\n`installWebVitalsPlugin` 通过 `PerformanceObserver` 采集页面性能指标：LCP 取最后一条候选的 `startTime`，CLS 累计 `hadRecentInput === false` 的位移（保留 3 位小数），FCP 来自 `paint` 事件的 `first-contentful-paint`，TTFB 和 load 耗时读取 navigation entry 的 `responseStart`/`loadEventEnd`。页面切换为 `hidden` 时上报一次（此时 LCP/CLS 已稳定）；若页面一直可见，则在 `load` 后延迟 8 秒兜底上报一次。每页面最多上报一次 `web_vitals` 事件，指标放在 `extra` 中（单位 ms），采不到的指标字段直接省略。`web_vitals` 是性能数据而非异常，服务端只存储原始事件，不会聚合为 Issue。非浏览器环境（无 `PerformanceObserver`）下插件会安全地安装失败，不影响宿主应用。\n\n```ts\nimport { installWebVitalsPlugin } from '@chenweikang/frontend-radar-sdk-core'\n\nconst webVitals = installWebVitalsPlugin(Monitor, {\n  delay: 8_000, // load 后兜底上报的延迟，默认 8000ms\n})\n\n// 宿主应用销毁时可选择执行清理，断开所有 observer 并移除监听器。\nwebVitals.uninstall()\n```\n","readmeFilename":""}