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 🙏

© 2025 – Pkg Stats / Ryan Hefner

paranote

v0.1.3

Published

ParaNote: Lightweight paragraph comments service for novel and article sites

Readme

ParaNote

轻量级段落评论服务 + 通用网页阅读器。为任何网页提供沉浸式阅读体验和段落级评论互动。

npm version License: MIT GitHub

在线演示 (集成在 TapNote 中) | npm | GitHub

目录


核心特性

  • 双重模式 - 既是独立的阅读器,也是可嵌入的评论插件
  • 段落级评论 - 精确到段落的互动,支持回复、点赞和删除
  • 通用阅读模式 - 输入任意 URL,自动提取正文,生成纯净阅读页面
  • 强力抗反爬 - 内置 Puppeteer + Stealth + BrowserForge,自动处理 Cloudflare 验证
  • 模糊定位 - 采用内容指纹定位,即使原文段落增删,评论也能自动归位
  • 现代 UI - Hypothesis 风格的卡片式侧边栏,支持多彩头像和丝滑动画
  • 移动端适配 - 专为手机优化的底部抽屉交互
  • 匿名支持 - 自动生成访客身份,IP 防重复点赞
  • 用户拉黑 - 管理员可拉黑恶意用户
  • CLI 管理 - 完整的命令行工具,无需 Web 界面即可管理

快速开始

方式一:npm 全局安装 (推荐)

npm install -g paranote

# 初始化配置
paranote init

# 启动服务
paranote start

# 查看帮助
paranote help

方式二:npx 直接运行

npx paranote start --port 4000

方式三:Docker

docker run -d -p 4000:4000 -v $(pwd)/data:/app/data paranote

方式四:作为项目依赖

npm install paranote
import { startServer } from 'paranote';

// 启动服务器
await startServer({ port: 4000 });

// 或者更细粒度的控制
import { initStorage, server, config } from 'paranote';

await initStorage();
server.listen(config.port, () => {
  console.log(`Server running on port ${config.port}`);
});

CLI 命令行工具

ParaNote 提供完整的命令行工具,让你无需 Web 管理后台即可管理评论和用户。

服务器命令

# 启动服务器
paranote start [options]
  --port, -p    指定端口 (默认: 4000)
  --host        指定主机 (默认: 0.0.0.0)
  --mode, -m    部署模式: full | api | reader

# 初始化配置文件
paranote init

# 构建嵌入脚本
paranote build

# 查看版本
paranote version

数据管理

# 查看统计信息
paranote stats

# 列出评论
paranote list [options]
  --site        按站点过滤
  --work        按作品过滤
  --chapter     按章节过滤
  --limit, -n   限制数量
  --json        JSON 格式输出

# 搜索评论
paranote search <keyword> [options]
  --site        按站点过滤
  --limit, -n   限制数量
  --json        JSON 格式输出

# 删除评论
paranote delete <comment-id> [options]
  --yes, -y     跳过确认

# 导出数据
paranote export [options]
  --output, -o  输出文件路径
  --storage, -s 存储类型: file | mongo

# 导入数据
paranote import <file> [options]
  --storage, -s 存储类型: file | mongo

用户管理

# 拉黑用户
paranote ban <user-id> --site <site-id> [options]
  --reason      拉黑原因
  --yes, -y     跳过确认

# 解除拉黑
paranote unban <user-id> --site <site-id>

# 查看黑名单
paranote banlist [options]
  --site        按站点过滤
  --json        JSON 格式输出

使用示例

# 查看最新 10 条评论
paranote list --limit 10

# 搜索包含"垃圾"的评论
paranote search "垃圾" --site my-site

# 删除评论 (会显示详情并要求确认)
paranote delete abc123

# 静默删除 (用于脚本)
paranote delete abc123 -y

# 拉黑用户
paranote ban ip_abc123 --site my-site --reason "发布垃圾评论" -y

# 导出备份
paranote export -o backup.json

# 从 MongoDB 导出
paranote export -s mongo -o mongo-backup.json

# 以 JSON 格式输出 (便于管道处理)
paranote list --json | jq '.[] | .id'

使用模式

模式一:ParaNote 阅读器 (独立使用)

作为独立 Web 服务运行,提供带评论功能的纯净阅读体验。

| 功能 | URL | 说明 | |------|-----|------| | 纯净阅读 | /read?url=<URL> | 提取正文,去除广告和侧边栏 | | 原样导入 | /import?url=<URL> | 保留原始样式 | | Telegra.ph | /p/<slug> | 针对 Telegra.ph 优化 | | 管理后台 | /admin.html | 评论管理、黑名单、数据导入导出 |

油猴脚本:访问 http://localhost:4000/paranote.user.js 安装,在任意网页按 Alt+P 启用评论。

模式二:ParaNote 插件 (嵌入式使用)

为博客或小说站添加段落评论功能。

1. 标记正文

<article data-na-root data-work-id="novel_001" data-chapter-id="chapter_001">
  <p>正文第一段...</p>
  <p>正文第二段...</p>
</article>

2. 引入脚本

<script async src="https://your-server/embed.js" 
        data-site-id="my-site" 
        data-api-base="https://your-server"></script>

站长集成指南

脚本配置参数

| 属性名 | 必填 | 默认值 | 说明 | |--------|------|--------|------| | src | 是 | - | 指向 embed.js 的 URL | | data-site-id | 是 | default-site | 站点唯一标识 | | data-api-base | 否 | 自动推导 | 后端 API 地址 |

JWT 用户认证

Token 是标准 HS256 JWT,Payload 必须包含 siteIdsub

Node.js

const jwt = require('jsonwebtoken');
const token = jwt.sign({
  siteId: 'my-site',
  sub: user.id,
  name: user.username,
  avatar: user.avatarUrl,
  role: 'admin'  // 可选,管理员可删除任意评论
}, process.env.PARANOTE_SECRET);

Python

import jwt, time
token = jwt.encode({
    "siteId": "my-site",
    "sub": str(user.id),
    "name": user.username,
    "exp": int(time.time()) + 3600
}, "YOUR_SECRET", algorithm="HS256")

前端注入

<script>window.PARANOTE_TOKEN = "eyJhbGciOiJIUzI1Ni...";</script>

服务端配置

SITE_SECRETS='{"my-site":"YOUR_SECRET"}'

匿名用户

未接入用户系统时,ParaNote 自动根据 IP 生成唯一访客身份:

  • 稳定身份访客-a1b2c3 (基于 IP hash)
  • 稳定头像:同一 IP 用户拥有固定头像颜色
  • 点赞支持:匿名用户可点赞 (基于 IP 防重复)

样式定制

:root {
  --na-bg: #f7f7f7;          /* 背景色 */
  --na-card-bg: #ffffff;     /* 卡片背景 */
  --na-primary: #bd1c2b;     /* 主题色 */
  --na-text: #333333;        /* 文字颜色 */
  --na-sidebar-width: 380px; /* 侧边栏宽度 */
}

部署

环境变量

# 初始化配置
paranote init

# 或手动创建
cp .env.example .env
nano .env

| 变量 | 默认值 | 说明 | |------|--------|------| | PORT | 4000 | 服务端口 | | HOST | 0.0.0.0 | 监听地址 | | DEPLOY_MODE | full | full / api / reader | | STORAGE_TYPE | file | file / mongo | | MONGO_URI | - | MongoDB 连接串 | | ADMIN_SECRET | - | 管理员密钥 | | SITE_SECRETS | {} | JWT 密钥 (JSON 格式) | | ENABLE_PUPPETEER | true | 启用 Puppeteer 抓取 | | PUPPETEER_HEADLESS | true | 无头模式 | | RATE_LIMIT | true | 启用速率限制 | | RATE_LIMIT_MAX | 100 | 每分钟最大请求数 |

部署模式

| 模式 | 说明 | 内存占用 | |------|------|----------| | full | 首页 + 阅读器 + 所有 API | ~500MB | | api | 仅核心 API,无抓取 | <100MB | | reader | API + 阅读器,无首页 | ~500MB |

Vercel 部署 (Serverless)

ParaNote 支持部署到 Vercel Serverless Functions(仅 API 模式)。

  1. Fork 本项目到你的 GitHub
  2. 在 Vercel 中导入项目
  3. 配置环境变量:
    • STORAGE_TYPE: mongo
    • MONGO_URI: mongodb+srv://... (你的 MongoDB Atlas 连接串)
    • ADMIN_SECRET: (生成的随机密钥)
    • SITE_SECRETS: (你的 JWT 密钥 JSON)
  4. 部署即可

注意:Serverless 模式下不支持 Puppeteer 抓取功能 (/api/v1/fetch),仅提供评论服务 API。

Cloudflare Workers 部署 (V8 Edge)

ParaNote 提供完全兼容 Edge 环境的重写版本,使用 MongoDB Atlas Data API。

  1. 准备: 在 MongoDB Atlas 开启 Data API,获取 URL 和 API Key。
  2. 安装: npm install -g wrangler
  3. 配置: 修改 wrangler.toml 中的 ATLAS_API_URL 等变量。
  4. 设置密钥:
    wrangler secret put ATLAS_API_KEY
    wrangler secret put SITE_SECRETS  # 例如 {"my-site":"secret"}
    wrangler secret put ADMIN_SECRET
  5. 部署: wrangler deploy

Docker Compose (推荐)

version: '3.8'
services:
  paranote:
    build: .
    ports:
      - "4000:4000"
    volumes:
      - ./data:/app/data
    environment:
      - NODE_ENV=production
      - ADMIN_SECRET=${ADMIN_SECRET}
    restart: always
docker-compose up -d

Docker 命令行

# 完整部署
docker run -d -p 4000:4000 -v $(pwd)/data:/app/data paranote

# 低内存模式
docker run -d -p 4000:4000 -e DEPLOY_MODE=api -e ENABLE_PUPPETEER=false paranote

更新部署

git pull
docker-compose up -d --build

数据存储在 /app/data 卷中,重建容器不会丢失评论数据。


API 参考

评论 API

| 方法 | 端点 | 说明 | |------|------|------| | GET | /api/v1/comments | 获取评论 | | POST | /api/v1/comments | 发布评论 | | POST | /api/v1/comments/like | 点赞 | | DELETE | /api/v1/comments | 删除评论 |

用户管理 API

| 方法 | 端点 | 说明 | |------|------|------| | GET | /api/v1/ban | 获取黑名单 | | POST | /api/v1/ban | 拉黑用户 | | DELETE | /api/v1/ban | 解除拉黑 |

数据管理 API

| 方法 | 端点 | 说明 | |------|------|------| | GET | /api/v1/export | 导出数据 (需 x-admin-secret) | | POST | /api/v1/import | 导入数据 (需 x-admin-secret) | | GET | /api/v1/fetch | 抓取网页 |

数据迁移示例

# 使用 CLI (推荐)
paranote export -o backup.json
paranote import backup.json

# 使用 API
curl -H "x-admin-secret: $ADMIN_SECRET" http://localhost:4000/api/v1/export -o backup.json
curl -X POST -H "x-admin-secret: $ADMIN_SECRET" -H "Content-Type: application/json" \
     -d @backup.json http://localhost:4000/api/v1/import

开发

npm install           # 安装依赖
npm start             # 启动开发服务器
npm test              # 运行测试
npm run test:watch    # 监听模式
npm run test:coverage # 覆盖率报告
npm run lint          # 代码检查
npm run build:embed   # 构建压缩版 embed.js

目录结构

├── index.js           # npm 包入口
├── server.js          # 主服务入口
├── config.js          # 配置管理
├── storage.js         # 存储层抽象
├── storage-file.js    # 文件存储实现
├── storage-mongo.js   # MongoDB 存储实现
├── fetcher.js         # 网页抓取
├── browser-forge.js   # 浏览器指纹生成
├── utils.js           # 工具函数
├── bin/
│   └── paranote.js    # CLI 入口
├── routes/
│   ├── api.js         # API 路由
│   └── static.js      # 静态文件路由
├── public/
│   ├── embed.js       # 前端评论组件
│   ├── loader.js      # 自动加载器
│   ├── paranote.user.js # 油猴脚本
│   ├── index.html     # 首页
│   ├── reader.html    # 阅读器页面
│   └── admin.html     # 管理后台
└── tests/             # 测试文件 (240+ 测试用例)

技术细节

模糊定位 (Fuzzy Anchoring):保存评论时记录段落「内容指纹」(前 32 字符)。加载时如果段落索引不匹配,前端自动全篇搜索指纹,将评论纠正到正确位置。

低内存模式:设置 ENABLE_PUPPETEER=false 禁用 Chrome,内存占用 <100MB,但无法抓取 Cloudflare 保护的网站。


致谢

License

MIT