desloppify: code health overhaul plus abuse hardening (140 green, strict 87.2)
Build & Push / Lint & Build (pull_request) Failing after 52s
Build & Push / Build & Push Image (pull_request) Skipped
Build & Push / Trigger Deploy (pull_request) Skipped

Honest baseline after removing 45 gaming suppressions. Structural: lib/game plus root hooks extraction, CORS origin echo, DEV_ORIGINS layering. Fixes: error-cause binding, discord 5xx split, null-cache guard, co-located tests, rejecting-fetch coverage, naming and typing cleanup, socket controller, cache bound, cascade helpers, latch resets. Hardening: per-IP rate limit on API routes, deterministic-miss UX, retry cooldown plus cap. Suite 140 green, build plus lint clean.
This commit is contained in:
fristy committed 2026-09-11 23:54:59 +03:00
1 parent 7d6d31265b
commit 864b9226fc
78 files changed
+4908 -1430

No files matched your search

+53 -383
View File
@@ -1,91 +1,12 @@
"use client";
import Image from "next/image";
import { useEffect, useMemo, useRef, useState } from "react";
import type { GamePricePoint, GameProfile } from "@/lib/game-profile";
import { steamdbRating } from "@/lib/game-profile";
import type { Dictionary } from "@/lib/i18n/get-dictionary";
type ModalDict = Dictionary["discord"]["gameModal"];
const STEAM_SCORE_KEYS: Record<string, keyof ModalDict["reviewScores"]> = {
"Overwhelmingly Positive": "overwhelminglyPositive",
"Very Positive": "veryPositive",
Positive: "positive",
"Mostly Positive": "mostlyPositive",
Mixed: "mixed",
"Mostly Negative": "mostlyNegative",
Negative: "negative",
"Very Negative": "veryNegative",
"Overwhelmingly Negative": "overwhelminglyNegative",
};
const LOCALE_TAGS: Record<string, string> = {
tr: "tr-TR",
en: "en-US",
de: "de-DE",
};
const COUNTRIES: Record<string, string> = {
tr: "TR",
en: "US",
de: "DE",
};
function localizeScore(label: string, dict: ModalDict): string {
const key = STEAM_SCORE_KEYS[label];
return key ? dict.reviewScores[key] : label;
}
function formatRatingPercent(value: number, tag: string): string {
try {
return new Intl.NumberFormat(tag, {
style: "percent",
maximumFractionDigits: 2,
}).format(value);
} catch {
return `%${(value * 100).toFixed(2)}`;
}
}
function formatPrice(point: GamePricePoint, tag: string): string {
try {
return new Intl.NumberFormat(tag, {
style: "currency",
currency: point.currency,
}).format(point.price);
} catch {
return `${point.price} ${point.currency}`;
}
}
function formatReleaseDate(value: string, tag: string): string {
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
const parsed = new Date(`${value}T00:00:00`);
if (!Number.isNaN(parsed.getTime())) {
return parsed.toLocaleDateString(tag, {
day: "numeric",
month: "long",
year: "numeric",
});
}
}
return value;
}
function formatCount(value: number | null | undefined, tag: string, unit: string): string {
if (value == null) {
return "—";
}
return `${value.toLocaleString(tag)} ${unit}`;
}
function discountPercent(point: GamePricePoint): number | null {
if (point.regular > point.price && point.regular > 0) {
return Math.round((1 - point.price / point.regular) * 100);
}
return null;
}
import { useEffect } from "react";
import { ModalPrices, ModalReviews, ModalScreenshots } from "@/components/game-profile-sections";
import { formatReleaseDate, selectGameView, type ModalDict } from "@/lib/game/game-format";
import { steamdbAppUrl } from "@/lib/game/discord-app";
import type { Locale } from "@/lib/i18n/locales";
import { useGameProfile } from "@/hooks/use-game-profile";
export function GameProfileModal({
applicationId,
@@ -99,48 +20,26 @@ export function GameProfileModal({
}: {
applicationId: string;
heroSeed: number;
lang: string;
lang: Locale;
iconUrl: string | null;
fallbackName: string;
fallbackGameUrl: string;
dict: ModalDict;
onClose: () => void;
}) {
const [profile, setProfile] = useState<GameProfile | null>(null);
const [failed, setFailed] = useState(false);
const [attempt, setAttempt] = useState(0);
const [bannerPick, setBannerPick] = useState<string | null>(null);
const tag = LOCALE_TAGS[lang] ?? "en-US";
const country = COUNTRIES[lang] ?? "US";
useEffect(() => {
let cancelled = false;
async function load(): Promise<void> {
try {
const response = await fetch(
`/api/game/${applicationId}?lang=${lang}&country=${country}`,
);
if (!response.ok) {
throw new Error(`game api: ${response.status}`);
}
const json = (await response.json()) as GameProfile;
if (!cancelled) {
setProfile(json);
setFailed(false);
}
} catch {
if (!cancelled) {
setFailed(true);
}
}
}
void load();
return () => {
cancelled = true;
};
}, [applicationId, lang, country, attempt]);
const partialFail =
!!profile && !profile.sources.igdb && !profile.sources.steam && !profile.sources.itad;
const {
profile,
failed,
localeTag,
hero,
hasDetails,
partialFail,
isDeterministicMiss,
canRetry,
retry,
reset,
setBannerPick,
} = useGameProfile(applicationId, lang, heroSeed);
useEffect(() => {
function onKey(event: KeyboardEvent): void {
@@ -157,72 +56,11 @@ export function GameProfileModal({
};
}, [onClose]);
const gameUrl = profile?.gameUrl ?? fallbackGameUrl;
const name = profile?.name ?? fallbackName;
const best = profile?.itad?.prices ?? null;
const low = profile?.itad?.historyLow ?? null;
const isFree = !!best && best.price === 0;
const hero = useMemo(() => {
if (bannerPick) {
return bannerPick;
}
const shots = profile?.screenshots ?? [];
if (shots.length > 0) {
return shots[heroSeed % shots.length] ?? null;
}
return profile?.artworkUrl ?? null;
}, [profile, heroSeed, bannerPick]);
const dbRating =
profile?.steamReviews?.positive != null && profile?.steamReviews?.total != null
? steamdbRating(profile.steamReviews.positive, profile.steamReviews.total)
: null;
const itadReviews = profile?.itad?.reviews ?? [];
const hasDetails = !!(
profile &&
(profile.developers.length > 0 ||
profile.publishers.length > 0 ||
profile.releaseDate ||
profile.platforms.length > 0 ||
profile.links.length > 0)
const { gameUrl, name, bestPrice, historyLow, isFree } = selectGameView(
profile,
fallbackName,
fallbackGameUrl,
);
const metascore = itadReviews.find((r) => r.source === "Metascore") ?? null;
const opencritic = itadReviews.find((r) => r.source === "OpenCritic") ?? null;
const hasReviews = !!(
profile?.steamReviews ||
(dbRating != null && profile?.steamId) ||
metascore ||
opencritic
);
const stripRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
const strip = stripRef.current;
if (!strip) {
return;
}
function onWheel(event: WheelEvent): void {
const el = stripRef.current;
if (!el) {
return;
}
if (Math.abs(event.deltaX) >= Math.abs(event.deltaY)) {
return;
}
if (el.scrollWidth <= el.clientWidth + 1) {
return;
}
event.preventDefault();
el.scrollLeft += event.deltaY;
}
strip.addEventListener("wheel", onWheel, { passive: false });
return () => strip.removeEventListener("wheel", onWheel);
}, [profile]);
function scrollStrip(by: number): void {
stripRef.current?.scrollBy({ left: by, behavior: "smooth" });
}
return (
<div
@@ -301,26 +139,26 @@ export function GameProfileModal({
<p>{dict.loadError}</p>
<button
type="button"
onClick={() => {
setFailed(false);
setAttempt((n) => n + 1);
}}
className="shrink-0 cursor-pointer rounded-full border border-white/10 px-3 py-1 text-xs text-zinc-300 transition-colors hover:border-white/25 hover:text-white"
onClick={retry}
disabled={!canRetry}
className="shrink-0 cursor-pointer rounded-full border border-white/10 px-3 py-1 text-xs text-zinc-300 transition-colors hover:border-white/25 hover:text-white disabled:cursor-not-allowed disabled:opacity-40"
>
{dict.retry}
</button>
</div>
) : null}
{partialFail ? (
{isDeterministicMiss ? (
<div className="mt-4 flex items-center gap-3 rounded-xl border border-white/5 bg-white/[0.03] p-3 text-sm text-zinc-400">
<p className="flex-1">{dict.noGameData}</p>
</div>
) : partialFail ? (
<div className="mt-4 flex items-center gap-3 rounded-xl border border-white/5 bg-white/[0.03] p-3 text-sm text-zinc-400">
<p className="flex-1">{dict.partialFail}</p>
<button
type="button"
onClick={() => {
setProfile(null);
setAttempt((n) => n + 1);
}}
className="shrink-0 cursor-pointer rounded-full border border-white/10 px-3 py-1 text-xs text-zinc-300 transition-colors hover:border-white/25 hover:text-white"
onClick={reset}
disabled={!canRetry}
className="shrink-0 cursor-pointer rounded-full border border-white/10 px-3 py-1 text-xs text-zinc-300 transition-colors hover:border-white/25 hover:text-white disabled:cursor-not-allowed disabled:opacity-40"
>
{dict.retry}
</button>
@@ -346,7 +184,7 @@ export function GameProfileModal({
) : null}
{profile?.steamId ? (
<a
href={`https://steamdb.info/app/${profile.steamId}/`}
href={steamdbAppUrl(profile.steamId)}
target="_blank"
rel="noopener noreferrer"
className="rounded-full border border-white/15 px-4 py-1.5 text-xs text-zinc-300 transition-colors hover:border-blurple hover:text-white"
@@ -384,7 +222,7 @@ export function GameProfileModal({
) : null}
</div>
{hasDetails ? (
{profile && hasDetails ? (
<dl className="mt-5 grid gap-x-6 gap-y-2 rounded-2xl border border-white/5 bg-white/[0.03] p-4 text-sm md:grid-cols-2">
{profile.developers.length > 0 ? (
<div className="flex flex-col gap-0.5 sm:flex-row sm:gap-3">
@@ -412,7 +250,7 @@ export function GameProfileModal({
{dict.releaseDate}
</dt>
<dd className="text-zinc-200">
{formatReleaseDate(profile.releaseDate, tag)}
{formatReleaseDate(profile.releaseDate, localeTag)}
</dd>
</div>
) : null}
@@ -447,193 +285,25 @@ export function GameProfileModal({
</dl>
) : null}
{profile && hasReviews ? (
<div className="mt-4">
<p className="font-mono text-xs uppercase tracking-wider text-zinc-500">
{dict.reviews}
</p>
<div className="mt-1.5 grid gap-2 sm:grid-cols-2">
{profile.steamReviews ? (
<a
href={profile.steamReviews.url}
target="_blank"
rel="noopener noreferrer"
className="rounded-xl border border-white/5 bg-white/[0.03] p-3 transition-colors hover:border-white/15"
>
<p className="font-mono text-xs text-zinc-500">
{dict.totalReviews}
</p>
<p className="mt-1 text-sm font-semibold">
{localizeScore(profile.steamReviews.label, dict)}
</p>
<p className="font-mono text-xs text-zinc-500">
{formatCount(
profile.steamReviews.total,
tag,
dict.reviewsUnit,
)}
</p>
</a>
) : null}
{dbRating != null && profile.steamId ? (
<a
href={`https://steamdb.info/app/${profile.steamId}/`}
target="_blank"
rel="noopener noreferrer"
className="rounded-xl border border-white/5 bg-white/[0.03] p-3 transition-colors hover:border-white/15"
>
<p className="font-mono text-xs text-zinc-500">
{dict.steamdbRating}
</p>
<p className="mt-1 text-sm font-semibold">
{formatRatingPercent(dbRating, tag)}
</p>
<p className="font-mono text-xs text-zinc-500">
steamdb.info ↗
</p>
</a>
) : null}
{metascore ? (
<a
href={metascore.url}
target="_blank"
rel="noopener noreferrer"
className="rounded-xl border border-white/5 bg-white/[0.03] p-3 transition-colors hover:border-white/15"
>
<p className="font-mono text-xs text-zinc-500">
Metacritic
</p>
<p className="mt-1 text-sm font-semibold">
{metascore.score ?? "—"}
<span className="font-normal text-zinc-500">/100</span>
</p>
<p className="font-mono text-xs text-zinc-500">
{formatCount(metascore.count, tag, dict.reviewsUnit)}
</p>
</a>
) : null}
{opencritic ? (
<a
href={opencritic.url}
target="_blank"
rel="noopener noreferrer"
className="rounded-xl border border-white/5 bg-white/[0.03] p-3 transition-colors hover:border-white/15"
>
<p className="font-mono text-xs text-zinc-500">
OpenCritic
</p>
<p className="mt-1 text-sm font-semibold">
{opencritic.score ?? "—"}
<span className="font-normal text-zinc-500">/100</span>
</p>
<p className="font-mono text-xs text-zinc-500">
{formatCount(opencritic.count, tag, dict.reviewsUnit)}
</p>
</a>
) : null}
</div>
</div>
) : null}
{profile ? <ModalReviews profile={profile} dict={dict} localeTag={localeTag} /> : null}
{profile?.itad && (best || low) ? (
<div className="mt-4">
<p className="font-mono text-xs uppercase tracking-wider text-zinc-500">
{dict.prices}
</p>
{isFree ? (
<p className="mt-1.5 inline-block rounded-full border border-mint/20 bg-mint/5 px-4 py-1.5 text-xs font-semibold text-mint">
{dict.free}
</p>
) : (
<div className="mt-1.5 grid gap-2 sm:grid-cols-2">
{best ? (
<a
href={best.url || undefined}
target="_blank"
rel="noopener noreferrer"
className="rounded-xl border border-mint/20 bg-mint/5 p-3 transition-colors hover:border-mint/40"
>
<p className="font-mono text-xs text-mint">
{dict.bestPrice} · {best.shop}
</p>
<p className="mt-1 text-lg font-bold">
{formatPrice(best, tag)}{" "}
{discountPercent(best) ? (
<span className="ml-1 rounded bg-mint/15 px-1.5 py-0.5 align-middle font-mono text-xs text-mint">
-%{discountPercent(best)}
</span>
) : null}
</p>
</a>
) : null}
{low ? (
<div className="rounded-xl border border-white/5 bg-white/[0.03] p-3">
<p className="font-mono text-xs text-zinc-500">
{dict.historyLow} · {low.shop}
</p>
<p className="mt-1 text-lg font-bold text-zinc-200">
{formatPrice(low, tag)}
</p>
</div>
) : null}
</div>
)}
</div>
{profile?.itad && (bestPrice || historyLow) ? (
<ModalPrices
dict={dict}
localeTag={localeTag}
bestPrice={bestPrice}
historyLow={historyLow}
isFree={isFree}
/>
) : null}
{profile && profile.screenshots.length > 0 ? (
<div className="mt-4">
<div className="flex items-center justify-between">
<p className="font-mono text-xs uppercase tracking-wider text-zinc-500">
{dict.screenshots}
</p>
<div className="flex gap-1.5">
<button
type="button"
onClick={() => scrollStrip(-360)}
aria-label={dict.scrollBack}
className="rounded-full border border-white/10 px-2.5 py-0.5 text-xs text-zinc-400 transition-colors hover:border-white/25 hover:text-white"
>
‹
</button>
<button
type="button"
onClick={() => scrollStrip(360)}
aria-label={dict.scrollForward}
className="rounded-full border border-white/10 px-2.5 py-0.5 text-xs text-zinc-400 transition-colors hover:border-white/25 hover:text-white"
>
›
</button>
</div>
</div>
<div
ref={stripRef}
className="no-scrollbar mt-1.5 flex gap-2 overflow-x-auto p-1"
>
{profile.screenshots.map((shot) => (
<button
key={shot}
type="button"
onClick={() => setBannerPick(shot)}
aria-label={dict.screenshots}
className={`shrink-0 overflow-hidden rounded-xl transition-all ${
hero === shot
? "ring-2 ring-blurple"
: "opacity-70 hover:opacity-100"
}`}
>
<Image
src={shot}
alt=""
width={320}
height={180}
loading="lazy"
className="h-auto w-56"
/>
</button>
))}
</div>
</div>
<ModalScreenshots
profile={profile}
dict={dict}
hero={hero}
onPick={setBannerPick}
/>
) : null}
</div>
</div>