better-auth Kysely Adapter 深度解析:从运行时 Schema 校验到原生事务与原子计数

发布时间:2026/9/10 16:47:48
better-auth Kysely Adapter 深度解析:从运行时 Schema 校验到原生事务与原子计数 better-auth Kysely Adapter 深度解析从运行时 Schema 校验到原生事务与原子计数【免费下载链接】better-authThe most comprehensive authentication framework项目地址: https://gitcode.com/GitHub_Trending/be/better-auth本篇技术指南以better-auth/kysely-adapter的 CHANGELOG 为骨架结合仓库源码与测试系统讲解该适配器的快速接入方式、各版本引入的核心能力运行时 Schema 校验、原生事务、原子计数器、fail-closed 更新语义、大小写不敏感查询及其底层实现原理。读完本文你将掌握该适配器在 Better Auth 项目中的正确配置方法并理解每个关键行为背后的源码机制便于在升级或排障时做出准确判断。一、适配器概览Better Auth 与 Kysely 之间的桥梁better-auth/kysely-adapter是 Better Auth 官方维护的数据库适配器之一位于仓库 packages/kysely-adapter。它基于 Kysely 这一类型安全的 TypeScript SQL 查询构建器实现让 Better Auth 可以接入 PostgreSQL、MySQL、SQLite含 better-sqlite3、node:sqlite、bun:sqlite、MSSQL 以及 Cloudflare D1 等多种数据库。从 package.json 可以看到包名better-auth/kysely-adapter当前版本1.7.3type: moduleESM提供两个导出入口主入口.与独立的./node-sqlite-dialect对应 node-sqlite-dialect.tsnode:sqlite尚未视为生产就绪因此默认不随主入口导出kysely被声明为可选的 peer dependency这意味着安装时若版本不匹配只会告警而不会硬失败这一设计在 1.7.0-beta.2 / 1.6.4 中用于收窄 peer 范围。二、快速接入安装与基础配置安装命令npm install better-auth/kysely-adapter在 Better Auth 配置中可以直接把原生的数据库实例传给database字段适配器会自动完成方言探测与封装。以下以 PostgreSQL 为例见 docs/content/docs/adapters/postgresql.mdximport { betterAuth } from better-auth; import { Pool } from pg; export const auth betterAuth({ database: new Pool({ connectionString: postgres://user:passwordlocalhost:5432/database, }), });如需显式控制方言类型、调试日志、复数表名与事务开关可以显式传入 Kysely 实例并携带配置import { betterAuth } from better-auth; import { kyselyAdapter } from better-auth/kysely-adapter; import { Kysely, PostgresDialect } from kysely; import { Pool } from pg; const db new Kyselyany({ dialect: new PostgresDialect({ pool: new Pool({ connectionString: postgres://... }), }), }); export const auth betterAuth({ database: kyselyAdapter(db, { type: postgres, // postgres | mysql | sqlite | mssql debugLogs: false, // 是否打印调试日志默认 false usePlural: false, // 是否使用复数表名默认 false transaction: false, // 是否以事务执行多步操作默认 false }), });方言自动探测从裸实例到 Kysely Dialect从源码 dialect.ts 可以看到createKyselyAdapter支持四种配置形态并会对裸数据库实例做鸭子类型探测显式{ db }或{ dialect }形态直接使用提供的实例或包装为Kysely裸实例形态快速开始写法database: new Database(...)通过getKyselyDatabaseType逐项探测——aggregate in db判定 better-sqlite3getConnection判定 mysql2connect判定 pg PoolfileControl判定 bun:sqlitecreateSession判定node:sqlitebatch in db exec in db prepare in db判定 Cloudflare D1。同时探测结果还会记录该数据库是否支持原生事务better-sqlite3、mysql2、pg、bun:sqlite、node:sqlite 均被标记为transaction true唯独 Cloudflare D1 被标记为false原因是 D1 没有交互式事务interactive transaction只有batch()API——这一点在 1.7.0 的变更说明中被再次确认。三、运行时 Schema 校验1.7.3上线前拦住表结构错误变更内容1.7.3 引入了此前版本不具备的运行时数据库结构校验适配器初始化时会通过 Kysely 的 introspection 读取线上数据库的真实表结构与 Better Auth 配置含插件期望写入的表、列进行比对报告三类问题缺失的表missing tables缺失的列missing columnsBetter Auth 永远不会写入但又是必需列的列required columns Better Auth never writes并附带修复指引。实现原理这一能力的核心实现在 schema-check.tstoIntrospectedTables将 Kysely 的TableMetadata转换为diffSchema可比对的IntrospectedTable[]表名、schema、列名、可空性、是否有默认值/自增toPhysicalSchema把期望 Schema 转换为连接实际发送的标识符形态——如果用户启用了诸如CamelCasePlugin这样的标识符改写插件期望侧的列名会通过sentIdentifiers编译一条 SELECT 查询读取改写后的真实标识符从而保证比对的是数据库真正被问到的名字而不是 Better Auth 内部的名字findSchemaProblems在单条连接上执行 introspectiondb.connection().execute对 PostgreSQL 通过pg_catalog.current_schemas(true)获取有效 search path对 MSSQL 通过SCHEMA_NAME()获取当前 schema默认dbo避免把 schema 限定错误当成结构缺失最终调用diffSchema(physical, tables)产出差异列表。适配器在 kysely-adapter.ts 中通过checksSchema(options)判定后用registerSchemaCheckcreateSchemaCheck注册该校验器。配置与行为影响默认开启包括生产环境可通过advanced.database.validateSchema: false关闭运行时校验认证请求会等待同一校验若线上 schema 与期望不匹配请求将被拒绝——这意味着结构错误会以显式失败暴露而不是在运行中悄悄出错auth migrate在存在需要手工修复的必需未写列时拒绝应用变更强制开发者先手工补齐再迁移。测试见 schema-check.test.ts其中toPhysicalSchema在无插件改写时保持原样、在CamelCasePlugin下正确改写标识符等用例验证了这套比对的正确性。四、原生事务支持1.7.0解锁 SCIM 等事务依赖插件变更内容1.7.0 之前快速开始形态database: new Database(...)裸数据库实例不会被自动套上原生事务只有显式{ db }/{ dialect }形态才具备。1.7.0 起直接传入以下裸实例都会自动获得原生适配器事务better-sqlite3node:sqlitebun:sqlitemysql2pg这解锁了依赖原生事务的插件如better-auth/scim在快速开始配置形态下的正常使用。唯一例外仍是 Cloudflare D1无交互式事务。实现细节在 dialect.ts 中每个裸实例被探测后都会自动包装为对应 Kysely DialectSqliteDialect、MysqlDialect、PostgresDialect、BunSqliteDialect、NodeSqliteDialect、D1SqliteDialect并同步标记transaction支持情况在 kysely-adapter.ts 中当配置开启transaction: true时适配器通过db.transaction().execute(...)在事务内重建 adapter factory并将transaction: false透传给内部实现以避免递归从而让create/update/delete等写操作在同一事务中完成。五、原子计数器 incrementOne1.6.17限流与 API Key 计数的正确姿势变更内容1.6.17 让 memory、Kysely、Drizzle、Prisma、MongoDB 五个适配器的计数器更新用于速率限制和API-key 用量上限在默认配置未开启事务下即是原子的每个适配器以单条语句原生实现incrementOne。源码验证从 kysely-adapter.ts 看实现增量字段被编译为自引用赋值field field delta通过sql模板与sql.ref算术由数据库而非应用完成天然原子绝对值set赋值在同一条语句中一并应用单行语义通过id IN (SELECT id WHERE guard LIMIT 1)子查询限定——防止 guard 非唯一时一次更新多行SQL Server 无LIMIT改用top(1)子查询MySQL 因不支持UPDATE ... RETURNING走SELECT ... FOR UPDATE加锁后在同一事务内更新再回读并发竞争者会阻塞在行锁上锁释放后若 guard 已失效则观察到 0 行更新并返回null。测试 increment-one.test.ts 使用真实的node:sqlite内存库验证了三个关键点increment: { remaining: -1, used: 1 }原子生效返回更新后的行remaining2、used1原生路径只发出一条自引用 UPDATE 且带 RETURNING没有任何先 SELECT 后 UPDATE 的兜底对测试断言executedSql中无select前缀语句增量与绝对值set: { status: closed }可同语句混用且 guard 匹配多行时只改动一行。同版本还修复了 SQLite 驱动的写语义Bun 与 Node 驱动的变更现在会正确报告受影响行数与插入行 id此前写入被误报为影响 0 行Bun 驱动修正了多查询参数的绑定问题consumeOne在无LIMIT子句的 SQL Server 上改为可用实现。六、fail-closed 更新语义1.6.21更新未命中返回 null 而非异常变更内容1.6.21 统一了各适配器受守卫更新未命中的行为adapter.update在没有行匹配或未携带谓词时返回null此前 MySQL 适配器可能在守卫更新未命中后仍返回某行带id守卫的更新即使id不是第一个谓词也能正确返回目标行Prisma 适配器同步收敛为返回null而非抛出 not-found 异常共享适配器测试套件对全部适配器断言同样的 fail-closed 行为。源码佐证在 kysely-adapter.ts 中update对空where直接返回null避免编译成无谓词的UPDATE table SET ...误改全表并明确指引有意的批量更新请使用updateMany。MySQL 分支withReturning见 kysely-adapter.ts先执行 UPDATE 再检查numUpdatedRows为 0 则返回null重查插入/更新行时优先使用values.id其次id等值守卫再次首个谓词字段最后才走唯一列查找与全字段匹配兜底。其中行数判定依赖rows matched 语义MySQL 下该适配器依赖驱动返回UPDATE/DELETE的匹配行数mysql2 的affectedRowsKysely 暴露为numUpdatedRows。mysql2 默认通过CLIENT_FOUND_ROWS标志启用该语义请勿禁用——若在连接池配置中移除例如flags: -FOUND_ROWS幂等更新新值等于旧值会被报告为 0 行导致update/incrementOne/updateMany即使命中谓词也返回null或0。该警告同时记录在 kysely-adapter.ts 的配置 JSDoc 中。七、大小写不敏感查询1.6.0统一跨方言的insensitive模式变更内容1.6.0 为数据库适配器新增大小写不敏感查询支持Minor Change并顺带移除了 D1 方言中已废弃的numUpdatedOrDeletedRows。源码验证实现在 query-builders.ts并已接入 kysely-adapter.ts 的convertWhereClause——当查询条件mode: insensitive且值为字符串或全字符串数组时PostgreSQLeq/ne走LOWER(col) LOWER(?)contains/starts_with/ends_with走ILIKEMySQL / SQLite / MSSQL统一用LOWER(col) LIKE LOWER(pattern)IN/NOT IN则对左侧列与右侧值同时LOWER大小写敏感模式默认行为不变。由此mode: insensitive的语义在五种方言上保持一致不再需要开发者自行拼LOWER()。八、方言兼容性修复与依赖收窄D1、SQLite 与 peer 版本1.7.2修复 Cloudflare D1 的程序化迁移1.7.2 修复了程序化迁移programmatic migrations在 Cloudflare D1 上失败的问题同时保留了对各受支持数据库的既有索引校验。D1 相关方言实现在 d1-sqlite-dialect.ts并配套createD1IndexIntrospector见 dialect.ts提供DatabaseIndexIntrospector接口见 types.ts用于以数据库无关的方式读取索引元数据是否唯一、是否 partial、列前缀长度等。1.7.0 PatchSQLite 方言与 Kysely 0.29 的兼容1.7.0 Patch 修复了与Kysely 0.29配合时 SQLite dialect bundle 的编译问题采用本地镜像迁移表常量见 kysely-migration-tables.ts的方式不再依赖 Kysely 内部未导出的常量。1.6.4 / 1.7.0-beta.2peer 版本收窄这两个版本把kyselypeer 依赖收窄为^0.28.14该范围锚定携带漏洞修复的 minor 版本线且不越级确保适配器只对实际测试过的版本声明支持旧版本使用者会在安装期看到警告可随适配器一并升级。peer 被标记为 optional见 package.json因此不会硬性阻断安装。九、版本演进速览版本类型核心内容1.7.3Patch运行时 Schema 校验缺失表/列/必需列 修复指引默认开启含生产环境advanced.database.validateSchema: false可关闭认证请求等待校验、不匹配即拒绝auth migrate在需手工修复时拒绝执行1.7.2Patch修复 Cloudflare D1 程序化迁移失败保留既有索引校验1.7.0Minor裸数据库实例better-sqlite3、node:sqlite、bun:sqlite、mysql2、pg自动获得原生事务解锁依赖事务的插件如better-auth/scimD1 仍无原生事务1.7.0Patch修复 Kysely 0.29 下 SQLite dialect bundle本地镜像迁移表常量1.6.21Patchadapter.update未命中/无谓词返回nullMySQL 守卫更新未命中不再返回行id非首谓词也能定位共享测试断言 fail-closed 语义1.6.17Patch默认配置下incrementOne原子化单条自引用 UPDATESQLiteBun/Node写操作正确报告影响行数与插入 idconsumeOne适配 SQL Server1.6.0Minor新增大小写不敏感查询支持移除 D1 方言废弃的numUpdatedOrDeletedRows1.6.4 / 1.7.0-beta.2Patchkyselypeer 收窄至^0.28.14漏洞修复线optional 不硬失败十、小结如何用好这套适配器新项目快速开始直接传原生数据库实例即可适配器会探测方言并自动启用原生事务D1 除外生产上线前保持默认开启的运行时 Schema 校验配合npx authlatest generate/npx authlatest migratePostgreSQL/MySQL 等均支持生成与迁移见 docs/content/docs/adapters/postgresql.mdx提前暴露表结构问题仅在确认需要时用advanced.database.validateSchema: false关闭涉及限流、API Key 用量放心使用默认配置下的incrementOne它是单语句原子的MySQL 用户切勿在连接池中关闭FOUND_ROWS否则幂等更新会被误判为未命中升级注意adapter.update的 fail-closed 语义、peer 版本收窄都属于行为变化升级 1.6.21 / 1.6.4 及以上版本时请回归测试所有写路径需要单行更新时使用update需要批量更新时显式使用updateMany避免无谓词更新被静默拒绝。以上各能力均有仓库源码与测试支撑可进一步阅读 kysely-adapter.ts、dialect.ts、schema-check.ts、query-builders.ts 以及 increment-one.test.ts、schema-check.test.ts 等测试文件深入验证。【免费下载链接】better-authThe most comprehensive authentication framework项目地址: https://gitcode.com/GitHub_Trending/be/better-auth创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考