Players get a fast TTL-backed homepage (local profile / Cloudflare D1) with dense UI polish; login unlocks /home without blocking on every OpenDota refresh. Co-authored-by: Cursor <cursoragent@cursor.com>
93 lines
2.6 KiB
JavaScript
93 lines
2.6 KiB
JavaScript
/**
|
|
* GET /api/players/me — logged-in user's profile from D1; enqueue refresh if stale.
|
|
*/
|
|
import { sessionFromRequest } from "../auth/_steam_common.js";
|
|
import {
|
|
enqueueRefresh,
|
|
isStale,
|
|
jsonResponse,
|
|
loadPlayerBundle,
|
|
} from "./_db.js";
|
|
|
|
export async function onRequestGet(context) {
|
|
try {
|
|
const session = await sessionFromRequest(context);
|
|
if (!session || !session.account_id) {
|
|
return jsonResponse({ authenticated: false }, 401);
|
|
}
|
|
const env = context.env || {};
|
|
const accountId = Number(session.account_id);
|
|
if (!env.DB) {
|
|
return jsonResponse(
|
|
{ error: "database not configured", account_id: accountId },
|
|
503
|
|
);
|
|
}
|
|
|
|
// Ensure user row exists for first login.
|
|
const now = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
await env.DB.prepare(
|
|
`INSERT INTO users (account_id, steamid, personaname, avatar, public_share, created_at, last_login_at)
|
|
VALUES (?, ?, ?, ?, 0, ?, ?)
|
|
ON CONFLICT(account_id) DO UPDATE SET
|
|
personaname=COALESCE(excluded.personaname, users.personaname),
|
|
avatar=COALESCE(excluded.avatar, users.avatar),
|
|
last_login_at=excluded.last_login_at`
|
|
)
|
|
.bind(
|
|
accountId,
|
|
String(session.steamid || ""),
|
|
session.personaname || null,
|
|
session.avatar || null,
|
|
now,
|
|
now
|
|
)
|
|
.run();
|
|
|
|
let bundle = await loadPlayerBundle(env.DB, accountId);
|
|
const fetchedAt =
|
|
(bundle && bundle.availability && bundle.availability.fetched_at) ||
|
|
(bundle && bundle.enriched_at) ||
|
|
null;
|
|
let stale = !bundle || isStale(fetchedAt);
|
|
if (stale) {
|
|
await enqueueRefresh(env, {
|
|
kind: "login_refresh",
|
|
account_id: accountId,
|
|
steamid: session.steamid,
|
|
personaname: session.personaname,
|
|
avatar: session.avatar,
|
|
});
|
|
}
|
|
if (!bundle) {
|
|
return jsonResponse({
|
|
authenticated: true,
|
|
account_id: accountId,
|
|
personaname: session.personaname || null,
|
|
avatar: session.avatar || null,
|
|
public_share: false,
|
|
recent: [],
|
|
career: null,
|
|
recent_20: null,
|
|
top_heroes: [],
|
|
peers: [],
|
|
activity_180: null,
|
|
availability: {
|
|
status: "unknown",
|
|
note: "正在同步…",
|
|
complete: false,
|
|
stale: true,
|
|
},
|
|
stale: true,
|
|
});
|
|
}
|
|
if (bundle.availability) bundle.availability.stale = stale;
|
|
return jsonResponse({ ...bundle, authenticated: true, stale });
|
|
} catch (e) {
|
|
return jsonResponse(
|
|
{ error: "me failed", detail: String((e && e.message) || e) },
|
|
500
|
|
);
|
|
}
|
|
}
|