feat(velocity): add /felis migrate to open an account migration (§B3 inherit)
Add the in-game /felis migrate command that a player runs to open an account migration, the entry point for handing their owned servers to another account (§B3 inherit, scenario A). The command posts the player's Mojang-verified UUID to the existing handleMigrateStart backend, which puts the account into migrate mode; the player then finishes on the web console (prove identity, name the receiving account, redeem a one-time code). Mirrors the existing /felis claim path: requires a real player past login limbo, acts on the caller's account rather than the current server, expects 201 Created affirming started=true (a 201 without it is a contract breach, not a refusal), and maps the handler refusals (404 not_linked, 409 account_retired) to player-facing guidance. On success it points the player at https://console.<root_domain>, derived from config, never hardcoded. Compile-verified against velocity-api:3.3.0-SNAPSHOT via the podman gradle toolchain. Closes the code-only gap named in handlers_account_migrate.go.
This commit is contained in:
2 files changed
+83
No files matched your search
@@ -200,6 +200,29 @@ public final class FelisApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* migrateStart opens an account migration for the player who ran {@code /felis
|
||||
* migrate} in-game (spec §B3 inherit, scenario A). It is the internal face of that
|
||||
* command: Velocity has already established the caller's Mojang-verified UUID, so the
|
||||
* initiator is trustworthy, and this POST puts that UUID's linked account into migrate
|
||||
* mode (state {@code initiated}). Only the migration is opened here — the sensitive
|
||||
* proof (web step-up, naming the receiving account, redeeming a code) happens
|
||||
* afterwards on the console. {@code POST /api/v1/internal/account/migrate/start} with
|
||||
* the verified UUID; expects 201. An unlinked UUID has no account to migrate (404
|
||||
* {@code not_linked}); a retired or already-migrating account cannot re-initiate (409
|
||||
* {@code account_retired}). Both surface as branchable {@link LinkException}s; a 201
|
||||
* that does not affirm {@code started:true} is a contract breach, not a refusal.
|
||||
*/
|
||||
public void migrateStart(UUID mcUuid) throws LinkException {
|
||||
Objects.requireNonNull(mcUuid, "mcUuid");
|
||||
String body = "{\"mc_uuid\":\"" + mcUuid + "\"}";
|
||||
Map<?, ?> res = postObject("/api/v1/internal/account/migrate/start", body, 201);
|
||||
Object started = res.get("started");
|
||||
if (!(started instanceof Boolean) || !((Boolean) started)) {
|
||||
throw new LinkException(201, "bad_response", "migrate start returned 201 without started=true");
|
||||
}
|
||||
}
|
||||
|
||||
// ---- transport ----
|
||||
|
||||
private Map<?, ?> getObject(String path, int expect) throws LinkException {
|
||||
|
||||
Reference in new issue
Block a user