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

@nstc-sdk/star-sdk

v1.0.0

Published

Front-end monitoring SDK

Downloads

26

Readme

Star SDK

轻量级前端监控埋点 SDK,支持 JS 错误监控、页面性能采集、用户行为追踪、白屏检测等功能。

特性

  • TypeScript 编写 — 完整的类型支持
  • 插件架构 — 支持自定义插件扩展
  • 批量上报 — 自动批量合并,减少请求数
  • 离线重试 — 使用 localStorage 持久化队列
  • 三级降级上报 — sendBeacon > fetch > Image Beacon
  • 会话追踪 — 自动管理 session ID
  • 用户行为轨迹 — 记录点击、导航等行为
  • 白屏检测 — MutationObserver 监控 DOM 渲染
  • 数据脱敏 — 自动过滤敏感字段
  • 完整清理 — destroy() 方法清理所有资源

安装

npm install star-sdk

或使用 CDN:

<script src="dist/index.global.js"></script>

快速开始

import { Star } from 'star-sdk';

// 初始化
const star = new Star({
  pid: 'your-project-id',        // 项目 ID(必填)
  reportUrl: 'https://your-server.com/report',  // 上报地址(必填)
  ucid: 'user-id',               // 用户 ID(可选)
  version: '1.0.0',             // 版本号
  isTest: true,                 // 测试模式
});

// 发送错误
star.notify('PaymentFailed', '/api/pay', { http_code: 500 });

// 发送行为
star.behavior('click', 'Submit Button', '/form');

// 发送事件
star.logger('page_view', { page: '/home' });

// SPA 卸载时清理
onUnmounted(() => star.destroy());

API 文档

构造函数

new Star(config: StarConfig): Star

配置项

| 配置项 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | pid | string | 必填 | 项目 ID | | reportUrl | string | 必填 | 上报服务器地址 | | uuid | string | 自动生成 | 设备唯一 ID | | ucid | string | '' | 用户唯一 ID | | isTest | boolean | false | 是否为测试数据 | | version | string | '1.0.0' | 应用版本号 | | sampleRate | number | 1 | 采样率 (0-1) | | batchMaxSize | number | 10 | 批量上报阈值 | | batchMaxWait | number | 5000 | 批量等待时间 (ms) | | maxRetries | number | 3 | 最大重试次数 | | getPageType | function | 自动生成 | 页面类型解析函数 | | record.js_error | boolean | true | 是否采集 JS 错误 | | record.performance | boolean | true | 是否采集性能数据 | | record.time_on_page | boolean | true | 是否采集在线时长 | | collectBreadcrumbs | boolean | true | 是否采集用户行为轨迹 | | collectResourceTiming | boolean | false | 是否采集资源耗时 | | maxBreadcrumbs | number | 20 | 最大行为轨迹条数 | | beforeSend | function | - | 发送前钩子 | | afterSend | function | - | 发送后钩子 |

实例方法

notify(errorName, url, extraInfo?)

上报自定义错误。

star.notify('PaymentFailed', '/api/pay', { http_code: 500, during_ms: 3000 });

error(code, detail?, extra?)

发送 error 类型日志 (codes 1-9999)。

star.error(1, { url: '/api/data', http_code: 500 }, {});

product(code, detail?, extra?)

发送 product 类型日志 (codes 10000-19999)。

star.product(10001, { duration_ms: 5000 }, {});

info(code, detail?, extra?)

发送 info 类型日志 (codes 20000-29999)。

star.info(20001, { action: 'search', keyword: 'test' }, {});

log(type, code, detail?, extra?)

通用日志方法。

star.log('error', 8, { error_name: 'CustomError' }, {});
star.log('product', 10002, { code: 'click', name: 'Button' }, {});

behavior(code, name, url?)

上报用户行为事件。

star.behavior('click_submit', 'Submit Button', '/form');

logger(name, props?, extra?)

通用事件追踪。

star.logger('page_exposure', { module: 'recommend', position: 3 }, { extra: 'data' });

detect(target?, notifyConfig?, observerConfig?, callback?)

白屏检测,监控 DOM 是否正常渲染。

// 基础用法
star.detect(
  document.getElementById('app'),  // 监控目标
  { errorName: 'WhiteScreen', url: '/home' },  // 错误配置
  { childList: true, subtree: true },  // MutationObserver 配置
  (hasContent) => { console.log(hasContent ? '渲染正常' : '白屏'); }  // 回调
);

addBreadcrumb(entry)

添加用户行为轨迹。

star.addBreadcrumb({
  category: 'custom',
  message: '用户提交表单',
  timestamp: Date.now(),
  data: { formId: 'contact-form' },
});

getBreadcrumbs()

获取当前所有行为轨迹。

const breadcrumbs = star.getBreadcrumbs();

use(plugin)

注册自定义插件。

import { Star, type StarPlugin } from 'star-sdk';

const myPlugin: StarPlugin = {
  name: 'my-plugin',
  setup(ctx) {
    ctx.bus.on('before-send', (payload) => {
      console.log('发送前:', payload);
      return payload;  // 返回 null 可丢弃
    });
  },
  teardown() {
    // 清理资源
  },
};

star.use(myPlugin);

destroy()

完整清理所有资源。

onUnmounted(() => {
  star.destroy();
});

getConfig()

获取当前配置(只读)。

const config = star.getConfig();

getSession()

获取会话信息。

const session = star.getSession();
// { id: 'abc123', startedAt: 1699999999999, pageViews: 3, lastActivity: 1699999999999 }

生命周期钩子

beforeSend

在数据发送前调用,可修改或丢弃数据。

const star = new Star({
  pid: 'test',
  reportUrl: 'https://example.com/report',
  beforeSend: (payload) => {
    // 丢弃测试环境的错误
    if (payload.type === 'error' && payload.detail?.desc?.includes('test')) {
      return null;
    }
    // 添加额外字段
    payload.extra = { ...payload.extra, environment: 'production' };
    return payload;
  },
});

afterSend

在数据发送后调用,可用于日志记录。

const star = new Star({
  pid: 'test',
  reportUrl: 'https://example.com/report',
  afterSend: (payload, success) => {
    if (!success) {
      console.error('上报失败:', payload);
    }
  },
});

错误类型码

| 类型 | 范围 | 说明 | |------|------|------| | error | 1-9999 | JS 运行时错误、资源加载错误等 | | product | 10000-19999 | 业务行为数据 | | info | 20000-29999 | 信息类数据 | | perf | 20001-20999 | 性能指标 | | event | 30001+ | 自定义事件 |

JS 错误类型

| 类型码 | 名称 | 说明 | |--------|------|------| | 1 | RUNTIME | JS 运行时错误 | | 2 | SCRIPT | 脚本加载失败 | | 3 | STYLE | 样式加载失败 | | 4 | IMAGE | 图片加载失败 | | 5 | AUDIO | 音频加载失败 | | 6 | VIDEO | 视频加载失败 | | 7 | CONSOLE | console.error 捕获 | | 8 | TRY_CATCH | try-catch 捕获 |

插件开发

StarPlugin 接口

interface StarPlugin {
  name: string;                    // 插件名称(唯一)
  setup(ctx: StarContext): void;  // 初始化时调用
  teardown(): void;               // 销毁时调用
}

StarContext 接口

interface StarContext {
  readonly config: Readonly<ResolvedConfig>;  // 只读配置
  report(payload: Omit<ReportPayload, 'common'>): void;  // 上报数据
  reportError(errorLog: ErrorLog): void;    // 上报错误
  notify(errorName: string, url: string, extraInfo?: Record<string, unknown>): void;
  addBreadcrumb(entry: BreadcrumbEntry): void;
  getBreadcrumbs(): ReadonlyArray<BreadcrumbEntry>;
  readonly bus: EventBus;          // 事件总线
  readonly session: SessionManager;  // 会话管理
  debug(...args: unknown[]): void;  // 调试日志
}

EventBus 事件

type EventMap = {
  'before-send': (payload: ReportPayload) => ReportPayload | null;
  'after-send': (payload: ReportPayload, success: boolean) => void;
  'on-error': (error: ErrorLog) => void;
  'session-update': (session: SessionInfo) => void;
};

示例:自定义性能插件

import type { StarPlugin, StarContext } from 'star-sdk';

export class CustomPerformancePlugin implements StarPlugin {
  name = 'custom-performance';
  private ctx!: StarContext;

  setup(ctx: StarContext): void {
    this.ctx = ctx;

    window.addEventListener('load', () => {
      this.ctx.report({
        type: 'perf',
        code: 20010,
        detail: {
          customMetric: this.measureSomething(),
        },
        extra: {},
      });
    });
  }

  teardown(): void {
    // 清理资源
  }

  private measureSomething(): number {
    return performance.now();
  }
}

// 使用
star.use(new CustomPerformancePlugin());

工具函数

tryWrap / tryWrapIgnore / tryWrapArgs

安全包装函数,自动捕获异常。

import { tryWrap, tryWrapIgnore, tryWrapArgs } from 'star-sdk';

// 包装函数,返回结果和错误
const safeFn = tryWrap((data: string) => JSON.parse(data));
const { result, error } = safeFn('invalid json');

// 忽略错误,返回 undefined
const safeParse = tryWrapIgnore(JSON.parse);
const result = safeParse('invalid json');  // undefined

// 包装函数参数
const wrappedFn = tryWrapArgs(someFunction);

debounce / throttle

防抖和节流函数。

import { debounce, throttle } from 'star-sdk';

// 防抖
const debouncedFn = debounce(() => {
  star.behavior('scroll', 'End of Page');
}, 500);

// 节流
const throttledFn = throttle(() => {
  star.behavior('scroll', 'Scrolling');
}, 200);

其他工具

import {
  getUUID,      // 生成 UUID
  hash,         // 字符串哈希
  parseDomain,  // 解析域名
  safeStringify,  // 安全 JSON 序列化
  truncate,     // 字符串截断
  noop,        // 空函数
  clog,        // 红色控制台日志
  getDeviceId,  // 获取设备 ID
} from 'star-sdk';

上报数据格式

单条数据

{
  "type": "error",
  "code": 1,
  "detail": {
    "desc": "Uncaught TypeError: Cannot read property",
    "stack": "at foo (https://example.com/app.js:10:5)"
  },
  "extra": {},
  "common": {
    "pid": "project-id",
    "uuid": "device-uuid",
    "ucid": "user-id",
    "timestamp": 1699999999999,
    "sdk_version": "1.0.0",
    "page_type": "example.com/detail",
    "session_id": "session-123"
  }
}

批量上报

批量数据通过 POST JSON 发送,请求体为数组格式:

[
  { "type": "error", "code": 1, ... },
  { "type": "product", "code": 10001, ... }
]

服务端接入

服务端需要接收 POST 请求,Content-Type 为 application/json

Node.js 示例:

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/report') {
    let body = '';
    req.on('data', chunk => body += chunk);
    req.on('end', () => {
      const data = JSON.parse(body);
      console.log('收到上报数据:', data);
      res.end('ok');
    });
  }
});

server.listen(3000);

浏览器兼容

  • Chrome 49+
  • Firefox 44+
  • Safari 10+
  • Edge 79+

不支持 IE。