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

nodebb-plugin-archcyril-r2

v1.0.10

Published

NodeBB v4.x upload provider for Cloudflare R2 (S3-compatible)

Readme

nodebb-plugin-archcyril-r2

NodeBB v4.x 插件,将上传文件存储到 Cloudflare R2(S3 兼容),支持 ACP 管理后台配置。

English | 中文

English

Features

  • Upload images and files to Cloudflare R2
  • ACP settings page for configuration
  • Automatic cleanup on post/topic purge and delete
  • Orphaned file cleanup on post edit
  • Old avatar cleanup on profile picture change
  • Multi-instance safe (shared DB snapshots with TTL)
  • Streaming uploads (no full file in memory)
  • i18n support (English, Chinese)

Installation

cd /path/to/nodebb
npm i /path/to/nodebb-plugin-archcyril-r2
./nodebb build
./nodebb restart

Enable in ACP → Extend → Plugins, then click Settings to configure R2 credentials.

Configuration

All settings are configured through the ACP settings page (ACP → Plugins → Cloudflare R2 → Settings).

| Field | Required | Default | Description | |---|---|---|---| | Access Key ID | Yes | | R2 Access Key ID | | Secret Access Key | Yes | | R2 Secret Access Key | | Bucket | Yes | | R2 Bucket name | | Endpoint | Yes | | S3 API endpoint | | Region | No | auto | Region | | Upload Path | No | | Object key prefix | | Public Host | No | | CDN/custom domain URL | | Force Path Style | No | false | Use path-style S3 addressing | | Delete on soft delete | No | false | Delete objects when posts are soft-deleted | | Delete on topic soft delete | No | false | Delete objects when topics are soft-deleted |

How It Works

Upload flow: When a user uploads an image or file, the plugin intercepts via filter:uploadImage / filter:uploadFile hooks, streams the file to R2, and returns the public URL.

Cleanup flow: When posts/topics are purged or deleted, the plugin extracts R2 object keys from post content via regex and batch-deletes them. On post edit, orphaned files (referenced before but not after) are cleaned up.

Object key format: <uploadPath>/<slugified-name>-<uuid><ext>

Testing

Unit tests (no R2 connection needed):

npm test

Integration tests (requires real R2):

export TEST_R2_ACCESS_KEY_ID="your-key-id"
export TEST_R2_SECRET_ACCESS_KEY="your-secret"
export TEST_R2_BUCKET="your-bucket"
export TEST_R2_ENDPOINT="https://<account-id>.r2.cloudflarestorage.com"
export TEST_R2_HOST="https://cdn.example.com"  # optional
npm run test:integration

Hooks

| Hook | Type | Purpose | |---|---|---| | static:app.load | static | Register ACP route | | filter:admin.header.build | filter | Add sidebar nav link | | filter:uploadImage | filter | Upload images to R2 | | filter:uploadFile | filter | Upload files to R2 | | action:posts.purge | action | Cleanup on post purge | | action:post.delete | action | Cleanup on post soft-delete | | filter:post.edit | filter | Snapshot before edit | | action:post.edit | action | Cleanup orphaned files | | action:topics.purge | action | Cleanup on topic purge | | action:topic.delete | action | Cleanup on topic soft-delete | | filter:user.updateProfile | filter | Snapshot before avatar change | | action:user.updateProfile | action | Cleanup old avatar | | action:user.removeUploadedPicture | action | Cleanup removed avatar | | action:settings.set | action | Invalidate settings cache |


中文

功能

  • 将图片和文件上传到 Cloudflare R2
  • ACP 管理后台设置页面
  • 帖子/主题删除时自动清理 R2 对象
  • 编辑帖子时清理不再引用的孤儿文件
  • 更换头像时清理旧头像文件
  • 多实例安全(共享数据库快照 + TTL)
  • 流式上传(不占用全部内存)
  • 支持中英文界面

安装

cd /path/to/nodebb
npm i /path/to/nodebb-plugin-archcyril-r2
./nodebb build
./nodebb restart

在 ACP → Extend → Plugins 中启用插件,然后点击 Settings 配置 R2 凭证。

配置

所有设置通过 ACP 管理后台配置(ACP → Plugins → Cloudflare R2 → Settings)。

| 字段 | 必填 | 默认值 | 说明 | |---|---|---|---| | Access Key ID | 是 | | R2 Access Key ID | | Secret Access Key | 是 | | R2 Secret Access Key | | Bucket | 是 | | R2 Bucket 名称 | | Endpoint | 是 | | S3 API endpoint | | Region | 否 | auto | 区域 | | Upload Path | 否 | | 对象 key 前缀 | | Public Host | 否 | | CDN/自定义域名 URL | | Force Path Style | 否 | false | 使用路径风格寻址 | | 帖子软删除时清理 | 否 | false | 帖子软删除时删除 R2 对象 | | 主题软删除时清理 | 否 | false | 主题软删除时删除 R2 对象 |

工作原理

上传流程: 用户上传图片或文件时,插件通过 filter:uploadImage / filter:uploadFile hook 拦截,将文件流式传输到 R2,返回公开访问 URL。

清理流程: 帖子/主题被删除时,插件通过正则从帖子内容中提取 R2 对象 key 并批量删除。编辑帖子时,清理编辑前引用但编辑后不再引用的孤儿文件。

对象 key 格式: <uploadPath>/<slugified-name>-<uuid><ext>

测试

单元测试(无需 R2 连接):

npm test

集成测试(需要真实 R2):

export TEST_R2_ACCESS_KEY_ID="your-key-id"
export TEST_R2_SECRET_ACCESS_KEY="your-secret"
export TEST_R2_BUCKET="your-bucket"
export TEST_R2_ENDPOINT="https://<account-id>.r2.cloudflarestorage.com"
export TEST_R2_HOST="https://cdn.example.com"  # 可选
npm run test:integration

License

MIT