Fix authPlugin's uuid7 id pin: config, not a hardcoded constant - #1550
Conversation
…ide it
authPlugin hardcoded db.idField: 'uuid7' on every Auth list it injects, with
no escape hatch, so an app-level db.idField default (e.g. cuid2, to adopt a
live better-auth install with text ids) never reached the Auth lists. The
extendList branch also never applied the pin, so an app-declared list could
silently disagree with the adapter's hardcoded supportsUUIDs/supportsNumericIds.
authPlugin now resolves idField from an explicit authPlugin({ idField }),
else the app's own db.idField default, else 'uuid7' — refusing a resolution
of 'int autoincrement' (the Auth adapter treats every id as a string) and
throwing when an app-declared list's own idField disagrees with the Auth
lists' resolved strategy. The adapter's supportsUUIDs/supportsNumericIds are
now derived from that resolved strategy instead of hardcoded.
Closes #1239
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01218dPJQasRpbcWL9w9fiZ8
|
Deployment failed for project stack-docs with the following error: Learn More: https://vercel.com/open-saas?upgradeToPro=build-rate-limit |
🦋 Changeset detectedLatest commit: dd57cf8 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. |
|
The That's the org's Vercel free-tier daily deployment quota being exhausted, not anything in this diff — this PR touches no docs content, and the failure names a resource limit rather than a build error. Nothing here for this PR to fix; it should clear on its own once the daily quota resets (or if/when the project moves to a paid plan). The real CI checks ( Generated by Claude Code |
borisno2
left a comment
There was a problem hiding this comment.
Single-pass review (no Agent-tool fan-out / subagent verify pass) of PR #1550 (959b078).
Worked through the diff line-by-line, traced resolveAuthIdField/authIdCapabilities against resolveIdStrategy/listIdColumn in core, checked the extendList id-agreement refusal against every fallback combination (explicit authPlugin({idField}), app-wide default, per-list override, singleton, int autoincrement), read the ADR-0048/0060 amendments and the new ADR-0070, and built+ran the full packages/auth suite (518 passed, 81 pre-existing skips) plus the three directly-relevant test files to confirm no regression.
No correctness bugs found — the id-resolution logic, the addList/extendList agreement check, and the derived supportsUUIDs/supportsNumericIds are internally consistent and well covered by the new tests. Left two low-severity notes inline (a reuse/drift-risk observation and a minor error-message attribution nit); neither blocks the change.
Generated by Claude Code
Review: #1550 — authPlugin's id strategy resolution (fixes #1239)I cloned the PR branch, read the full diff, and traced the resolution logic against 1.
|
Cross-reference resolveIdStrategy in the reimplemented fallback chain, and soften the extendList mismatch error to not assume the application (rather than an earlier-running plugin) declared the conflicting list. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01218dPJQasRpbcWL9w9fiZ8
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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. |
…llision 0070-the-auth-plugins-id-strategy-is-config-not-a-hardcoded-pin.md (#1550) and 0070-the-generated-clients-identity-is-a-process-wide-registry-entry.md (#1548) landed within a minute of each other and both claimed 0070, tripping check:adr-duplicates on every PR against main. Renumbered the id-strategy ADR to 0071 (2 filename-link updates in ADR-0048 and ADR-0060) rather than the client-identity one, which has 7+ scattered bare "(ADR-0070)" comment references across packages/core, packages/cli and packages/auth that would otherwise need updating instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HEEWCWcKXFFYY3PXE2zBH6
…llision 0070-the-auth-plugins-id-strategy-is-config-not-a-hardcoded-pin.md (#1550) and 0070-the-generated-clients-identity-is-a-process-wide-registry-entry.md (#1548) landed within a minute of each other and both claimed 0070, tripping check:adr-duplicates on every PR against main. Renumbered the id-strategy ADR to 0071 (2 filename-link updates in ADR-0048 and ADR-0060) rather than the client-identity one, which has 7+ scattered bare "(ADR-0070)" comment references across packages/core, packages/cli and packages/auth that would otherwise need updating instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HEEWCWcKXFFYY3PXE2zBH6
…llision (#1555) 0070-the-auth-plugins-id-strategy-is-config-not-a-hardcoded-pin.md (#1550) and 0070-the-generated-clients-identity-is-a-process-wide-registry-entry.md (#1548) landed within a minute of each other and both claimed 0070, tripping check:adr-duplicates on every PR against main. Renumbered the id-strategy ADR to 0071 (2 filename-link updates in ADR-0048 and ADR-0060) rather than the client-identity one, which has 7+ scattered bare "(ADR-0070)" comment references across packages/core, packages/cli and packages/auth that would otherwise need updating instead. Claude-Session: https://claude.ai/code/session_01HEEWCWcKXFFYY3PXE2zBH6 Co-authored-by: Claude <noreply@anthropic.com>
* Fix read-restricted embedding fields re-embedding on every write (#1282) The generation hook's regeneration skip read the stored hash off the write's own Field-Visibility-filtered `item`, which strips a field the session cannot read. For a read-restricted embedding() field this hash always read back undefined, so every later write regenerated the embedding regardless of whether the source text changed. Adds readPluginOwnedRow to @opensaas/stack-core/extend — the read-side twin of writePluginOwnedField (ADR-0068) — so the RAG plugin can read the row's real, persisted columns for the regeneration check instead of the caller's projection of it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGrzpcxbUT9PCsvDRbTpgi * docs(adr): renumber the auth idField ADR to 0071 to resolve a 0070 collision 0070-the-auth-plugins-id-strategy-is-config-not-a-hardcoded-pin.md (#1550) and 0070-the-generated-clients-identity-is-a-process-wide-registry-entry.md (#1548) landed within a minute of each other and both claimed 0070, tripping check:adr-duplicates on every PR against main. Renumbered the id-strategy ADR to 0071 (2 filename-link updates in ADR-0048 and ADR-0060) rather than the client-identity one, which has 7+ scattered bare "(ADR-0070)" comment references across packages/core, packages/cli and packages/auth that would otherwise need updating instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HEEWCWcKXFFYY3PXE2zBH6 * Address review: classify the read refusal, fix the read-doc comment - generation-failure.ts: HandlelessPluginFieldReadError was missing from the refused-access classification set, so the wiring defect it names would have mis-reported as a per-row transient failure instead of the deduplicated standing-defect message its write-side twin gets. Renamed REFUSED_WRITE_ERRORS/isRefusedWrite to REFUSED_ACCESS_ERRORS/isRefusedAccess now that it covers both sides. - plugin.ts: readForRegenerationCheck's comment claimed it reads only the metadata column; readPluginOwnedRow has no column projection and always fetches the whole row. Corrected, and noted the added id-scoped read per write in the changeset. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGrzpcxbUT9PCsvDRbTpgi --------- Co-authored-by: Claude <noreply@anthropic.com>
…n lane (#1554) * fix(auth): route databaseHooks context.adapter through the transaction lane better-auth hands a databaseHooks before/after hook a GenericEndpointContext whose .context.adapter is the Auth adapter's ROOT instance — better-auth never swaps that reference for the transaction-bound one (only its own AsyncLocalStorage, read via getCurrentAdapter, does). A hook that queried through it during sign-up therefore ran on the outer lane while the sign-up transaction held the database's only connection: a hang on the Dev database, and a read outside the transaction (surviving a rollback) on pooled Postgres. The root instance now reads its lane from the same AsyncLocalStorage store the transaction-bound instance does. Both instances run inside the same boundLane.run(...) call for the life of the transaction, so a hook reaching through context.context.adapter lands on the transaction-bound connection without needing to touch better-auth's own ALS routing. Closes #1252 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HEEWCWcKXFFYY3PXE2zBH6 * docs(adr): renumber the auth idField ADR to 0071 to resolve a 0070 collision 0070-the-auth-plugins-id-strategy-is-config-not-a-hardcoded-pin.md (#1550) and 0070-the-generated-clients-identity-is-a-process-wide-registry-entry.md (#1548) landed within a minute of each other and both claimed 0070, tripping check:adr-duplicates on every PR against main. Renumbered the id-strategy ADR to 0071 (2 filename-link updates in ADR-0048 and ADR-0060) rather than the client-identity one, which has 7+ scattered bare "(ADR-0070)" comment references across packages/core, packages/cli and packages/auth that would otherwise need updating instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HEEWCWcKXFFYY3PXE2zBH6 * docs(auth): drop the now-fixed databaseHooks-outside-transaction limit docs/content/reference/auth.md's "Known limits" section and the pending #1251 changeset (.changeset/silent-moons-gather.md) both still described the databaseHooks-hook-runs-outside-the-transaction limit this PR closes. Left unedited, both would have shipped in the same release as this PR's own changeset claiming it fixed — a contradiction in the same changelog entry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HEEWCWcKXFFYY3PXE2zBH6 * fix(auth): doc-comment phrasing nit from review Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HEEWCWcKXFFYY3PXE2zBH6 --------- Co-authored-by: Claude <noreply@anthropic.com>
Summary
authPluginhardcodeddb.idField: 'uuid7'on every Auth list it injects, with no escape hatch:An app-level
db.idFielddefault (e.g.cuid2, set to match a live better-auth install whoseidcolumns already hold non-uuid text ids) never reached the Auth lists — the generator kept emitting apg/uuidcolumn regardless, breakingadopt-better-auth-tables's whole reason for existing.The
extendListbranch (for a list the app declares itself under one of the derived keys) never applied the pin at all, so it could silently end up on a differentidFieldthan the injected branch, while the adapter'ssupportsUUIDs: true/supportsNumericIds: falsewere hardcoded regardless of which branch actually produced the list.authPlugingains anidField?: 'uuid7' | 'cuid2'option. Resolution order: explicitauthPlugin({ idField })→ the app's owndb.idFielddefault →'uuid7'.'int autoincrement'is refused at config time (the Auth adapter treats every id as a string).The
addListandextendListbranches are now required to agree: an app-declared list whose own resolvedidFielddisagrees with the plugin's throws, naming both values.adoptBetterAuthTables()grows a matchingidFieldoption, so adopting a text/cuid2-shaped live install is one line:adoptBetterAuthTables({ idField: 'cuid2' }).The adapter's
supportsUUIDs/supportsNumericIds(authIdCapabilities) are now derived from the resolved strategy instead of hardcoded, so they can never contradict the emitted column type.ADR-0048 and ADR-0060 amended in place; new ADR-0070 records the decision. Changeset added for
@opensaas/stack-auth(minor).Test plan
packages/auth/tests/config.test.ts,adopt-better-auth-tables.test.ts, and a newadapter-id-capabilities.test.tspnpm testinpackages/auth— 518 passed, 81 skipped (pre-existing skips)pnpm testinpackages/core— 1757 passedpnpm typecheckandpnpm build(root, turbo) — all 16 tasks succeedpnpm lint/pnpm format/pnpm manypkg fix— cleanCloses #1239
🤖 Generated with Claude Code
https://claude.ai/code/session_01218dPJQasRpbcWL9w9fiZ8
Generated by Claude Code