From 0bf610037a75e1353118f1f2b227dd6cbc8ad938 Mon Sep 17 00:00:00 2001 From: TyperBody Date: Thu, 24 Sep 2026 01:31:54 +0800 Subject: [PATCH] fix(web): keep reset-password wire shape for the default method resetPassword() unconditionally added `method` and an empty `totp_code` to every request, which broke the Playwright smoke test that asserts the recovery-key flow posts exactly {user, recovery_key, new_password}. Send only the second-factor fields that apply to the selected method, so the default recovery-key flow stays byte-compatible with existing callers while the totp / recovery_code methods still carry their inputs. --- web/src/app/infra/http/BackendClient.ts | 30 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/web/src/app/infra/http/BackendClient.ts b/web/src/app/infra/http/BackendClient.ts index bf27187a0..1811c7686 100644 --- a/web/src/app/infra/http/BackendClient.ts +++ b/web/src/app/infra/http/BackendClient.ts @@ -1404,17 +1404,25 @@ export class BackendClient extends BaseHttpClient { totpCode?: string; } = {}, ): Promise<{ user: string }> { - return this.post( - '/api/v1/user/reset-password', - { - user, - new_password: newPassword, - method: options.method ?? 'recovery_key', - recovery_key: options.recoveryKey, - totp_code: options.totpCode, - }, - { skipWorkspace: true }, - ); + // Only send the second-factor fields that apply to the selected method, so + // the default recovery-key flow keeps its historical wire shape (no empty + // `method`/`totp_code` keys) and stays byte-compatible with existing callers. + const body: Record = { + user, + new_password: newPassword, + }; + if (options.method && options.method !== 'recovery_key') { + body.method = options.method; + } + if (options.recoveryKey) { + body.recovery_key = options.recoveryKey; + } + if (options.totpCode) { + body.totp_code = options.totpCode; + } + return this.post('/api/v1/user/reset-password', body, { + skipWorkspace: true, + }); } public changePassword(