Skip to content

Commit ea7488c

Browse files
Enhance profile and UUID route handling by introducing username support; refactor identifier parsing and improve error handling
1 parent e65c950 commit ea7488c

5 files changed

Lines changed: 72 additions & 22 deletions

File tree

pages/defaultPage.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ <h2>Route: /uuid/&#123;username|uuid&#125;</h2>
2121
</article>
2222

2323
<article class="card">
24-
<h2>Route: /profile/&#123;uuid&#125;</h2>
24+
<h2>Route: /profile/&#123;username|uuid&#125;</h2>
2525
<div>Usage:</div>
2626
<pre><code>__PROFILE_USAGE__</code></pre>
2727
<div>Example response (jeb_):</div>
@@ -43,7 +43,7 @@ <h2>Error behavior</h2>
4343
<tr>
4444
<td>400</td>
4545
<td>BAD_REQUEST</td>
46-
<td>Missing identifier on <code class="inline">/uuid</code> or invalid UUID format on <code class="inline">/profile/&#123;uuid&#125;</code>.</td>
46+
<td>Missing identifier on <code class="inline">/uuid</code> or <code class="inline">/profile</code>.</td>
4747
</tr>
4848
<tr>
4949
<td>404</td>

pages/defaultPage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function serveDefaultPage(request) {
8585
const html = htmlSource
8686
.replace("/*__INLINE_CSS__*/", cssSource)
8787
.replace("__UUID_USAGE__", escapeHtml(`${base}/uuid/jeb_\n${base}/uuid/853c80ef3c3749fdaa49938b674adae6`))
88-
.replace("__PROFILE_USAGE__", escapeHtml(`${base}/profile/853c80ef3c3749fdaa49938b674adae6`))
88+
.replace("__PROFILE_USAGE__", escapeHtml(`${base}/profile/jeb_\n${base}/profile/853c80ef3c3749fdaa49938b674adae6`))
8989
.replace("__UUID_EXAMPLE__", renderJson(UUID_EXAMPLE))
9090
.replace("__PROFILE_EXAMPLE__", renderJson(PROFILE_EXAMPLE));
9191

routes/profileRoute.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { CACHE_TTL_SECONDS, STATUS } from "../config/constants";
2-
import { fetchSessionProfile } from "../services/minecraftApi";
2+
import { fetchSessionProfile, lookupByUsername } from "../services/minecraftApi";
33
import { getCachedEntry, setCachedEntry } from "../utils/cache";
44
import { badRequest, internalError, jsonResponse, notFound } from "../utils/responses";
55
import {
66
buildCacheMeta,
77
decodeBase64Json,
8-
isUuid,
9-
normalizeUuid,
10-
nowSeconds
8+
nowSeconds,
9+
parseUsernameOrUuid
1110
} from "../utils/utils";
1211

1312
function uuidNameKey(username) {
@@ -61,12 +60,14 @@ async function cacheIdentityPayload(env, payload) {
6160
}
6261

6362
export async function handleProfileRoute(identifier, env) {
64-
if (!identifier || !isUuid(identifier.trim())) {
65-
return badRequest("Invalid uuid format");
63+
const parsed = parseUsernameOrUuid(identifier);
64+
if (!parsed.ok) {
65+
return badRequest(parsed.message);
6666
}
6767

68-
const normalizedUuid = normalizeUuid(identifier.trim());
69-
const cacheKey = uuidIdKey(normalizedUuid);
68+
const cacheKey = parsed.kind === "uuid"
69+
? uuidIdKey(parsed.normalizedUuid)
70+
: uuidNameKey(parsed.username);
7071

7172
const cached = await getCachedEntry(env, cacheKey);
7273
if (isValidCachedProfile(cached)) {
@@ -76,7 +77,23 @@ export async function handleProfileRoute(identifier, env) {
7677
}
7778

7879
try {
79-
const upstream = await fetchSessionProfile(normalizedUuid);
80+
let resolvedId = parsed.kind === "uuid" ? parsed.normalizedUuid : null;
81+
82+
// If a username key is already cached without profile, skip an extra lookup.
83+
if (!resolvedId && cached?.payload?.id) {
84+
resolvedId = cached.payload.id;
85+
}
86+
87+
if (!resolvedId) {
88+
const identityUpstream = await lookupByUsername(parsed.username);
89+
if (identityUpstream.notFound) {
90+
return notFound("Player profile not found");
91+
}
92+
93+
resolvedId = identityUpstream.data.id;
94+
}
95+
96+
const upstream = await fetchSessionProfile(resolvedId);
8097
if (upstream.notFound) {
8198
return notFound("Player profile not found");
8299
}

routes/uuidRoute.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { CACHE_TTL_SECONDS, STATUS } from "../config/constants";
22
import { getCachedEntry, setCachedEntry } from "../utils/cache";
33
import { badRequest, internalError, jsonResponse, notFound } from "../utils/responses";
4-
import { buildCacheMeta, isUuid, normalizeUuid, nowSeconds } from "../utils/utils";
4+
import { buildCacheMeta, nowSeconds, parseUsernameOrUuid } from "../utils/utils";
55
import { lookupByUsername, lookupByUuid } from "../services/minecraftApi";
66

77
function uuidNameKey(username) {
@@ -41,14 +41,14 @@ async function cacheIdentityPayload(env, payload) {
4141
}
4242

4343
export async function handleUuidRoute(identifier, env) {
44-
if (!identifier) {
45-
return badRequest("Missing username or uuid");
44+
const parsed = parseUsernameOrUuid(identifier);
45+
if (!parsed.ok) {
46+
return badRequest(parsed.message);
4647
}
4748

48-
const input = identifier.trim();
49-
const inputIsUuid = isUuid(input);
50-
const normalizedUuid = inputIsUuid ? normalizeUuid(input) : null;
51-
const cacheKey = inputIsUuid ? uuidIdKey(normalizedUuid) : uuidNameKey(input);
49+
const cacheKey = parsed.kind === "uuid"
50+
? uuidIdKey(parsed.normalizedUuid)
51+
: uuidNameKey(parsed.username);
5252

5353
const cached = await getCachedEntry(env, cacheKey);
5454
if (isValidCachedIdentity(cached)) {
@@ -58,9 +58,9 @@ export async function handleUuidRoute(identifier, env) {
5858
}
5959

6060
try {
61-
const upstream = inputIsUuid
62-
? await lookupByUuid(normalizedUuid)
63-
: await lookupByUsername(input);
61+
const upstream = parsed.kind === "uuid"
62+
? await lookupByUuid(parsed.normalizedUuid)
63+
: await lookupByUsername(parsed.username);
6464

6565
if (upstream.notFound) {
6666
return notFound("Player not found");

utils/utils.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,39 @@ export function normalizeUuid(value) {
99
return value.toLowerCase().replace(/-/g, "");
1010
}
1111

12+
export function parseUsernameOrUuid(identifier) {
13+
if (typeof identifier !== "string") {
14+
return {
15+
ok: false,
16+
message: "Missing username or uuid"
17+
};
18+
}
19+
20+
const value = identifier.trim();
21+
if (!value) {
22+
return {
23+
ok: false,
24+
message: "Missing username or uuid"
25+
};
26+
}
27+
28+
if (isUuid(value)) {
29+
return {
30+
ok: true,
31+
kind: "uuid",
32+
value,
33+
normalizedUuid: normalizeUuid(value)
34+
};
35+
}
36+
37+
return {
38+
ok: true,
39+
kind: "username",
40+
value,
41+
username: value
42+
};
43+
}
44+
1245
export function nowSeconds() {
1346
return Math.floor(Date.now() / 1000);
1447
}

0 commit comments

Comments
 (0)