feat(account): unlink game accounts on the shard before an account is deleted (MODULE_API 1.20.0) #47
Reference in New Issue
Block a user
No description provided.
Delete Branch "feature/account-deletion-hook"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Step 3 of
docs/website/ACCOUNT_DELETION.md§6, the UO half of §4.4. Core side: website#232 (merged,7bd93b8).Why
shard_account_linksis only a mirror. The shard keeps the site user id on the game account and reports it aswebIdon everymob.login. So the cascade alone would leave the shard attributing the account to a deleted user forever. Deletion has to unlink on the shard (AD10). The shard account and its characters stay (AD8).What it does (
server/utils/accountDeletion.js)onUserDeleting({ userId, deletedBy }):shard_pending_unlinkstable, before the first call to the shard. Core gives a hook 10 s and one sidecar call can take 12, so an abandoned hook still leaves the rest queued.uoLinkClient.unlinkAccount({ actor: 'web:account-deletion', account }).shard.account.unlinkis logged withdetail: { account, webUserId, reason: 'account deleted', deletedBy }. The entry has nouserIdcolumn, because on a retry the user is already gone.refusedand never retried.pending. The mirror row goes with the cascade.retryPending()runs one pass at a time and tries every pending row. It runs:onBootstarts the socket and boot never calls the shard.server.hello, which is the plugin reconnecting while the sidecar was already up.mob.loginon that account carries nowebId, or a different one: the tag is gone, whoever cleared it. A replayed login never clears a row, because one from before the link carries nowebId.GET /admin/uo-link/configgainspendingUnlinks(the swagger description is updated and the fragment regenerated; no new route).Schema
shard_pending_unlinks(accountPK,web_user_id,state,queued_at,attempts,last_attempt_at,last_error). It has no foreign key, on purpose: a row outlives the user it names. It's added topurge.sql.Also
coreApiis^1.20.0.ci/core-ref.jsonmoves from655fbf3(1.10.0) to7bd93b8(1.20.0, website#232's merge).Checked
npm test736/736,check:importspasses, andcheck:swaggerpasses after regenerating the fragment.npm run build, andnpm test45/45.7bd93b8:route manifest up to date (282 routes)routes.manifest.json is current — 76 routes, all documentedonUserDeletingregistration.test/accountDeletion.test.js, 13 tests:server.helloandmob.loginact only when liveentry.test.jsasserts the hook is registered.Not walked yet: the ServUO + sidecar walk (unlink cleared, then the sidecar stopped, queued, and cleared on return) is §6 step 6.
🤖 Generated with Claude Code
https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
ACCOUNT_DELETION.md §4.4 (AD10, AD11). api.onUserDeleting queues every linked account in the new shard_pending_unlinks table, then calls the sidecar's DELETE /link/{account} (actor web:account-deletion) and drops the mirror on 200/404. A shard that is away leaves the row pending, retried on WS reconnect and on a live server.hello; a protected account (403) is refused and listed on Admin -> Shard as still linked on the shard. A live mob.login without the deleted user's webId clears the row. coreApi ^1.20.0; core-ref pinned to website#232's merge (7bd93b8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY