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

@stringzhao/feedback-sdk

v0.1.0

Published

通用用户反馈接入 SDK(hook 核心 + 可选预制 UI),用于接入 stringzhao 名下 base-account 反馈系统(`user.stringzhao.life`)。

Readme

@stringzhao/feedback-sdk

通用用户反馈接入 SDK(hook 核心 + 可选预制 UI),用于接入 stringzhao 名下 base-account 反馈系统(user.stringzhao.life)。

鉴权解耦:SDK 只调可配置 baseUrl(默认相对 "" 同源),鉴权完全由宿主 proxy route 注入。SDK 不内化 token / cookie,避免 CORS 与跨域 cookie 麻烦。

安装

npm install @stringzhao/feedback-sdk
# peer: react >= 19, next >= 15(可选)

1. 配置 Proxy(宿主项目,同源注入鉴权)

SDK 默认走相对路径 /api/feedback/*,宿主需提供一个同源 proxy 转发到 base-account 并注入 access_token。Next.js App Router 示例:

// app/api/feedback/[...path]/route.ts
import { cookies } from "next/headers";

const BASE_ACCOUNT_URL = process.env.BASE_ACCOUNT_URL!; // https://user.stringzhao.life

export async function POST(req: Request, { params }: { params: Promise<{ path: string[] }> }) {
  return forward(req, await params);
}
export async function GET(req: Request, { params }: { params: Promise<{ path: string[] }> }) {
  return forward(req, await params);
}

async function forward(req: Request, params: { path: string[] }) {
  const store = await cookies();
  const accessToken = store.get("access_token")?.value;
  const devToken = process.env.DEV_FEEDBACK_ACCESS_TOKEN;
  const token = accessToken ?? devToken;
  if (!token) {
    return Response.json({ error: "unauthorized" }, { status: 401 });
  }

  const url = `${BASE_ACCOUNT_URL}/api/feedback/${params.path.join("/")}${new URL(req.url).search}`;
  const headers = new Headers(req.headers);
  headers.set("Cookie", `access_token=${token}`);
  return fetch(url, { method: req.method, headers, body: req.body });
}

生产环境:access_token cookie 需跨子域(.stringzhao.life),依赖宿主 silent_reauth 持续刷新。 本地开发:cookie 不可跨域,用 DEV_FEEDBACK_ACCESS_TOKEN 兜底(从 base-account curl /dev/admin-login 取)。

2. 挂 Provider

// app/layout.tsx
import { FeedbackProvider } from "@stringzhao/feedback-sdk";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <FeedbackProvider serviceKey="my-app" baseUrl="" />
      </body>
    </html>
  );
}
  • baseUrl:默认 ""(相对同源)。SDK 不内化鉴权,由 proxy 控制。
  • serviceKey:Provider 级默认值,调用时可覆盖。

3a. 用 hook 自建 UI

"use client";
import { useFeedback } from "@stringzhao/feedback-sdk";

export function MyFeedbackButton() {
  const { submit, loading, error } = useFeedback();

  async function onClick() {
    const result = await submit({
      type: "BUG",
      description: "某按钮点击无响应",
    });
    if (result) alert("已提交,感谢反馈!");
  }

  return (
    <>
      <button onClick={onClick} disabled={loading}>反馈</button>
      {error && <p role="alert">{error.message}</p>}
    </>
  );
}

useFeedback() 返回:

| 字段 | 说明 | | --- | --- | | submit({ type, description, attachments?, serviceKey? }) | 提交反馈,成功返回 { id, status },失败返回 null(错误进 error) | | listMine() | 拉取我的反馈,填充 feedbacks | | uploadAttachment(file) | 上传单张截图(image/* ≤ 2MB),返回 { url, size } | | addMessage(feedbackId, content) | 追加消息 | | loading / error / feedbacks | 状态 | | clearError() | 清除错误态 |

容错契约:所有操作 catch 错误转入 error 态,不向调用方抛未捕获异常(网络失败 / 5xx 同样安全)。

3b. 用预制 UI(FeedbackFab)

// app/layout.tsx
import { FeedbackProvider, FeedbackFab } from "@stringzhao/feedback-sdk";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <FeedbackProvider serviceKey="my-app">
          <FeedbackFab />
        </FeedbackProvider>
      </body>
    </html>
  );
}

<FeedbackFab/> 右下悬浮 → 点击展开 <FeedbackDialog/>(类型选择 + 描述 + 截图上传 ≤4 + 提交)。 配色遵循 stringzhao.life/colors(苔绿主色 + 暖白基底 + 语义色)。

也可单独用 <FeedbackDialog open={...} onClose={...} serviceKey="..." onSuccess={(id)=>...} />

错误码

FeedbackError.code(对齐 base-account 服务端):

| code | HTTP | 含义 | | --- | --- | --- | | invalid_input | 400 | 参数不合法 | | too_many_attachments | 400 | 附件超过 4 张 | | invalid_service_key | 400 | 未注册的 serviceKey | | invalid_file_type | 400 | 非 image/* | | unauthorized | 401 | 未登录 / 登录过期 | | forbidden | 403 | 无权操作他人反馈 | | feedback_not_found | 404 | 反馈不存在 | | file_too_large | 413 | 单张 > 2MB | | rate_limited | 429 | 60s 内超 3 条 | | network_error | — | 网络失败(SDK 归类) |

API 导出

| 导出 | 说明 | | --- | --- | | useFeedback() | 核心 hook | | FeedbackProvider | Context Provider("use client") | | FeedbackFab | 右下悬浮触发 + 弹窗 | | FeedbackDialog | 反馈表单弹窗 | | createFeedbackApi(baseUrl?) | 底层 API client(进阶,绕过 React) | | FeedbackType / FeedbackStatus | 枚举 | | FeedbackView / FeedbackMessage / SubmitFeedbackInput / FeedbackError 等 | 类型 |