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

@lhxktxwd/stackflare-browser

v0.1.1

Published

给业务前端项目使用的日志上传 SDK,目标是默认接入简单、需要定制时也足够灵活。

Readme

@lhxktxwd/stackflare-browser

给业务前端项目使用的日志上传 SDK,目标是默认接入简单、需要定制时也足够灵活。

安装时只需要这个包,不需要再额外安装 @log-monitor/shared

快速开始

import { createLogMonitorSdk } from '@lhxktxwd/stackflare-browser';

const sdk = createLogMonitorSdk({
  endpoint: 'https://your-domain.com',
  appId: 'mobile-h5',
  clientKey: 'your-client-key',
  env: 'prod',
  appVersion: '1.2.3'
});

sdk.installAutoCapture();

常用用法

1. 手动上报一条日志

sdk.capture({
  level: 'error',
  type: 'custom',
  message: 'submit order failed',
  extra: {
    orderId: 'o_1001'
  }
});

2. 直接上报 Error

try {
  throw new Error('manual test');
} catch (error) {
  sdk.captureError(error, {
    scene: 'checkout'
  });
}

3. 上报接口异常

sdk.captureApiError({
  error,
  method: 'POST',
  requestUrl: '/api/orders',
  status: 500,
  responseBody: responseData,
  extra: {
    scene: 'submit-order'
  }
});

4. 包装 fetch

const monitoredFetch = sdk.wrapFetch(window.fetch.bind(window));

await monitoredFetch('/api/orders', {
  method: 'POST',
  body: JSON.stringify({ orderId: 'o_1' })
});

默认会自动上报:

  • fetch 抛出的网络异常
  • HTTP 4xx / 5xx 响应

5. 接入 uniapp

uniapp 的 uni.request 不是标准 fetch,建议给 SDK 单独配置上传 transport,不要复用业务项目封装过的请求实例,避免把 platformtenant-id 等业务请求头带到日志上报里。

import { createLogMonitorSdk, createUniRequestTransport } from '@lhxktxwd/stackflare-browser';

const sdk = createLogMonitorSdk({
  endpoint: 'https://winsan.com.cn/view/log-monitor',
  appId: 'mobile-h5',
  clientKey: 'your-client-key',
  env: 'prod',
  transport: createUniRequestTransport(uni.request)
});

sdk.installAutoCapture();

SDK 只会给上传请求设置 content-typex-log-monitor-key

6. 接入 axios

import axios from 'axios';
import { createLogMonitorSdk } from '@lhxktxwd/stackflare-browser';

const sdk = createLogMonitorSdk({
  endpoint: 'https://your-domain.com',
  appId: 'mobile-h5',
  clientKey: 'your-client-key',
  env: 'prod'
});

const request = axios.create();
const teardownAxios = sdk.instrumentAxios(request);

这样 axios 请求失败时会自动上报接口异常;如果后面不需要了,可以执行 teardownAxios() 移除拦截器。

如果你们项目里已经有统一请求实例,通常就是这样接:

import axios from 'axios';
import { createLogMonitorSdk } from '@lhxktxwd/stackflare-browser';

export const sdk = createLogMonitorSdk({
  endpoint: 'https://your-domain.com',
  appId: 'mobile-h5',
  clientKey: 'your-client-key',
  env: 'prod',
  getContext: () => ({
    userId: window.__CURRENT_USER__?.id,
    route: window.location.pathname
  })
});

export const request = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000
});

sdk.instrumentAxios(request);

默认会上报:

  • 请求抛出的异常
  • error.response 里的状态码、状态文案、请求地址、请求方法
  • 请求体和响应体

如果你只想上报 5xx,或者想补充业务字段,也可以这样写:

sdk.instrumentAxios(request, {
  captureHttpErrorStatus: (response) => response.status >= 500,
  buildInput({ error, response }) {
    return {
      error,
      requestUrl: response?.config?.url,
      method: response?.config?.method,
      status: response?.status,
      extra: {
        scene: 'submit-order'
      }
    };
  }
});

框架接入示例

Vue 项目

可以在 src/monitor.ts 里统一初始化:

import axios from 'axios';
import { createLogMonitorSdk } from '@lhxktxwd/stackflare-browser';

export const sdk = createLogMonitorSdk({
  endpoint: 'https://your-domain.com',
  appId: 'mobile-h5',
  clientKey: 'your-client-key',
  env: import.meta.env.PROD ? 'prod' : 'dev',
  appVersion: __APP_VERSION__,
  getContext: () => ({
    route: window.location.pathname,
    userId: window.__CURRENT_USER__?.id
  })
});

export const request = axios.create({
  baseURL: '/api',
  timeout: 10000
});

sdk.installAutoCapture();
sdk.instrumentAxios(request);

然后在 main.ts 里引入一次:

import { createApp } from 'vue';
import App from './App.vue';
import './monitor';

createApp(App).mount('#app');

如果你们项目用了 vue-router,也可以在路由切换后同步上下文:

import { router } from './router';
import { sdk } from './monitor';

router.afterEach((to) => {
  sdk.updateContext({
    route: to.fullPath
  });
});

React 项目

可以在 src/monitor.ts 里统一初始化:

import axios from 'axios';
import { createLogMonitorSdk } from '@lhxktxwd/stackflare-browser';

export const sdk = createLogMonitorSdk({
  endpoint: 'https://your-domain.com',
  appId: 'web-admin',
  clientKey: 'your-client-key',
  env: import.meta.env.PROD ? 'prod' : 'dev',
  getContext: () => ({
    route: window.location.pathname,
    userId: window.__CURRENT_USER__?.id
  })
});

export const request = axios.create({
  baseURL: '/api',
  timeout: 10000
});

sdk.installAutoCapture();
sdk.instrumentAxios(request);

然后在应用入口引入一次:

import './monitor';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

如果路由是 React Router,可以在路由变化时同步上下文:

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { sdk } from './monitor';

export function RouteMonitor() {
  const location = useLocation();

  useEffect(() => {
    sdk.updateContext({
      route: `${location.pathname}${location.search}`
    });
  }, [location.pathname, location.search]);

  return null;
}

灵活配置

const sdk = createLogMonitorSdk({
  endpoint: 'https://your-domain.com',
  appId: 'mobile-h5',
  clientKey: 'your-client-key',
  env: 'prod',
  appVersion: '1.2.3',
  defaultContext: {
    route: '/orders',
    extra: {
      tenant: 'cn'
    }
  },
  getContext: () => ({
    userId: currentUser?.id,
    extra: {
      release: window.__APP_VERSION__
    }
  }),
  beforeSend(payload) {
    if (payload.message.includes('ignore')) {
      return null;
    }

    return {
      ...payload,
      extra: {
        ...(payload.extra || {}),
        appChannel: 'h5'
      }
    };
  },
  sanitize: {
    sensitiveKeys: ['payToken', /^x-/i],
    replacement: '[Filtered]'
  },
  batch: {
    maxBatchSize: 10,
    flushIntervalMs: 5000,
    maxRetries: 2,
    retryDelayMs: 1500
  }
});

SDK 默认会在发送前脱敏常见敏感字段,例如 authorizationcookietokenpasswordsecretphoneidCard。如需完全关闭:

const sdk = createLogMonitorSdk({
  endpoint: 'https://your-domain.com',
  appId: 'mobile-h5',
  clientKey: 'your-client-key',
  env: 'prod',
  sanitize: false
});

wrapFetchinstrumentAxios 也支持自定义:

const monitoredFetch = sdk.wrapFetch(window.fetch.bind(window), {
  captureHttpErrorStatus: (response) => response.status >= 500,
  buildInput({ input, response, error }) {
    if (!response && !error) return null;

    return {
      error,
      requestUrl: typeof input === 'string' ? input : undefined,
      status: response?.status,
      extra: {
        scene: 'order-submit'
      }
    };
  }
});

能力说明

  • capture:手动上报任意日志
  • captureError:快速上报 Error
  • captureApiError:快速上报接口异常
  • wrapFetch:自动采集 fetch 请求异常
  • instrumentAxios:自动采集 axios 请求异常
  • installAutoCapture:自动采集运行时异常
  • updateContext:动态更新公共上下文
  • flush:立即发送当前批次队列
  • destroy:卸载监听并清空发送队列

Source Map 自动上传

发布构建后可以在 CI/CD 中上传 .map 文件:

npx @lhxktxwd/stackflare-browser upload-sourcemaps \
  --endpoint https://your-domain.com \
  --upload-key "$STACKFLARE_SOURCE_MAP_UPLOAD_KEY" \
  --app-id mobile-h5 \
  --app-version "$APP_VERSION" \
  --dir dist/assets \
  --bundle-prefix /assets

STACKFLARE_SOURCE_MAP_UPLOAD_KEY 可以在后台“应用配置”里复制,对应具体 app,只能上传该 app 的 Source Map。

也可以用环境变量:

STACKFLARE_ENDPOINT=https://your-domain.com \
STACKFLARE_SOURCE_MAP_UPLOAD_KEY=xxx \
STACKFLARE_APP_ID=mobile-h5 \
STACKFLARE_APP_VERSION=1.2.3 \
STACKFLARE_SOURCEMAP_DIR=dist/assets \
npx @lhxktxwd/stackflare-browser upload-sourcemaps

CLI 会优先读取 Source Map JSON 中的 file 字段作为打包文件名;没有 file 字段时,会用 .map 文件相对 --dir 的路径去掉 .map 后缀。

如果项目已经安装了 @lhxktxwd/stackflare-browser,也可以使用包管理器执行本地 bin:

pnpm exec stackflare upload-sourcemaps

构建与发包准备

当前仓库已经补好包构建配置:

pnpm build:packages

执行后会生成:

  • packages/shared/dist
  • packages/sdk/dist

当前 SDK 已经把发布所需的共享类型内聚到了包内部,外部使用时只需要安装 @lhxktxwd/stackflare-browser

发布前可以先做一次本地打包校验:

pnpm pack:sdk

这会先构建产物,再执行 npm pack --dry-run,用于确认最终会被发布的文件是否正确。

发布流程

推荐在仓库根目录使用一键发布命令:

npm login --registry https://registry.npmjs.org/
npm whoami --registry https://registry.npmjs.org/
# 发布 beta 版本
pnpm release:sdk:beta

# 发布正式版本
pnpm release:sdk:latest

这两个命令都会先执行测试、构建包产物和 npm pack --dry-run,通过后才发布。 如果没有登录 npm,命令会在发布前直接失败并提示先登录。

如果 npm 账号开启了双因素认证,发布时需要传一次性验证码:

NPM_CONFIG_OTP=123456 pnpm release:sdk:beta
NPM_CONFIG_OTP=123456 pnpm release:sdk:latest

CI/CD 发布时需要使用 npm granular access token,并在 npm token 配置里开启 publish 所需的 2FA bypass 权限。

发布前建议确认:

  • packages/sdk/package.json 里的 nameversion 已经是你要发布的最终值
  • 你已经登录 npm:npm login
  • 当前 git 提交已经稳定,避免发布后源码和 npm 包内容对不上