function client(changing) { var form = document.getElementById('account-form'); var username = document.getElementById('username'); var secret = document.getElementById('secret'); var confirm = document.getElementById('confirm-password'); var mode = document.getElementById('use-pin'); var button = document.getElementById('submit'); var error = document.getElementById('error'); var enrolling = false; if (changing) { enrolling = true; document.getElementById('heading').textContent = 'Change your password'; document.getElementById('description').textContent = 'Use 15–128 characters. Saving signs out your other sessions.'; document.getElementById('username-row').hidden = true; username.required = false; document.getElementById('mode-row').hidden = true; document.getElementById('current-row').hidden = false; document.getElementById('confirm-row').hidden = false; document.getElementById('secret-label').textContent = 'New password or passphrase'; secret.autocomplete = 'new-password'; button.textContent = 'Save password'; } function update() { document.getElementById('secret-label').textContent = mode.checked ? 'Current account PIN' : 'Password'; secret.autocomplete = mode.checked ? 'off' : 'current-password'; secret.value = ''; error.textContent = ''; button.textContent = mode.checked ? 'Verify PIN' : 'Sign in'; } mode.onchange = update; form.onsubmit = async function (event) { event.preventDefault(); button.disabled = true; error.textContent = ''; try { var body = enrolling ? { password: secret.value, confirmPassword: confirm.value } : { username: username.value }; if (!enrolling) body[mode.checked ? 'pin' : 'password'] = secret.value; if (changing) body.currentPassword = document.getElementById('current-password').value; var response = await fetch(changing ? '/auth/password-change' : enrolling ? '/auth/password-transition' : '/auth/login', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); var data = await response.json(); if (!response.ok || !data.ok) throw new Error(data.error || 'Could not sign in.'); secret.value = ''; if (!data.passwordRequired) { location.href = '/'; return; } enrolling = true; document.getElementById('passkey-login').hidden = true; document.getElementById('heading').textContent = 'Set your password'; document.getElementById('description').textContent = 'Use 15–128 characters. A long passphrase works well. Your account PIN is replaced only after saving.'; username.readOnly = true; document.getElementById('mode-row').hidden = true; document.getElementById('secret-label').textContent = 'New password or passphrase'; secret.autocomplete = 'new-password'; document.getElementById('confirm-row').hidden = false; button.textContent = 'Save password and continue'; secret.focus(); } catch (failure) { error.textContent = failure.message; } finally { button.disabled = false; } }; } function shell(title, body) { return '' + title + ' — Clay' + '
' + body + '
'; } function render(changing) { return shell('Account sign-in', '

Account sign-in

This server uses account passwords. Still using an account PIN? Verify it once to set your password.

' + '
' + '' + '' + '' + '' + '

Forgot your credentials? Contact your server administrator for account recovery.

Start again' + ''); } module.exports = { render: render, shell: shell };