Fix deriveAuthLists shadowing an FK column for non-Id-suffixed reference names - #1549
Conversation
…nce names A better-auth reference field whose name doesn't end in `Id` (e.g. a plugin's `nullableReference`) derived a relation() whose own field name equaled the exact string its foreign-key column physically maps to — a self-collision the contract derivation refuses (#1236), since Prisma rc.8 aliases an include by relation name and a scalar by physical column name. Fall back to a plain scalar column in that case, mirroring the existing fallback for a reference whose target field isn't the target's `id`. Un-skips the previously-failing "should return null for nullable foreign keys" conformance test. Closes #1222 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XYJgtohJXN2UNtCfL873k
|
Deployment failed for project stack-docs with the following error: Learn More: https://vercel.com/open-saas?upgradeToPro=build-rate-limit |
🦋 Changeset detectedLatest commit: c0419a2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
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 |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
ReviewReviewed the diff ( 1. Guard condition/placement ( 2. Fallback-to-scalar path correctness — Correct on all three sub-points. The no-op-strip case falls into the same
3. Other 4. Doc/comment updates — Accurate and consistent with CLAUDE.md's comment rules. The expanded inline comment explains two external constraints (Prisma's relation-column addressing, and the contract derivation's self-collision refusal from #1236) with issue links — it doesn't restate the code, and it's the kind of "the obvious edit is wrong" warning the rules call out as earning its place. The One thing worth fixing before or shortly after merge
if (upstream.references?.field === 'id') {
throw new Error(
`deriveAuthLists: credentialFields names "${modelKey}.${fieldKey}", but "${fieldKey}" is a ` +
`relationship field (references "${upstream.references.model}.id"), not a scalar credential column`,
)
}This check's premise — "any Suggested fix — mirror the same guard used at the derivation site: if (upstream.references?.field === 'id' && relationshipFieldName(fieldKey) !== fieldKey) {This is a pre-existing check whose assumption this PR's own fix invalidates, not a bug in the new code path itself, and it doesn't affect the #1222 fix or the un-skipped test — I'd call it a should-fix-for-consistency rather than a blocker, since it only bites a narrower, currently-untested combination ( Nothing else foundNo correctness bugs, missed edge cases, or simplification opportunities beyond the above. The change is minimal, well-scoped, and correctly reuses the existing fallback path rather than introducing parallel logic. Generated by Claude Code |
buildCredentialFieldRegistry rejected any id-referencing field named in credentialFields, on the premise that it always derives to a relationship() that withCredentialAccess can't apply to. This PR's own fix (#1222) falsifies that premise for the no-op-strip case, where the field now derives to a scalar column instead — exactly the case withCredentialAccess applies to. Add the same relationshipFieldName guard so the validation matches the derivation it checks. Found in review of PR #1549. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XYJgtohJXN2UNtCfL873k
|
Thanks for the review — fixed the Generated by Claude Code |
|
The Generated by Claude Code |
Coverage Report for Core Package Coverage (./packages/core)
File CoverageNo changed files found. |
Coverage Report for UI Package Coverage (./packages/ui)
File CoverageNo changed files found. |
Coverage Report for CLI Package Coverage (./packages/cli)
File CoverageNo changed files found. |
Coverage Report for Auth Package Coverage (./packages/auth)
File Coverage
|
||||||||||||||||||||||||||||||||||||||
Coverage Report for Storage Package Coverage (./packages/storage)
File CoverageNo changed files found. |
Coverage Report for RAG Package Coverage (./packages/rag)
File CoverageNo changed files found. |
Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)
File CoverageNo changed files found. |
Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)
File CoverageNo changed files found. |
Summary
deriveAuthLists(packages/auth/src/config/derive-auth-lists.ts) derived arelationship()field for everyid-referencing better-auth column, naming the relation by stripping a trailingIdfrom the upstream field key. When the upstream key does not end inId, stripping is a no-op, so the relation's own field name ends up identical to the exact physical column name its foreign key maps onto (db.foreignKey.map) — a self-collision the contract derivation already refuses at generate time (A to-one relation and its foreign key collide on one alias, breaking nested to-one includes #1236: "rc.8 aliases an include by relation name and a scalar by physical column name, so the two would collide").Id), but a better-auth plugin schema can declare a reference field named otherwise (e.g.nullableReference), which is exactly what better-auth's ownnormalconformance suite's "should return null for nullable foreign keys" test exercises via an ad-hoc plugin schema.Idfrom the upstream field key is a no-op, fall back to deriving a plain scalar column instead of a relation — the same fallback the code already uses for a reference whose target field isn't the target'sid(issue auth: consolidate the two better-auth→list converters, and give plugin tables real foreign keys #992). This keeps the derived field's contract name identical to better-auth's own canonical field key, which is what the stack-authored Auth adapter'screate/find/updateround-trip relies on.'create - should return null for nullable foreign keys'entry inpackages/auth/tests/adapter-conformance.test.ts'sNOT_IMPLEMENTEDmap, and updated the doc comments in that file and inpackages/auth/CLAUDE.mdaccordingly.Test plan
create - should return null for nullable foreign keys(both thenormalanduuidsuite variants) now pass un-skippedauth-lists-drift.test.tsstill passespackages/authtest suite passes (511 passed, 79 skipped — the remaining skips are documented and unrelated:join/numberId/generateId/issuer-scoped-key)pnpm build,tsc --noEmit,pnpm lint,pnpm format(repo-wide) all clean@opensaas/stack-auth, patch)Closes #1222
🤖 Generated with Claude Code
https://claude.ai/code/session_019XYJgtohJXN2UNtCfL873k
Generated by Claude Code