Skip to content

feat(auth): preserve plugin/session type inference via optional plugin-tuple argument - #888

Merged
borisno2 merged 1 commit into
mainfrom
claude/funny-sagan-of4ih5
Aug 4, 2026
Merged

feat(auth): preserve plugin/session type inference via optional plugin-tuple argument#888
borisno2 merged 1 commit into
mainfrom
claude/funny-sagan-of4ih5

Conversation

@borisno2

@borisno2 borisno2 commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

  • buildBetterAuthOptions() and createAuth() now accept an optional third argument — the app's own betterAuthPlugins array, the exact same array passed to authPlugin({ betterAuthPlugins }) — so the returned options/Auth type carries the literal plugin tuple instead of the widened BetterAuthOptions / Auth<BetterAuthOptions>. This lets betterAuth() re-infer plugin-derived auth.api.* endpoints (e.g. emailOTP()'s signInEmailOTP) and a customSession() plugin's replaced session shape, which were previously erased when constructing from the widened return.
  • The supplied tuple is for typing only. It's verified against the plugin array actually resolved from authPlugin({ betterAuthPlugins }) by instance identity and order, throwing a clear, prefixed error naming the mismatch if they diverge — closing the drift hole the issue's original hand-rolled workaround left open.
  • Calling either function with no third argument is unchanged: same widened return type, same runtime options — fully backwards compatible.
  • AuthConfig['betterAuthPlugins'] / NormalizedAuthConfig['betterAuthPlugins'] are now typed as better-auth's own BetterAuthPlugin[] instead of any[], with the eslint-disable removed. Two downstream local type approximations in schema-converter.ts (modelName, type, onDelete) were widened to match better-auth's real (looser) shapes, which this type change surfaced.
  • createAuth()'s JSDoc documents an existing, unrelated limitation of its lazy Proxy: non-function properties are surfaced through async wrappers, so it doesn't behave identically to a real Auth instance — pointing typed auth.api.* reads at buildBetterAuthOptions() + betterAuth() instead.
  • Fixed a pre-existing eslint config gap: base no-redeclare doesn't understand TypeScript function overload signatures (this PR's first use of them in this repo) — switched to the overload-aware @typescript-eslint/no-redeclare and removed now-stale disable comments in packages/rag/src/runtime/embeddings.ts.
  • Updated buildBetterAuthOptions()/createAuth() JSDoc, packages/auth/CLAUDE.md, and docs/content/reference/auth.md to show the tuple-carrying form and state which entry point to reach for when reading auth.api.* in typed code.

Test plan

  • Type-level test (packages/auth/src/server/build-better-auth-options.test.ts, colocated in src/ so tsc/pnpm build gates it) constructs the builder's return type with a plugin tuple containing emailOTP() and a customSession() that replaces the session shape, asserting api.signInEmailOTP, api.sendVerificationOTP, api.checkVerificationOTP, and the customSession return type of api.getSession() are present and correctly typed
  • Same file asserts the no-argument call still typechecks and returns the widened BetterAuthOptions (back-compat)
  • Verified each type assertion is load-bearing by intentionally breaking it and confirming tsc --noEmit fails, then reverting
  • Runtime tests (packages/auth/tests/server.test.ts) cover: mismatched tuple length/order/identity throws naming the index; matching tuple succeeds; exactly one nextCookies() is appended, last, in both the argument and no-argument forms; createAuth with a plugin tuple parities with buildBetterAuthOptions for the same tuple; createAuth rejects when its tuple doesn't match
  • Existing buildBetterAuthOptions / createAuth parity test still passes
  • pnpm lint, pnpm format, pnpm manypkg fix pass repo-wide
  • packages/auth test suite passes (207 tests, 12 files) and tsc --noEmit is clean
  • Changeset added for @opensaas/stack-auth (minor)

Closes #876


🤖 Generated with Claude Code

https://claude.ai/code/session_01FiWn5P7wPEycHS4WeQYDjs


Generated by Claude Code

…Options and createAuth

buildBetterAuthOptions() and createAuth() now accept an optional plugin-tuple
argument — the same betterAuthPlugins array passed to authPlugin() — so the
returned options/Auth type carries the literal tuple instead of the widened
BetterAuthOptions/Auth<BetterAuthOptions>, letting betterAuth() re-infer
plugin endpoints (e.g. emailOTP()) and a customSession() plugin's replaced
session shape. The supplied tuple is verified against the resolved plugin
array by instance identity and order, throwing on mismatch. No-argument calls
are unchanged. Also types betterAuthPlugins as better-auth's own
BetterAuthPlugin[] instead of any[].

Fixes eslint's base no-redeclare rule flagging legitimate TS function
overloads (switches to the overload-aware @typescript-eslint/no-redeclare).

Closes #876

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FiWn5P7wPEycHS4WeQYDjs
@changeset-bot

changeset-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 455f358

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@opensaas/stack-auth Minor
@opensaas/stack-cli Minor
@opensaas/stack-core Minor
@opensaas/stack-rag Minor
@opensaas/stack-storage-s3 Minor
@opensaas/stack-storage-vercel Minor
@opensaas/stack-storage Minor
@opensaas/stack-tiptap Minor
@opensaas/stack-ui Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
stack-docs Ready Ready Preview Aug 4, 2026 10:41am

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for Core Package Coverage (./packages/core)

Status Category Percentage Covered / Total
🟢 Lines 93.32% (🎯 65%) 1231 / 1319
🟢 Statements 91.77% (🎯 65%) 1328 / 1447
🟢 Functions 98.12% (🎯 62%) 209 / 213
🟢 Branches 83.31% (🎯 50%) 894 / 1073
File CoverageNo changed files found.
Generated in workflow #1610 for commit 455f358 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for UI Package Coverage (./packages/ui)

Status Category Percentage Covered / Total
🔵 Lines 76.72% 244 / 318
🔵 Statements 76.29% 251 / 329
🔵 Functions 69.15% 74 / 107
🔵 Branches 64.25% 160 / 249
File CoverageNo changed files found.
Generated in workflow #1610 for commit 455f358 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for CLI Package Coverage (./packages/cli)

Status Category Percentage Covered / Total
🔵 Lines 79.16% 1539 / 1944
🔵 Statements 78.86% 1601 / 2030
🔵 Functions 85.94% 214 / 249
🔵 Branches 67.84% 690 / 1017
File CoverageNo changed files found.
Generated in workflow #1610 for commit 455f358 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for Auth Package Coverage (./packages/auth)

Status Category Percentage Covered / Total
🔵 Lines 98.33% 118 / 120
🔵 Statements 98.37% 121 / 123
🔵 Functions 100% 38 / 38
🔵 Branches 94.44% 85 / 90
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/auth/src/config/plugin.ts 100% 94.11% 100% 100%
packages/auth/src/config/types.ts 0% 0% 0% 0%
packages/auth/src/server/schema-converter.ts 94.28% 89.18% 100% 94.28% 171-173
Generated in workflow #1610 for commit 455f358 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for Storage Package Coverage (./packages/storage)

Status Category Percentage Covered / Total
🔵 Lines 78.57% 220 / 280
🔵 Statements 80.06% 245 / 306
🔵 Functions 86.07% 68 / 79
🔵 Branches 75.88% 214 / 282
File CoverageNo changed files found.
Generated in workflow #1610 for commit 455f358 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for RAG Package Coverage (./packages/rag)

Status Category Percentage Covered / Total
🔵 Lines 47.97% 355 / 740
🔵 Statements 48.14% 377 / 783
🔵 Functions 54.26% 70 / 129
🔵 Branches 42.55% 180 / 423
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/rag/src/runtime/embeddings.ts 100% 96.29% 100% 100%
Generated in workflow #1610 for commit 455f358 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)

Status Category Percentage Covered / Total
🔵 Lines 100% 40 / 40
🔵 Statements 100% 40 / 40
🔵 Functions 100% 9 / 9
🔵 Branches 100% 19 / 19
File CoverageNo changed files found.
Generated in workflow #1610 for commit 455f358 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)

Status Category Percentage Covered / Total
🔵 Lines 100% 68 / 68
🔵 Statements 100% 71 / 71
🔵 Functions 100% 15 / 15
🔵 Branches 97.87% 46 / 47
File CoverageNo changed files found.
Generated in workflow #1610 for commit 455f358 by the Vitest Coverage Report Action

@borisno2
borisno2 merged commit 8183827 into main Aug 4, 2026
6 checks passed
@borisno2
borisno2 deleted the claude/funny-sagan-of4ih5 branch August 4, 2026 11:07
@github-actions github-actions Bot mentioned this pull request Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

auth: buildBetterAuthOptions returns the widened BetterAuthOptions, erasing better-auth's plugin/session type inference

2 participants