ACCOUNT_DELETION.md phase 2 (core): a member deletes their own account on
the website, and the admin route runs the same procedure.
- DELETE /api/v1/auth/me/account: typed username, password always (AD7),
and a 2FA or recovery code when 2FA is on. A wrong password or code is
400, not 401 (AD12), so the app's refresh-on-401 never replays it.
409 password_required and last_admin; the demo's shared logins are
locked.
- auth/accountDeletion.js: module hooks first, then one transaction that
reserves a staff username (reserved_usernames, AD9) and deletes the row,
then a Teams reconcile, the audit entry (no username) and a notice to
the old address (new protected template auth.account-deleted).
- MODULE_API 1.20.0: api.onUserDeleting({ userId, deletedBy }), before the
delete, 10 s limit, cannot veto (AD10, AD11).
- utils/displayAuthor.js: a deleted account's username snapshots read
"[deleted player]" to members and the stored name, marked, to staff
(AD5, AD6). Used by the forum, the Reports queue, the guest list and
the Team digest. A deleted account drops off Forum guests (AD13).
- Reserved names refuse at every username write, answered as "taken".
- Web: Delete my account on the player and staff Account pages; staff
views mark "(deleted account)".
- OpenAPI regenerated; route manifest and engagement manifest regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
28 lines
861 B
JavaScript
28 lines
861 B
JavaScript
// A one-line notice for the site-wide toast (components/DemoToast.jsx), for the
|
|
// rare moment a screen has to say something after it has navigated away — the
|
|
// account page cannot show "Your account has been deleted." on itself, because
|
|
// the account it would be shown on no longer exists.
|
|
//
|
|
// The same shape as lib/demoNotice.js and drawn by the same toast, so the site
|
|
// has one place a passing message appears.
|
|
|
|
const listeners = new Set()
|
|
|
|
/** Subscribe to notices. Returns the unsubscribe function. */
|
|
export function onNotice(fn) {
|
|
listeners.add(fn)
|
|
return () => listeners.delete(fn)
|
|
}
|
|
|
|
/** Show one notice. */
|
|
export function showNotice(message) {
|
|
if (typeof message !== 'string' || !message) return
|
|
for (const fn of listeners) {
|
|
try {
|
|
fn(message)
|
|
} catch {
|
|
// A broken listener must not stop the caller.
|
|
}
|
|
}
|
|
}
|