[PR #8824] fix(types): preserve plugin endpoint types on server-side auth.api #25138

Open
opened 2026-04-15 22:44:15 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/8824
Author: @jmalmo
Created: 3/29/2026
Status: 🔄 Open

Base: mainHead: fix/preserve-plugin-endpoint-types


📝 Commits (3)

  • 62edc96 fix(types): preserve plugin endpoint types on server-side auth.api
  • a6ded3d fix(types): cover remaining readonly-sensitive plugin type consumers
  • e05c334 fix(types): strengthen $context type test assertions

📊 Changes

9 files changed (+126 additions, -38 deletions)

View changed files

📝 packages/better-auth/src/api/index.ts (+1 -1)
📝 packages/better-auth/src/auth/full.ts (+1 -1)
📝 packages/better-auth/src/auth/minimal.ts (+1 -1)
📝 packages/better-auth/src/types/models.ts (+10 -9)
📝 packages/better-auth/src/types/plugins.ts (+7 -6)
📝 packages/better-auth/src/types/types.test.ts (+87 -1)
📝 packages/core/src/db/type.ts (+4 -4)
📝 packages/core/src/types/context.ts (+14 -14)
📝 packages/core/src/types/init-options.ts (+1 -1)

📄 Description

Summary

Fixes server-side auth.api losing plugin-contributed endpoint types (e.g., createUser, removeUser from admin()) when betterAuth() is used in a lazy singleton / factory pattern.

Root cause: All plugin type extraction utilities use Array<infer T> which silently fails on ReadonlyArray. Combined with no const generic on betterAuth(), TypeScript can widen the plugin tuple and erase endpoint types.

Changes:

  • Accept readonly BetterAuthPlugin[] in BetterAuthOptions.plugins
  • Handle ReadonlyArray<infer T> in all server-side plugin type extraction:
    • PluginEndpoint (in getEndpoints)
    • InferPluginTypes, InferPluginErrorCodes, InferPluginIDs, InferPluginContext
    • InferDBFieldsFromPluginsInput, InferDBFieldsFromPlugins (also updated tuple destructuring to readonly [infer P, ...infer Rest])
    • InferPluginID, InferPluginOptions (in context.ts — fixes hasPlugin/getPlugin inference)
  • Add const type parameter to betterAuth() (full + minimal) for narrower inference
  • Add type regression tests: lazy singleton, mixed plugins, as const readonly, and $context hasPlugin/getPlugin

Files changed (9):

  • packages/core/src/types/init-options.ts — accept readonly plugins
  • packages/core/src/types/context.tsReadonlyArray in InferPluginID + InferPluginOptions
  • packages/core/src/db/type.ts — readonly constraint + tuple destructuring in InferDBFieldsFromPlugins*
  • packages/better-auth/src/auth/full.tsconst generic
  • packages/better-auth/src/auth/minimal.tsconst generic
  • packages/better-auth/src/api/index.tsReadonlyArray in PluginEndpoint
  • packages/better-auth/src/types/models.tsReadonlyArray in InferPluginTypes
  • packages/better-auth/src/types/plugins.tsReadonlyArray in 3 utility types
  • packages/better-auth/src/types/types.test.ts — 4 type regression tests

Known limitations:

  • satisfies BetterAuthOptions pattern: If options are contextually typed via satisfies before reaching betterAuth(), plugins may already be widened to BetterAuthPlugin[]. The const generic cannot recover types that were already erased. Inline options or as const work correctly.
  • Client-side consumers: client/types.ts and client/plugins/infer-plugin.ts also use Array<infer P>. Those are left out of scope for this server-side fix. Happy to expand or open a follow-up PR for #7043.
  • TS version: The const type parameter requires TypeScript 5.0+. The repo uses TS ^5.9.3. If Better Auth needs to support TS 4.x consumers, this would need a different approach.

Fixes #8823
Refs #3015


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/8824 **Author:** [@jmalmo](https://github.com/jmalmo) **Created:** 3/29/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `fix/preserve-plugin-endpoint-types` --- ### 📝 Commits (3) - [`62edc96`](https://github.com/better-auth/better-auth/commit/62edc9628a933bc89ff3cc229a372b6bdf1dc92e) fix(types): preserve plugin endpoint types on server-side auth.api - [`a6ded3d`](https://github.com/better-auth/better-auth/commit/a6ded3d9d4868c03e6f5af13f2f2c019ae7d5dcd) fix(types): cover remaining readonly-sensitive plugin type consumers - [`e05c334`](https://github.com/better-auth/better-auth/commit/e05c33450e7317d5cfd5523a8137d19195088ed9) fix(types): strengthen $context type test assertions ### 📊 Changes **9 files changed** (+126 additions, -38 deletions) <details> <summary>View changed files</summary> 📝 `packages/better-auth/src/api/index.ts` (+1 -1) 📝 `packages/better-auth/src/auth/full.ts` (+1 -1) 📝 `packages/better-auth/src/auth/minimal.ts` (+1 -1) 📝 `packages/better-auth/src/types/models.ts` (+10 -9) 📝 `packages/better-auth/src/types/plugins.ts` (+7 -6) 📝 `packages/better-auth/src/types/types.test.ts` (+87 -1) 📝 `packages/core/src/db/type.ts` (+4 -4) 📝 `packages/core/src/types/context.ts` (+14 -14) 📝 `packages/core/src/types/init-options.ts` (+1 -1) </details> ### 📄 Description ## Summary Fixes server-side `auth.api` losing plugin-contributed endpoint types (e.g., `createUser`, `removeUser` from `admin()`) when `betterAuth()` is used in a lazy singleton / factory pattern. **Root cause:** All plugin type extraction utilities use `Array<infer T>` which silently fails on `ReadonlyArray`. Combined with no `const` generic on `betterAuth()`, TypeScript can widen the plugin tuple and erase endpoint types. **Changes:** - Accept `readonly BetterAuthPlugin[]` in `BetterAuthOptions.plugins` - Handle `ReadonlyArray<infer T>` in all server-side plugin type extraction: - `PluginEndpoint` (in `getEndpoints`) - `InferPluginTypes`, `InferPluginErrorCodes`, `InferPluginIDs`, `InferPluginContext` - `InferDBFieldsFromPluginsInput`, `InferDBFieldsFromPlugins` (also updated tuple destructuring to `readonly [infer P, ...infer Rest]`) - `InferPluginID`, `InferPluginOptions` (in `context.ts` — fixes `hasPlugin`/`getPlugin` inference) - Add `const` type parameter to `betterAuth()` (full + minimal) for narrower inference - Add type regression tests: lazy singleton, mixed plugins, `as const` readonly, and `$context` hasPlugin/getPlugin **Files changed (9):** - `packages/core/src/types/init-options.ts` — accept readonly plugins - `packages/core/src/types/context.ts` — `ReadonlyArray` in `InferPluginID` + `InferPluginOptions` - `packages/core/src/db/type.ts` — readonly constraint + tuple destructuring in `InferDBFieldsFromPlugins*` - `packages/better-auth/src/auth/full.ts` — `const` generic - `packages/better-auth/src/auth/minimal.ts` — `const` generic - `packages/better-auth/src/api/index.ts` — `ReadonlyArray` in `PluginEndpoint` - `packages/better-auth/src/types/models.ts` — `ReadonlyArray` in `InferPluginTypes` - `packages/better-auth/src/types/plugins.ts` — `ReadonlyArray` in 3 utility types - `packages/better-auth/src/types/types.test.ts` — 4 type regression tests **Known limitations:** - **`satisfies BetterAuthOptions` pattern:** If options are contextually typed via `satisfies` before reaching `betterAuth()`, plugins may already be widened to `BetterAuthPlugin[]`. The `const` generic cannot recover types that were already erased. Inline options or `as const` work correctly. - **Client-side consumers:** `client/types.ts` and `client/plugins/infer-plugin.ts` also use `Array<infer P>`. Those are left out of scope for this server-side fix. Happy to expand or open a follow-up PR for #7043. - **TS version:** The `const` type parameter requires TypeScript 5.0+. The repo uses TS ^5.9.3. If Better Auth needs to support TS 4.x consumers, this would need a different approach. Fixes #8823 Refs #3015 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-15 22:44:15 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#25138