Repository navigation
fix(plugin-auth): Create User with no email names Email, and a wrong password on the password-change screen reads in the user's language - #28288
Conversation
…og marks Email required when phone sign-in is off The refusal read "Either email or phoneNumber is required", naming a body key the dialog does not show. It now reads "Email is required", or "Email or phone number is required" where phone sign-in is on; the code and status are unchanged. The create_user dialog backs Email with two params, a required one shown while phone sign-in is off and an optional one behind the phoneNumber feature, so the required mark appears exactly when Email is required. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cwXFwjU2YZW2dRuZZt
… or temporary password The screen showed the server's English "Invalid password" for the INVALID_PASSWORD refusal in every language. The code now maps to a translated sentence, one new key in every console language pack; any other refusal keeps the server's message. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cwXFwjU2YZW2dRuZZt
The two visibility-gated Email params trip the feature-gate registry guard: the negated phoneNumber gate is not a shape PUBLIC_AUTH_FEATURES books, and booking it means editing the spec registry. The required mark is carried separately; this change keeps the refusal wording. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cwXFwjU2YZW2dRuZZt
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin c61303dd6a1c9b8ffe38fbdc72c9fc4d67e2a78d && git checkout c61303dd6a1c9b8ffe38fbdc72c9fc4d67e2a78d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 53749673ba7a0005d09e8a79544da10d5faa10bc d5b0a9e4beee79dbe7b26b3b98632aff0ac5e521 && git checkout -B drift-repro 53749673ba7a0005d09e8a79544da10d5faa10bc && git merge --no-ff d5b0a9e4beee79dbe7b26b3b98632aff0ac5e521
node scripts/docs-audit/affected-docs.mjs --json 53749673ba7a0005d09e8a79544da10d5faa10bc |
changePassword threw a bare Error built from error.message, so the INVALID_PASSWORD code a wrong current password carries never reached ChangePasswordForm and its mapping to the translated sentence never fired. Route the refusal through toAuthError, as sign-in and the organization methods already do, and pin the code at the client boundary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cwXFwjU2YZW2dRuZZt
|
domain:server#1 · os-elon-musk · session_016WV4czVnUdQQCVKSW5J2uk Seat ACCEPT · PR #28288 · head
|
domain:server#1 · os-elon-musk · session_016WV4cwXFwjU2YZW2dRuZZt
Requested by Elon · project thread
Fixes #27857
Part of #27869
Clause-②: no
Metadata-protocol: none
Skills-docs: none —
git grepofskills/**andcontent/docs/**for "Either email or phoneNumber is required", "Invalid password" andINVALID_PASSWORDhas zero hits.维护者速读
phoneNumber;法语用户改密输错时看到英文。邮箱必填标记另立卡(见下文)。INVALID_REQUEST与状态 400 不变,只改措辞;createAuthClient的changePassword抛错时保留 better-auth 的错误码(原先丢失,映射永不触发);界面只多一个翻译键;元数据未改。回滚即还原本 PR。packages/plugins/plugin-auth/src/admin-user-endpoints.ts(报错措辞)、ui/packages/auth/src/createAuthClient.ts(保留错误码)、ui/packages/app-shell/src/console/RemediationOverlay.tsx(错误码映射)、ui/packages/i18n/src/locales/fr.ts。What changes
One commit per card, plus a revert commit, a merge of
origin/main, and the seat-review fix for #27869 (a):plugin-authadmin-user-endpoints.ts: with neither an email nor a phone number, the refusal reads "Email is required", or "Email or phone number is required" when phone sign-in is on (deps.phoneNumberEnabled()). It used to read "Either email or phoneNumber is required", naming a body key. Status 400 and codeINVALID_REQUESTare unchanged (dispatch: wording only)./change-passwordrefuses a wrong current or temporary password withAPIError.from('BAD_REQUEST', BASE_ERROR_CODES.INVALID_PASSWORD), so the body is{ message: "Invalid password", code: "INVALID_PASSWORD" }(better-auth 1.7.12,api/routes/update-user.mjs). Two links were broken:createAuthClient'schangePasswordthrewnew Error(error.message)and dropped the code. It now throws throughtoAuthError, as sign-in and the organization methods already do, so the thrown error carriescode. The message is unchanged.ChangePasswordForminRemediationOverlay.tsxshowederr.messageas it came. It now mapsINVALID_PASSWORDtoauth.remediation.password.wrongPassword, a new key in all ten console packs (ar, de, en, es, fr, ja, ko, pt, ru, zh). Any other refusal keeps the server's message.What this PR does not carry
feature-gate-guard.test.ts, whose registry ispackages/spec/src/kernel/public-auth-features.ts, outside this PR's surface: the negatedphoneNumbergate is not a shapegatedInputsbooks, and both params resolve to one path. Seat ruling B: it was committed (3a05184), then taken out again by the revert commit, and the seat files it as its own card. Create User with Email empty says "Either email or phoneNumber is required" and the dialog marks nothing required (#27521 row 10) #27857's refusal row still closes here, as the seat ruled.Clause-②: yeschange, and the dispatch fixes the code asINVALID_REQUEST, so it is reported as a finding for the seat.Part of). Its (b) and "loudly" halves are i18n: French is not a platform locale, so a user whose locale isfrreads Englishsys_userlabels (Home feed field labels) #28107 and service-i18n: a missing translation falls back to the fallback locale, then to the key, with no signal #28109. This PR leaves French user sees English: "Invalid password", untranslated sys_user labels in Home feed, misleading Locale help (#27521 row 22) #27869 open; the seat shuts the card once all its rows are carried.Tests
changePassword-code-27869.test.ts(drives the real better-auth client through a mockedfetch; a 400{ message: 'Invalid password', code: 'INVALID_PASSWORD' }from/change-passwordrejects with.code === 'INVALID_PASSWORD'and the message unchanged). New:RemediationOverlay.wrongPassword-27869.test.tsx(the fr and en sentences, plus a control: another code keeps the server message; it mocksuseAuth, so the client pin above covers the first link). Extended:admin-user-endpoints.test.ts(the refusal wording with phone sign-in off and on, code and status pinned). Updated:request-json-body-refusal.test.ts(the empty-body control reads the new wording).pnpm --filter @objectstack/plugin-auth test: Test Files 205 passed (205), Tests 3917 passed, 10 skipped.typecheck: exit 0.uivitest overpackages/auth/,packages/app-shell/src/console/andpackages/i18n/: Test Files 354 passed (354), Tests 3299 passed, 13 skipped.@object-ui/authtype-check: exit 0.scripts/ablation-replace.mjs, restored to the HEAD blob,git statusclean after):admin-user-endpoints.test.ts2 failed / 93 passed.INVALID_PASSWORDmapping disabled →RemediationOverlay.wrongPassword-27869.test.tsx2 failed / 1 passed (the control stays green).changePasswordback tothrow new Error(error.message ?? …)→changePassword-code-27869.test.ts1 failed (expected undefined to be 'INVALID_PASSWORD').Acceptance notes
Verification
The test and ablation readings above are on head
d5b0a9e4. The gate readings below are on9248a860;d5b0a9e4adds only theui/packages/authcommit,dispatch-gates --commandsderives the same 66 families on it, and their rerun ond5b0a9e4is recorded in the card report on #27857.Derived gate families: 66 of 66 exit 0
node scripts/pm/dispatch-gates.mjs --commandsderived 66 families. They ran after builds of@objectstack/cli+platform-objects(with the i18n-bundle packagescheck:i18nnames), the@objectstack/dogfood^...and@objectstack/runtime^...closures, and@objectstack/plugin-auth...(all exit 0).check:i18n,check:dual-build-cjs-loads,check:closing-keyword-parity,check:nul-bytes,check:published-filesandpnpm --dir ui exec vitest run scripts/.dispatch-gates --ran: "66 derived famil(ies) accounted for — 66 run, 0 NOT-MEASURED", exit 0.pnpm lint(eslint . --no-inline-config): exit 0.uitype-check and the fulluitest shards. CI's Type Check UI and Test UI own them.CI check-runs on this PR are the authority for every family CI runs.
Human Minimum
packages/specholds no runtime logic. (not touched)pnpm lintpasses.main, one pull request. (the seat widened Create User with Email empty says "Either email or phoneNumber is required" and the dialog marks nothing required (#27521 row 10) #27857's claim to carry French user sees English: "Invalid password", untranslated sys_user labels in Home feed, misleading Locale help (#27521 row 22) #27869 (a))packages/spectouched: its generated artifacts are regenerated and committed. (not touched)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4cwXFwjU2YZW2dRuZZt
Generated by Claude Code