Files
climperor/web/frontend/functions/api/players/publish.js
T
vosonandCursor f5b7011c45 Ship Steam login, D1 player sync, and cached「我」dashboard.
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>
2026-08-01 01:24:30 +08:00

97 lines
2.7 KiB
JavaScript

/**
* POST /api/players/publish
*
* Body: { account_id, match_id }
* Optional header: X-Climperor-Publish-Secret
*
* Enqueues Cloudflare Queue sync (D1 + R2). No longer writes OSS profile JSON.
*/
import { enqueueRefresh, jsonResponse } from "./_db.js";
function envOf(context) {
return (context && context.env) || {};
}
function intField(v, fallback = 0) {
const n = Number(v);
return Number.isFinite(n) ? Math.trunc(n) : fallback;
}
export async function onRequestPost(context) {
try {
const env = envOf(context);
const expected = (env.PLAYER_PAGES_PUBLISH_SECRET || "").trim();
if (expected) {
const got = (
context.request.headers.get("X-Climperor-Publish-Secret") || ""
).trim();
if (got !== expected) {
return jsonResponse({ error: "forbidden" }, 403);
}
}
let body;
try {
body = await context.request.json();
} catch {
return jsonResponse({ error: "invalid json" }, 400);
}
const accountId = intField(body && body.account_id, -1);
const matchId = intField(body && body.match_id, -1);
if (accountId <= 0 || matchId <= 0) {
return jsonResponse({ error: "account_id and match_id required" }, 400);
}
if (!env.SYNC_QUEUE) {
return jsonResponse({ error: "sync queue not configured" }, 503);
}
// Mark public_share when PC publishes intentionally.
if (env.DB) {
const now = new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
const steamid = String(BigInt(accountId) + 76561197960265728n);
await env.DB.prepare(
`INSERT INTO users (account_id, steamid, personaname, avatar, public_share, created_at, last_login_at)
VALUES (?, ?, NULL, NULL, 1, ?, ?)
ON CONFLICT(account_id) DO UPDATE SET public_share = 1, last_login_at = excluded.last_login_at`
)
.bind(accountId, steamid, now, now)
.run();
}
const queued = await enqueueRefresh(env, {
kind: "publish_match",
account_id: accountId,
match_id: matchId,
public_share: true,
});
if (!queued) {
return jsonResponse({ error: "enqueue failed" }, 503);
}
return jsonResponse({
ok: true,
queued: true,
account_id: accountId,
match_id: matchId,
});
} catch (e) {
return jsonResponse(
{ error: "publish failed", detail: String((e && e.message) || e) },
500
);
}
}
export async function onRequestOptions() {
return new Response(null, {
status: 204,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, X-Climperor-Publish-Secret",
"Access-Control-Max-Age": "86400",
},
});
}