Add public profiles and cosmetic shop
All checks were successful
Deploy MineGeo to Dokploy / deploy (push) Successful in 7m10s

This commit is contained in:
2026-10-15 17:30:10 +05:00
parent 44e62cff2f
commit c541cc09b4
28 changed files with 1359 additions and 45 deletions

52
lib/cosmetics-api.ts Normal file
View File

@@ -0,0 +1,52 @@
import "server-only";
import { NextRequest, NextResponse } from "next/server";
import { profileCosmeticActionSchema } from "@/shared/profile-cosmetics";
import { admin, required, user } from "./supabase";
import { browserAccount } from "./request-security";
import { profileCosmeticsState } from "./profile-cosmetics";
type Context = {
jsonBody: (request: NextRequest) => Promise<unknown>;
limit: (key: string, count: number, seconds: number) => Promise<void>;
};
const json = (body: unknown, status = 200) =>
NextResponse.json(body, { status, headers: { "Cache-Control": "no-store" } });
export async function cosmeticsApi(
request: NextRequest,
path: string[],
context: Context,
) {
if (path.length !== 1) return json({ error: "Not found" }, 404);
const account = await browserAccount(request, user);
if (request.method === "GET")
return json({ shop: await profileCosmeticsState(account.id) });
if (request.method !== "POST")
return json({ error: "Method not allowed" }, 405);
const body = profileCosmeticActionSchema.parse(
await context.jsonBody(request),
);
if (body.action === "purchase") {
await context.limit("cosmetic-purchase:" + account.id, 8, 60);
return json({
shop: required(
await admin().rpc("buy_profile_cosmetic", {
p_user: account.id,
p_cosmetic_id: body.cosmeticId,
}),
),
});
}
await context.limit("cosmetic-equip:" + account.id, 30, 60);
return json({
shop: required(
await admin().rpc("equip_profile_cosmetic", {
p_user: account.id,
p_cosmetic_id: body.cosmeticId,
}),
),
});
}