Add player bug reports and profile identity features

This commit is contained in:
2026-10-08 18:27:20 +05:00
parent 36e8d11eb4
commit 0b08672f4a
51 changed files with 3938 additions and 45 deletions

View File

@@ -3,6 +3,8 @@ import { createHash, randomBytes } from "node:crypto";
import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { admin, required, user } from "./supabase";
import { accountProfile } from "./profile";
import { multiplayerAppearance } from "./multiplayer-appearance";
import { mediaUrls } from "./catalog";
import { requestOrigin } from "./request-origin";
import { ServiceError } from "./service-error";
@@ -13,6 +15,7 @@ import {
roomGuessSchema,
chatMessageSchema,
type RoomView,
type RoomChat,
} from "../shared/multiplayer";
import {
datasetSchema,
@@ -55,6 +58,7 @@ export async function multiplayerApi(
const body = createRoomSchema.parse(await jsonBody(request));
await limit("multiplayer:create:" + accessHash, 20, 3600);
const account = await user();
if (account) await accountProfile(account);
const id = required(
await client.rpc("create_map_room", {
p_dataset: body.datasetId,
@@ -65,6 +69,16 @@ export async function multiplayerApi(
p_owner: account?.id ?? null,
}),
);
if (account)
required(
await client
.from("multiplayer_players")
.update({ account_id: account.id })
.eq("room_id", id)
.eq("access_hash", accessHash)
.is("account_id", null)
.select("id"),
);
return respond({ id });
}
const id = z.string().uuid().parse(path[1]);
@@ -81,16 +95,25 @@ export async function multiplayerApi(
? chatMessageSchema.parse(await jsonBody(request))
: null;
if (body) await limit("multiplayer:chat:" + accessHash, 60, 60);
return respond(
required(
await client.rpc("multiplayer_chat", {
p_room: id,
p_access_hash: accessHash,
p_text: body?.text ?? null,
p_client_id: body?.clientId ?? null,
}),
),
const chat = required(
await client.rpc("multiplayer_chat", {
p_room: id,
p_access_hash: accessHash,
p_text: body?.text ?? null,
p_client_id: body?.clientId ?? null,
}),
) as unknown as RoomChat;
const appearances = await multiplayerAppearance(
id,
chat.messages.map((message) => message.playerId),
);
return respond({
...chat,
messages: chat.messages.map((message) => ({
...message,
...appearances.get(message.playerId),
})),
});
}
let payload: Record<string, string | number> = {};
if (request.method === "POST" && path.length === 3) {
@@ -121,6 +144,32 @@ export async function multiplayerApi(
p_payload: payload,
}),
) as unknown as RoomView;
if (action === "join" && room.you) {
const account = await user();
if (account) {
await accountProfile(account);
required(
await client
.from("multiplayer_players")
.update({ account_id: account.id })
.eq("id", room.you)
.eq("room_id", id)
.eq("access_hash", accessHash)
.is("account_id", null)
.select("id"),
);
}
}
if (action !== "media") {
const appearances = await multiplayerAppearance(
id,
room.players.map((player) => player.id),
);
room.players = room.players.map((player) => ({
...player,
...appearances.get(player.id),
}));
}
if (action !== "media") return respond(room);
if (!room.you) throw new ServiceError("Join this room to play", 403);
if (["lobby", "closed"].includes(room.status))