npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@arms/rum-electron

v0.0.9

Published

ARMS RUM SDK for Electron – real user monitoring for main & renderer processes

Readme

@arms/rum-electron

阿里云 ARMS 用户体验监控 Electron SDK。一次主进程 init() 即覆盖主进程与渲染进程:自动采集异常、原生崩溃、HTTP/tRPC、应用启动指标、页面 PV、性能、Web Vitals 等数据,由主进程统一上报。

核心特性

  • 零配置自动注入:主进程 init() 后,所有 BrowserWindow 自动注入 Browser SDK 与 IPC Bridge,渲染进程零改造
  • 统一上报通道:渲染进程事件经 arms:rum-bridge IPC 通道回流至主进程,由主进程统一组织与上报
  • 主进程监控全覆盖
    • 未捕获异常、未处理 Promise 拒绝、console.error 拦截
    • 原生崩溃(集成 WASM minidump-processor,解析 .dmp 获取完整堆栈与模块)
    • 应用启动指标(app ready 耗时、进程数、主进程 CPU/内存)
    • HTTP 请求自动采集:globalThis.fetchhttp/https 模块双层 patch(覆盖 axios 默认 adapter、got、node-fetch 等),自动产出 type='api' 资源事件,附带 DNS/TCP/TLS/TTFB/下载等细分耗时
    • tRPC server 端 procedure 调用(type='rpc'),通过 armsRum.instrumentTRPC() 一行接入
  • 内存与 OOM 监控:运行时内存水位 + OOM 专项(RendererOOM / MainProcessOOM 回溯补报 / 双链路去重)+ memory-eviction(MemoryEviction,不计崩溃率)+ V8 堆高水位预警(V8HeapNearOOM
  • 渲染进程自动注入:PV、性能、Web Vitals、白屏、API、长任务等
  • 分布式链路追踪:内置 tracing 配置,支持 W3C tracecontext / B3 / B3 multi / Jaeger / SW8;主进程 fetch、http/https 模块与 tRPC procedure 共享同一份决策
  • 远程配置:支持 ARMS 控制台下发配置,动态调整采样率、采集器开关等

安装

npm install @arms/rum-electron

| 依赖 | 版本要求 | 说明 | |------|----------|------| | electron | >= 28.0.0 | peerDependency(必装),由项目自行安装 | | @trpc/server | * | 仅在使用 instrumentTRPC() 时由业务侧安装(optional peer) |

运行环境要求 Node >= 18、Electron >= 28。需要 Electron 28+ 是因为 SDK 使用 session.registerPreloadScript()(v28 新增),低版本会自动回退到 session.setPreloads()

快速接入

1. 主进程顶层 importinit()

SDK 必须在 app.ready 之前被 import——src/index.ts 顶层会调用 protocol.registerSchemesAsPrivileged() 注册 rum-event 协议(占位用,预留给后续降级通道,不影响功能)。

// main/index.ts —— 文件顶部
import armsRum from '@arms/rum-electron';
import { app } from 'electron';

armsRum.init({
  endpoint: '<your-endpoint>',  // 控制台「用户体验监控 > 应用列表」创建应用后获取
  env: 'prod',                  // 'prod' | 'gray' | 'pre' | 'daily' | 'local'
  version: '1.0.0',
});

app.whenReady().then(() => {
  // 创建 BrowserWindow 等
});

2. 渲染进程零改造

默认 autoInject: true:SDK 监听 web-contents-created,在每个 BrowserWindowdom-ready 时机注入 Browser SDK 脚本与 IPC Bridge。渲染进程既不需要 import SDK,也不需要修改 preload。

3.(可选)验证数据

armsRum.init({
  endpoint: '<your-endpoint>',
  beforeReport(bundle) {
    console.log('[RUM]', bundle);
    return bundle;     // 返回 falsy(如 undefined)会丢弃整个 bundle 不上报;需保留数据必须 return bundle
  },
});

4.(可选)自定义 partition

BrowserWindow 使用了自定义 partition(如 'persist:main')时,必须显式声明,否则该 partition 下的窗口不会注入 IPC Bridge:

// 方式一:init 时声明(单 partition 推荐)
await armsRum.init({
  endpoint: '<your-endpoint>',
  partition: 'persist:main',
});

// 方式二:init 之后动态注册(多 partition 场景)
await armsRum.init({ endpoint: '<your-endpoint>' });
await armsRum.registerSession('persist:other');

5.(可选)启用 tRPC 监控

主进程使用 tRPC 定义 server router 时(如 electron-trpc),用 armsRum.instrumentTRPC() 包一层 t,所有 procedure 自动带监控 middleware:

import { initTRPC } from '@trpc/server';
import armsRum from '@arms/rum-electron';

const t = armsRum.instrumentTRPC(initTRPC.create());

export const appRouter = t.router({
  greeting: t.procedure.input(...).query(...),
});

详见 docs/接入Electron应用.md 中的 tRPC 监控章节。

主进程作为 tRPC client 调用云端 HTTP 服务时无需额外接入:底层 fetch 或 http/https 请求会被 ApiCollector 自动采集为 type='api' 事件。

配置一览

init(config) 接收 IElectronConfig,继承自 @arms/rum-coreIConfiguration。下表为常用字段,完整版见 docs/Electron SDK配置参考.md

基础

| 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | endpoint | string | 是 | — | ARMS 数据上报地址 | | enable | boolean | 否 | true | 关闭后所有采集器与上报均不工作 | | env | 'prod' \| 'gray' \| 'pre' \| 'daily' \| 'local' | 否 | — | 应用环境标识 | | version | string | 否 | — | 应用版本号 | | app | object | 否 | — | 应用扩展信息(name / channel / framework 等) | | user | object | 否 | — | 用户信息(id / name / tags) |

Electron 专属

| 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | autoInject | boolean | true | 是否自动向 BrowserWindow 注入 Browser SDK | | partition | string | — | 自定义 session partition;与 BrowserWindow.webPreferences.partition 对应 | | spaMode | false \| true \| 'auto' \| 'hash' \| 'history' | false | SPA 路由追踪模式 | | tracing | boolean \| ITracingOption | — | 分布式链路追踪(主进程 fetch + tRPC procedure 共用) | | evaluateApi | (request, response, error?) => Promise<IApiBaseAttr> | — | 自定义 API/RPC payload 解析,返回值经 reviseApiAttr 裁剪后合并 | | parseViewName | (url: string) => string | — | 自定义页面 name 解析(兜底用 SpaMode 解析 URL) | | parseResourceName | (url: string) => string | — | 自定义资源 name 解析;默认取 URL pathname | | beforeReport | (bundle) => any | — | 上报前回调,可改写 bundle | | browserCollectors | Record<string, boolean \| ICollectorConfig> | 全部启用 | 渲染进程 Browser SDK 采集器开关(仅 autoInject 模式生效) | | properties | Record<string, number \| string> | — | 全局自定义属性,附加到所有上报事件 |

主进程采集器(collectors)

armsRum.init({
  endpoint: '<your-endpoint>',
  collectors: {
    crash: false,            // 关闭崩溃采集
    consoleError: false,     // 关闭 console.error 拦截
    api: {
      enable: true,
      filters: [/\.internal\.example\.com/],   // 命中即不上报
    },
    rpc: {
      enable: true,
      filters: [/^internal\./],                // 按 procedure path 跳过
    },
    memory: {
      enable: true,                            // 默认关闭,需显式开启;OOM / eviction / 堆预警均随此总开关
      interval: 1_800_000,                     // 窗口聚合上报间隔 ms,默认 30min(最小值同样为 30min)
      onLaunch: true,                          // app ready 时发出启动基线事件
      onInterval: true,                        // 启用窗口聚合周期采集
      onCrash: true,                           // render/child-process-gone 时立即 flush
      onQuit: true,                            // before-quit 时立即 flush
      onOom: true,                             // OOM 事件分发 + 主进程 OOM 回溯补报(默认 true;eviction 不受其控制)
      crashReasons: [                          // crash flush 触发 reason 白名单(默认 6 项)
        'crashed', 'oom', 'memory-eviction',
        'abnormal-exit', 'launch-failed', 'integrity-failure',
      ],
      heapWarning: {                           // 渲染进程 V8 堆高水位预警(near_oom),默认全开
        enable: true,                          // 默认 true
        threshold: 0.85,                       // 堆使用率阈值 (0,1),默认 0.85
        consecutiveCount: 3,                   // 连续超阈采样次数,默认 3
        sampleInterval: 10_000,                // 采样间隔 ms(下限 1s),默认 10s
      },
    },
    anr: {
      enable: true,                            // 默认关闭,需显式开启
      anrThreshold: 5000,                      // ANR 阈值 ms(3000–30000)
      captureStackTrace: true,                 // 渲染进程调用栈采集(Electron >= 34 需 Feature Flag;低版本自动走 CDP 采集)
      main: true,
      renderer: true,
    },
  },
});

| 采集器 | 默认 | 说明 | |--------|------|------| | jsError | true | 主进程未捕获异常 + 未处理 Promise 拒绝 | | consoleError | true | console.error 拦截上报 | | crash | true | 原生崩溃采集(依赖 crashReporter) | | application | true | 应用启动指标 | | memory | false | 内存监控总开关:运行时内存水位(10s 后台采样 / 30min 窗口聚合 + crash/quit 触发;事件附 context 公用环境快照)+ OOM 专项 + memory-eviction + V8 堆高水位预警,详见下文「内存与 OOM 监控」 | | api | true | 主进程 HTTP 请求采集:globalThis.fetch + http/https 模块 patch,覆盖 axios 默认 adapter 等(type='api',附细分耗时字段) | | rpc | true | tRPC server middleware(配合 instrumentTRPCtype='rpc') | | anr | false | 应用未响应监控(主进程 worker + V8 Inspector 采集调用栈,降级为 setTimeout 探针;渲染进程心跳超时,Electron >= 34 经官方 API、低版本经 CDP 采集渲染进程调用栈) |

ANR 监控

AnrCollector 检测主进程与渲染进程的事件循环长时间阻塞(Application Not Responding),作为 EXCEPTION 事件上报:exception.type='anr'exception.source='main_anr'(主进程)或 'renderer_anr'(渲染进程)。

  • 主进程:独立 worker_threads watchdog 通过 IPC 心跳检测主线程阻塞,阻塞时经 V8 Inspector(connectToMainThread + Debugger.pause)采集主线程调用栈(snapshots.timing='on-block'snapshots.stack_source='inspector_worker');worker 不可用或 Inspector 超时时自动降级为 setTimeout 探针漂移检测,此路径无调用栈、仅 post-block 进程快照(snapshots.timing='post-block')。
  • 渲染进程:主进程作为外部观察者,监测渲染进程经 preload 定时器发送的 IPC 心跳超时;超时后采集调用栈(snapshots.timing='on-detect')——Electron >= 34 经 webContents.mainFrame.collectJavaScriptCallStack()snapshots.stack_source='collectJavaScriptCallStack');Electron < 34 自动降级为 CDP 采集:SDK 预先 webContents.debugger.attach + Debugger.enable,ANR 时发送 Debugger.pause 打断阻塞主线程获取栈帧(snapshots.stack_source='cdp_debugger')。

ℹ️ 渲染进程心跳机制:心跳由 SDK preload 脚本内的 setInterval 自主驱动,与渲染进程主线程共用同一事件循环——主线程被同步阻塞时心跳随之停发,从而被主进程 watchdog 判定为 ANR。无需主进程 executeJavaScript 注入。

  • 防抖与限流:同源同窗口 120s 内最多 1 条;全局 30min 内最多 5 条;ANR 触发后 5s 恢复静默窗;被抑制次数记入 snapshots.suppressed_count
  • caused_by(仅主进程,启发式推断):系统可用内存 < 15% → memory_pressure;主进程 CPU > 80% → cpu_saturation;否则 event_loop_blocked

⚠️ 渲染进程调用栈采集(Electron >= 34)需用户设置 Feature Flag:在 app.ready 之前、import SDK 之前调用 app.commandLine.appendSwitch('enable-features', 'DocumentPolicyIncludeJSCallStacksInCrashReports')。 SDK 自动注入 Document-Policy: include-js-call-stacks-in-crash-reports 响应头;未设置 flag 时渲染进程 ANR 仍会上报,但 stack 为空。

Electron < 34(低至 28)自动降级为 CDP 采集,无需 Feature Flag 与 Document-Policy;若该窗口的调试会话已被 DevTools 扩展/业务代码经 webContents.debugger 占用,则降级为无栈事件(仅 warn 一次)。

已知限制:Electron 每个 session 每 event 仅允许一个 onHeadersReceived listener,SDK 注入会覆盖既有 listener;需保留自定义 listener 时设 autoInjectDocumentPolicy: false

内存与 OOM 监控

MemoryCollectorcollectors.memory,默认关闭,需显式开启)除运行时内存水位(启动基线 / 30min 窗口聚合 / crash / quit 多触发时机,后台采样固定 10s)外,还提供四类异常事件,均以 EXCEPTION 上报:

| 事件 | type / subtype / name | 语义 | |------|----------------------|------| | 渲染进程 OOM | crash / oom / RendererOOM | 判定三判据(满足其一):render-process-gonereason='oom'killedexitCode=134killed 且系统可用内存 ≤ 10%。immediate 分发,附带崩溃时刻全进程内存现场与 crashed_url | | 主进程 OOM 回溯 | crash / oom / MainProcessOOM | 主进程死亡无法实时上报,下次启动回溯补报;仅当上次启动异常退出且有高水位佐证(工作集 ≥ 70% 或系统可用内存 ≤ 10%)才补报,断电 / 强杀等无佐证场景自动降噪不发 | | memory-eviction | memory / eviction / MemoryEviction | 渲染进程被系统因整机内存压力回收:应用整体存活,不计入崩溃率,可进异常列表告警;仅随 memory 总开关,与 onOom / onCrash 互不影响;同时 APPLICATION 内存指标照发(双链路) | | V8 堆高水位预警 | memory / near_oom / V8HeapNearOOM | heapUsed / heap_size_limit 超过阈值(默认 0.85)连续 3 个采样周期(默认每 10s)触发,5min 冷却,immediate 单发;与 OOM 构成「预警 → 真死」漏斗,不计入崩溃率 |

  • onOom(默认 true):控制 OOM 事件分发与主进程 OOM 回溯补报;eviction 不受其控制。
  • heapWarning 配置入口为 collectors.memory.heapWarningenable 默认 truethreshold 默认 0.85consecutiveCount 默认 3sampleInterval 默认 10s,下限 1s);autoInject: false 手动注入模式下需在渲染侧 browser 初始化配置 collectors.heapWarning 启用。
  • 独立限流:OOM 桶 30min 内最多 5 条、eviction 桶 30min 内最多 2 条,独立分桶计数,防多窗口连续异常风暴。
  • system_memory 条件附带:仅 OOM 与 eviction 事件在应用占用系统内存 ≥ 30% 或系统可用内存 ≤ 15% 时于 snapshots 附带 system_memory 键,其余场景省略;near_oom 不附带。
  • Electron 42+ 双链路去重:同一渲染进程 V8 堆 OOM,运行时链路与 crashReporter / minidump 链路经跨会话登记表去重(60s 容差);minidump 链路未命中登记表(运行时漏报)时补发 OOM 归因的 crash 事件(subtype='oom'name='RendererOOM',吸收 crashpad 注解中的 JS 调用栈),避免漏采。
  • 崩溃率口径type='crash'name != 'NonFatalCrash' 计入崩溃率;type='memory' 不计入;子进程(GPU / utility)崩溃不计入崩溃率,仅内存留痕。

渲染进程采集器(browserCollectors)

autoInject: true 时控制注入到渲染进程的 Browser SDK 采集器:

| 采集器 | 说明 | |--------|------| | perf | 页面加载性能 | | webvitals | Web Vitals(LCP / FID / CLS) | | exception | 未捕获异常 + Promise 拒绝 | | whiteScreen | 白屏检测 | | api | XHR / Fetch HTTP 请求 | | staticResource | 静态资源加载 | | click / action | 用户交互 | | longTask | 长任务(>50ms) |

armsRum.init({
  endpoint: '<your-endpoint>',
  browserCollectors: {
    longTask: false,
    whiteScreen: false,
    api: { enable: true },
  },
});

链路追踪(tracing)

armsRum.init({
  endpoint: '<your-endpoint>',
  tracing: {
    enable: true,
    sample: 10,                                    // 10% 采样(取值 0–100)
    propagatorTypes: ['tracecontext', 'b3'],
    allowedUrls: [/^https:\/\/api\.example\.com/], // 仅向白名单注入追踪头
  },
});

| 字段 | 类型 | 说明 | |------|------|------| | enable | boolean | 是否启用链路追踪 | | sample | number | 采样率,取值 0–100(默认 100) | | propagatorTypes | Array<'tracecontext' \| 'b3' \| 'b3multi' \| 'jaeger' \| 'sw8'> | 传播协议 | | allowedUrls | Array<MatchOption \| TraceOption> | 命中规则的 URL/path 才会注入追踪头;未配置时默认全量命中 | | tracestate / baggage | boolean | 是否携带 W3C tracestate / baggage |

主进程 fetch 与 http/https 模块请求(ApiCollector)、tRPC procedure(RpcCollector)共用同一份 tracing 决策,自动在 outbound 请求注入 traceparent 等头。

evaluateApi:把 payload 写入 snapshots

evaluateApi 用于把请求/响应内容写入事件。SDK 不会自动采集 payload——业务侧按需提取并经返回值 snapshots 上报,SDK 自动经 reviseApiAttr 裁剪至 5KB:

armsRum.init({
  endpoint: '<your-endpoint>',
  async evaluateApi(request, response, error) {
    const snapshot: Record<string, unknown> = {};
    if (request && typeof request === 'object' && 'input' in request) {
      snapshot.input = (request as { input?: unknown }).input;
    }
    if (response && typeof response === 'object' && 'data' in response) {
      snapshot.output = (response as { data?: unknown }).data;
    }
    return {
      success: error ? 0 : 1,
      snapshots: JSON.stringify(snapshot),
    };
  },
});

字段约定:snapshots 留给 SDK / evaluateApi 写采集元数据,properties 保留给用户业务标签。回调有 50ms 超时硬限,超时后回退到原始事件。

离线队列(offlineQueue)

上报失败(网络异常 / 超时 / HTTP 非 2xx)时,事件自动持久化到磁盘({userData}/rum-electron-store/offline-queue/),应用重启或网络恢复后自动重发:

armsRum.init({
  endpoint: '<your-endpoint>',
  offlineQueue: {
    enable: true,        // 默认 true
    maxAgeDays: 30,      // 最大保留天数,默认 30
    maxQueueSize: 200,   // 最大条数,默认 200,超限淘汰最旧
  },
});

运行时 API

// 修改单个字段
armsRum.setConfig('enable', false);

// 批量修改
armsRum.setConfig({ env: 'staging', version: '1.1.0' });

// 读取当前完整配置
const config = armsRum.getConfig();

// 为额外的 partition 注册 preload(init 之后调用)
await armsRum.registerSession('persist:other');

// 一行接入 tRPC server 监控(需 @trpc/server)
const t = armsRum.instrumentTRPC(initTRPC.create());

渲染进程门面 window.ArmsRum

preload 脚本会在渲染进程暴露 window.ArmsRum 门面(不依赖 autoInject,preload 已加载即可用),提供 sendCustom / sendView / sendException / sendResource 四个方法,payload 经 IPC 转发至主进程,复用主进程校验与组装逻辑:

// renderer(任意页面脚本)
window.ArmsRum?.sendCustom({ type: 'biz', name: 'checkout_click', value: 1 });
window.ArmsRum?.sendException(new Error('checkout failed'));
  • 不依赖 Browser SDK 注入时机,页面早期即可调用;autoInject: false 手动注入模式下同样可用
  • 兼容 contextIsolation 开启 / 关闭两种场景(双注入兼容)
  • SDK init() 之前的调用会被静默丢弃
  • sendView 的视图 URL 由 SDK 自动采集当前页面地址,payload 中的 url 字段会被忽略

注意事项

  1. init() 必须在 app.ready 之前调用,且 SDK 模块本身必须更早被 import——src/index.ts 顶层调用 protocol.registerSchemesAsPrivileged(),错过 ready 之前的窗口会导致协议注册失败并触发 Electron 警告。
  2. Electron 版本 >= 28:SDK 优先使用 session.registerPreloadScript()(v28 新增),低版本自动降级到 session.setPreloads()
  3. 不要覆盖 SDK 注册的 preload:若应用层调用 session.setPreloads() 覆盖全部 preload,渲染进程事件将无法回流。建议使用追加方式。
  4. autoInject: true 模式下禁止在渲染进程手动 import '@arms/rum-electron/browser':会导致重复初始化与事件双采。
  5. 自定义 partition 必须显式声明:未声明的 partition 下的窗口里 window.ArmsEventBridgeundefined,RUM 数据无法上报。
  6. evaluateApi 内禁止同步阻塞:回调有 50ms 超时硬限,超时后回退到原始事件不抛错。
  7. tRPC 监控仅采 server 端:主进程作为 tRPC client 调用云端 HTTP 时由 ApiCollector 在 fetch / http 模块层自动采集为 type='api',不需要再包 link。
  8. 主进程原生 ESM 可用:无打包器直接 import SDK 产物(如 dist/index.mjs)时 @arms/rum-core 模块解析正常(0.0.9 修复了此场景下的解析崩溃)。