aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(app)/migrate
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes/(app)/migrate')
-rw-r--r--src/routes/(app)/migrate/+page.server.ts38
-rw-r--r--src/routes/(app)/migrate/+page.svelte3
2 files changed, 32 insertions, 9 deletions
diff --git a/src/routes/(app)/migrate/+page.server.ts b/src/routes/(app)/migrate/+page.server.ts
index dc3beb02..5182e8a0 100644
--- a/src/routes/(app)/migrate/+page.server.ts
+++ b/src/routes/(app)/migrate/+page.server.ts
@@ -20,12 +20,26 @@ async function invoiceFor(address: string, sats: number) {
return inv.pr as string;
}
+// The server only accepts letters and numbers, 2–24 of them, so the retired
+// name can't carry a separator. Candidates are <name>v2, <name>v3, … each
+// trimmed to fit, so a long username still lands inside the limit.
+function retiredNames(username: string) {
+ const base = String(username).replace(/[^\p{L}\p{N}]/gu, "");
+ const out: string[] = [];
+ for (let n = 2; n <= 9; n++) {
+ const suffix = `v${n}`;
+ out.push(base.slice(0, 24 - suffix.length) + suffix);
+ }
+ return out;
+}
+
export async function load({ parent, url }) {
const { user } = await parent();
if (!user) redirect(307, `/login?redirect=${encodeURIComponent(url.pathname + url.search)}`);
return {
to: url.searchParams.get("to") || "",
back: url.searchParams.get("back") || "",
+ newName: retiredNames(user.username)[0],
};
}
@@ -62,13 +76,23 @@ export const actions = {
}
if (!sent) throw lastErr;
}
- // Releasing the username is what lets them keep it on v3.
- await post(
- "/user",
- { username: `${username}_v2`, ...(pin ? { pin } : {}) },
- auth(cookies),
- );
- return { ok: true, sent, released: username };
+ // Releasing the username is what lets them keep it on v3. If the
+ // retired name is itself taken, step to the next candidate.
+ let renamed = "";
+ let renameErr;
+ for (const candidate of retiredNames(username)) {
+ try {
+ await post("/user", { username: candidate, ...(pin ? { pin } : {}) }, auth(cookies));
+ renamed = candidate;
+ break;
+ } catch (e) {
+ renameErr = e;
+ const msg = String((e as any)?.message || e);
+ if (!/taken/i.test(msg)) throw e;
+ }
+ }
+ if (!renamed) throw renameErr;
+ return { ok: true, sent, released: username, renamed };
} catch (e) {
const msg = e && typeof e === "object" && "message" in e ? String(e.message) : String(e);
return { error: msg, sent };
diff --git a/src/routes/(app)/migrate/+page.svelte b/src/routes/(app)/migrate/+page.svelte
index eae612f1..e1e4a79d 100644
--- a/src/routes/(app)/migrate/+page.svelte
+++ b/src/routes/(app)/migrate/+page.svelte
@@ -9,11 +9,10 @@
import { enhance } from "$app/forms";
let { data, form } = $props();
- let { user, to, back } = $derived(data);
+ let { user, to, back, newName } = $derived(data);
let working = $state(false);
let balance = $derived(user?.balance || 0);
- let newName = $derived(`${user?.username}_v2`);
let backUrl = $derived.by(() => {
try {
const u = new URL(back || "https://v3.coinos.io/");