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

@evumi/better-auth-berth

v0.1.2

Published

Run better-auth on Berth: libSQL / bun:sqlite databases, Berth KV secondary storage, Worker handlers and S3.

Readme

@evumi/better-auth-berth

在 Berth 上运行 better-auth:数据库用环境绑定的 libSQL 或 Worker 本地 SQLite,secondaryStorage 用项目 KV(Valkey),再提供 Worker 路由挂载和对象存储客户端。

不重新实现数据库 adapter:better-auth 自带的 SQLite(Kysely)和 Drizzle adapter 已经够用,这个包只负责把 Berth 注入的变量和能力接上去。

bun add @evumi/better-auth-berth better-auth
# 按需:
bun add drizzle-orm @libsql/client          # Drizzle(模板默认)
bun add @libsql/client @libsql/kysely-libsql # 不用 ORM,用 better-auth 内置的 Kysely

| 入口 | 内容 | 运行时 | |---|---|---| | @evumi/better-auth-berth | withBerth、berthKVStorage、toWorkerHandler、betterAuthInterceptor、resolveBerthDatabase | Node ≥ 20 / Bun(KV 需要 Bun 或自带客户端) | | /drizzle | createBerthDrizzle({ schema }) | Node / Bun | | /libsql | berthLibsqlDatabase()、createBerthLibsqlClient() | Node / Bun | | /bun | openBerthSqlite()(bun:sqlite) | Bun | | /s3 | berthS3Config()、createBerthS3()(Bun.S3Client) | 配置任意;客户端需 Bun |

用法

// src/lib/auth.ts
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { withBerth } from '@evumi/better-auth-berth';
import { createBerthDrizzle } from '@evumi/better-auth-berth/drizzle';
import * as schema from '@/db/schema';

export const db = createBerthDrizzle({ schema });

export const auth = betterAuth(withBerth({
  database: drizzleAdapter(db, { provider: 'sqlite' }),
  emailAndPassword: { enabled: true },
}));

withBerth 只补充 Berth 相关的配置,options 里已经写了的值优先,session、rateLimit、advanced 合并一层:

| 字段 | 值 | |---|---| | baseURL | BETTER_AUTH_URL,否则 BERTH_PUBLIC_URL | | trustedOrigins | baseURL 的 origin | | secondaryStorage | 项目开了 kv 时用 Berth KV(BERTH_KV_URL、BERTH_KV_PREFIX);没开就不设 | | session.storeSessionInDatabase | 有 KV 时为 true。项目 KV 默认 64 MB 且 noeviction,写满会报错;session 同时存数据库,KV 满了或被清空都不会让用户掉线 | | rateLimit.storage | 有 KV 时 secondary-storage,否则 database | | advanced.ipAddress.trustedProxies | 传了 trustedProxies 才设置 |

第二个参数:{ env?, kv?: false | { url, prefix, namespace, client }, trustedProxies? }。KV 键是 BERTH_KV_PREFIX + namespace + key,namespace 默认 auth:。

数据库怎么选

resolveBerthDatabase() 的顺序:

  1. 有 LIBSQL_URL:libSQL(LIBSQL_AUTH_TOKEN 可选)。URL 原样使用:Berth 托管的 sqld 注入的是 http://;Turso 之类的 libsql:// 需要 TLS,不能改写。
  2. BERTH_WORKER_DATABASE=libsql 但没有 URL:报错,不会悄悄退回本地文件。
  3. 否则是本地 SQLite:BERTH_SQLITE_PATH(Worker 是卷上的 /data/worker.sqlite),再否则 ./berth.sqlite。

三种接法:

// Drizzle:业务表和 auth 表共用一个客户端,迁移用 drizzle-kit
drizzleAdapter(createBerthDrizzle({ schema }), { provider: 'sqlite' })

// Kysely:可以用 `npx @better-auth/cli migrate` 或 getMigrations()
import { berthLibsqlDatabase } from '@evumi/better-auth-berth/libsql';
betterAuth(withBerth({ database: berthLibsqlDatabase() }))

// inline Worker 的本地 SQLite(WAL、synchronous=FULL、busy_timeout 5s)
import { openBerthSqlite } from '@evumi/better-auth-berth/bun';
betterAuth(withBerth({ database: openBerthSqlite() }))

libSQL 的 interactive transaction 每次占一条 Hrana stream,事务里不要调用外部 API。

挂载

TanStack Start(Worker 全栈模式或普通服务):

// src/routes/api/auth/$.ts
import { createFileRoute } from '@tanstack/react-router';
import { auth } from '@/lib/auth';

export const Route = createFileRoute('/api/auth/$')({
  server: { handlers: { GET: ({ request }) => auth.handler(request), POST: ({ request }) => auth.handler(request) } },
});

inline Worker:文件路由目前没有 catch-all,用拦截器挂载。所有请求(包括 404)都会经过它:

// __interceptor__.ts
import { betterAuthInterceptor } from '@evumi/better-auth-berth';
import { auth } from '@/lib/auth';

export default betterAuthInterceptor(auth, { basePath: '/api/auth' });

已经有拦截器时,在自己的函数里先调用它:return authInterceptor(ctx, next)。平台以后支持 catch-all 路由时,也可以写 export const GET = toWorkerHandler(auth)。

KV

berthKVStorage() 用 Bun 内置的 RedisClient,连接只在第一次使用时建立。不在 Bun 上时,传入任何带 send(command, args) 的客户端:

import Redis from 'ioredis';
const redis = new Redis(process.env.BERTH_KV_URL!);
berthKVStorage({ client: { send: (cmd, args) => redis.call(cmd, ...args) } });

| 方法 | 命令 | |---|---| | get / delete | GET / DEL | | set(k, v, ttl) | SET k v EX ttl | | getAndDelete | GETDEL | | increment(k, ttl) | SET k 0 EX ttl NX → INCR → EXPIRE k ttl NX |

increment 不用 MULTI:Bun 的客户端在一条连接上 pipeline 所有请求,事务可能和其他请求的命令交错。三条命令各自原子;TTL 只在创建时设置(better-auth 要求的固定窗口),EXPIRE NX 补上「键在两条命令之间过期」的情况。CI 在 Berth 的环境 ACL 下实测这些命令。

Worker 关闭时释放连接:

export async function onStop() { (auth.options.secondaryStorage as BerthKVStorage | undefined)?.close(); }

客户端 IP

better-auth 默认只信任单值的 x-forwarded-for。如果前面有多层代理,用 trustedProxies 写上代理的地址,better-auth 会从右往左跳过它们取客户端 IP。不要填覆盖客户端的大网段。

对象存储

import { createBerthS3 } from '@evumi/better-auth-berth/s3';
const s3 = createBerthS3(); // BERTH_S3_*,path-style
await s3.write('avatars/1.png', bytes, { type: 'image/png' });
const url = s3.presign('avatars/1.png', { expiresIn: 3600 });

其他 SDK 用 berthS3Config() 拿配置。这些都是服务端凭据,浏览器只拿预签名 URL。

开发

bun install
bun run typecheck
bun test        # 单元测试 + 本地 SQLite / libSQL 文件的端到端测试
bun run build

BERTH_TEST_KV_URL(加 BERTH_TEST_KV_PREFIX)和 BERTH_TEST_LIBSQL_URL 设置后,会额外跑真实 Valkey 和 sqld 的测试。CI 用的是 Berth 部署的同版本镜像,见 .github/workflows/ci.yml。

发布

改 package.json 的 version,合并后打同名 tag:

git tag v0.1.0 && git push origin v0.1.0

release.yml 校验 tag、跑测试并 npm publish。版本号带 -(如 0.2.0-beta.1)时发到 next dist-tag。需要仓库 secret NPM_TOKEN。

License

MIT