feat: remove sentry

This commit is contained in:
trafficlunar 2026-04-13 20:39:32 +01:00
parent 144240e278
commit e500cefcc2
21 changed files with 20 additions and 2011 deletions

View file

@ -9,10 +9,6 @@ NEXT_PUBLIC_BASE_URL=http://localhost:3000
CLOUDFLARE_ZONE_ID=XXXXXXXXXXXXXXXX CLOUDFLARE_ZONE_ID=XXXXXXXXXXXXXXXX
CLOUDFLARE_API_TOKEN=XXXXXXXXXXXXXXXX CLOUDFLARE_API_TOKEN=XXXXXXXXXXXXXXXX
# Used for error tracking
NEXT_PUBLIC_SENTRY_DSN=""
SENTRY_URL=""
# Check Auth.js docs for information # Check Auth.js docs for information
AUTH_URL=http://localhost:3000 # This should be the same as NEXT_PUBLIC_BASE_URL AUTH_URL=http://localhost:3000 # This should be the same as NEXT_PUBLIC_BASE_URL
AUTH_TRUST_HOST=true AUTH_TRUST_HOST=true

2
.gitignore vendored
View file

@ -44,5 +44,3 @@ next-env.d.ts
# tomodachi-share # tomodachi-share
uploads/ uploads/
# Sentry Config File
.env.sentry-build-plugin

View file

@ -1,4 +1,3 @@
import { withSentryConfig } from "@sentry/nextjs";
import type { NextConfig } from "next"; import type { NextConfig } from "next";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
@ -8,41 +7,4 @@ const nextConfig: NextConfig = {
}, },
}; };
export default withSentryConfig(nextConfig, { export default nextConfig;
// For all available options, see:
// https://www.npmjs.com/package/@sentry/webpack-plugin#options
org: "trafficlunar",
project: "tomodachishare",
sentryUrl: process.env.SENTRY_URL,
// Only print logs for uploading source maps in CI
silent: !process.env.CI,
// For all available options, see:
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
// Upload a larger set of source maps for prettier stack traces (increases build time)
widenClientFileUpload: true,
// Uncomment to route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
// This can increase your server load as well as your hosting bill.
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
// side errors will fail.
// tunnelRoute: "/monitoring",
webpack: {
// Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
// See the following for more information:
// https://docs.sentry.io/product/crons/
// https://vercel.com/docs/cron-jobs
automaticVercelMonitors: false,
// Tree-shaking options for reducing bundle size
treeshake: {
// Automatically tree-shake Sentry logger statements to reduce bundle size
removeDebugLogging: true,
},
},
});

View file

@ -16,7 +16,6 @@
"@bprogress/next": "^3.2.12", "@bprogress/next": "^3.2.12",
"@hello-pangea/dnd": "^18.0.1", "@hello-pangea/dnd": "^18.0.1",
"@prisma/client": "^6.19.2", "@prisma/client": "^6.19.2",
"@sentry/nextjs": "^10.48.0",
"bit-buffer": "^0.3.0", "bit-buffer": "^0.3.0",
"canvas-confetti": "^1.9.4", "canvas-confetti": "^1.9.4",
"dayjs": "^1.11.20", "dayjs": "^1.11.20",

File diff suppressed because it is too large Load diff

View file

@ -1,16 +0,0 @@
// This file configures the initialization of Sentry on the server.
// The config you add here will be used whenever the server handles a request.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
tracesSampleRate: 0.1,
// Enable logs to be sent to Sentry
enableLogs: true,
// Enable sending user PII (Personally Identifiable Information)
// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
sendDefaultPii: false,
});

View file

@ -1,5 +1,4 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
import { profanity } from "@2toad/profanity"; import { profanity } from "@2toad/profanity";
import z from "zod"; import z from "zod";
@ -10,7 +9,6 @@ import { RateLimit } from "@/lib/rate-limit";
export async function PATCH(request: NextRequest) { export async function PATCH(request: NextRequest) {
const session = await auth(); const session = await auth();
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Sentry.setUser({ id: session.user?.id, name: session.user?.name });
const rateLimit = new RateLimit(request, 3); const rateLimit = new RateLimit(request, 3);
const check = await rateLimit.handle(); const check = await rateLimit.handle();
@ -29,7 +27,6 @@ export async function PATCH(request: NextRequest) {
}); });
} catch (error) { } catch (error) {
console.error("Failed to update description:", error); console.error("Failed to update description:", error);
Sentry.captureException(error, { extra: { stage: "update-about-me" } });
return rateLimit.sendResponse({ error: "Failed to update description" }, 500); return rateLimit.sendResponse({ error: "Failed to update description" }, 500);
} }

View file

@ -1,5 +1,4 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
import { auth } from "@/lib/auth"; import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma"; import { prisma } from "@/lib/prisma";
@ -8,7 +7,6 @@ import { RateLimit } from "@/lib/rate-limit";
export async function DELETE(request: NextRequest) { export async function DELETE(request: NextRequest) {
const session = await auth(); const session = await auth();
if (!session || !session.user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session || !session.user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Sentry.setUser({ id: session.user.id, name: session.user.name });
const rateLimit = new RateLimit(request, 1); const rateLimit = new RateLimit(request, 1);
const check = await rateLimit.handle(); const check = await rateLimit.handle();
@ -20,7 +18,6 @@ export async function DELETE(request: NextRequest) {
}); });
} catch (error) { } catch (error) {
console.error("Failed to delete user:", error); console.error("Failed to delete user:", error);
Sentry.captureException(error, { extra: { stage: "delete-account" } });
return rateLimit.sendResponse({ error: "Failed to delete account" }, 500); return rateLimit.sendResponse({ error: "Failed to delete account" }, 500);
} }

View file

@ -1,5 +1,4 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
import { profanity } from "@2toad/profanity"; import { profanity } from "@2toad/profanity";
import { auth } from "@/lib/auth"; import { auth } from "@/lib/auth";
@ -10,7 +9,6 @@ import { RateLimit } from "@/lib/rate-limit";
export async function PATCH(request: NextRequest) { export async function PATCH(request: NextRequest) {
const session = await auth(); const session = await auth();
if (!session || !session.user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session || !session.user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Sentry.setUser({ id: session.user.id, name: session.user.name });
const rateLimit = new RateLimit(request, 3); const rateLimit = new RateLimit(request, 3);
const check = await rateLimit.handle(); const check = await rateLimit.handle();
@ -32,7 +30,6 @@ export async function PATCH(request: NextRequest) {
}); });
} catch (error) { } catch (error) {
console.error("Failed to update name:", error); console.error("Failed to update name:", error);
Sentry.captureException(error, { extra: { stage: "update-name" } });
return rateLimit.sendResponse({ error: "Failed to update name" }, 500); return rateLimit.sendResponse({ error: "Failed to update name" }, 500);
} }

View file

@ -1,5 +1,4 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { z } from "zod"; import { z } from "zod";
@ -21,7 +20,6 @@ const formDataSchema = z.object({
export async function PATCH(request: NextRequest) { export async function PATCH(request: NextRequest) {
const session = await auth(); const session = await auth();
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Sentry.setUser({ id: session.user?.id, name: session.user?.name });
const rateLimit = new RateLimit(request, 3); const rateLimit = new RateLimit(request, 3);
const check = await rateLimit.handle(); const check = await rateLimit.handle();
@ -70,7 +68,6 @@ export async function PATCH(request: NextRequest) {
await fs.writeFile(fileLocation, pngBuffer); await fs.writeFile(fileLocation, pngBuffer);
} catch (error) { } catch (error) {
console.error("Error uploading profile picture:", error); console.error("Error uploading profile picture:", error);
Sentry.captureException(error, { extra: { stage: "upload-profile-picture" } });
return rateLimit.sendResponse({ error: "Failed to store profile picture" }, 500); return rateLimit.sendResponse({ error: "Failed to store profile picture" }, 500);
} }
@ -81,7 +78,6 @@ export async function PATCH(request: NextRequest) {
}); });
} catch (error) { } catch (error) {
console.error("Failed to update profile picture:", error); console.error("Failed to update profile picture:", error);
Sentry.captureException(error, { extra: { stage: "update-profile-picture" } });
return rateLimit.sendResponse({ error: "Failed to update profile picture" }, 500); return rateLimit.sendResponse({ error: "Failed to update profile picture" }, 500);
} }

View file

@ -1,5 +1,4 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
import fs from "fs/promises"; import fs from "fs/promises";
import path from "path"; import path from "path";
@ -14,7 +13,6 @@ const uploadsDirectory = path.join(process.cwd(), "uploads", "mii");
export async function DELETE(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { export async function DELETE(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
const session = await auth(); const session = await auth();
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Sentry.setUser({ id: session.user?.id, name: session.user?.name });
const rateLimit = new RateLimit(request, 30, "/api/mii/delete"); const rateLimit = new RateLimit(request, 30, "/api/mii/delete");
const check = await rateLimit.handle(); const check = await rateLimit.handle();
@ -44,7 +42,6 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
}); });
} catch (error) { } catch (error) {
console.error("Failed to delete Mii from database:", error); console.error("Failed to delete Mii from database:", error);
Sentry.captureException(error, { extra: { stage: "delete-mii" } });
return rateLimit.sendResponse({ error: "Failed to delete Mii" }, 500); return rateLimit.sendResponse({ error: "Failed to delete Mii" }, 500);
} }
@ -52,7 +49,6 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
await fs.rm(miiUploadsDirectory, { recursive: true, force: true }); await fs.rm(miiUploadsDirectory, { recursive: true, force: true });
} catch (error) { } catch (error) {
console.warn("Failed to delete Mii image files:", error); console.warn("Failed to delete Mii image files:", error);
Sentry.captureException(error, { extra: { stage: "delete-mii-images" } });
} }
return rateLimit.sendResponse({ success: true }); return rateLimit.sendResponse({ success: true });

View file

@ -1,7 +1,6 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
import { z } from "zod"; import { z } from "zod";
import { Mii, MiiGender, MiiMakeup, Prisma } from "@prisma/client"; import { MiiGender, MiiMakeup, Prisma } from "@prisma/client";
import fs from "fs/promises"; import fs from "fs/promises";
import path from "path"; import path from "path";
@ -46,7 +45,6 @@ const editSchema = z.object({
export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
const session = await auth(); const session = await auth();
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Sentry.setUser({ id: session.user?.id, name: session.user?.name });
const rateLimit = new RateLimit(request, 6); // no grouped pathname; edit each mii 2 times a minute const rateLimit = new RateLimit(request, 6); // no grouped pathname; edit each mii 2 times a minute
const check = await rateLimit.handle(); const check = await rateLimit.handle();
@ -192,7 +190,6 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
); );
} catch (error) { } catch (error) {
console.error("Error uploading user images:", error); console.error("Error uploading user images:", error);
Sentry.captureException(error, { extra: { stage: "edit-custom-images" } });
return rateLimit.sendResponse({ error: "Failed to store user images" }, 500); return rateLimit.sendResponse({ error: "Failed to store user images" }, 500);
} }
} }
@ -232,7 +229,6 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
); );
} catch (error) { } catch (error) {
console.error("Error uploading portrait/features images:", error); console.error("Error uploading portrait/features images:", error);
Sentry.captureException(error, { extra: { stage: "edit-portrait-features" } });
return rateLimit.sendResponse({ error: "Failed to store portrait/features images" }, 500); return rateLimit.sendResponse({ error: "Failed to store portrait/features images" }, 500);
} }
} }
@ -257,7 +253,6 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
}), }),
}).catch((err) => { }).catch((err) => {
console.error("Cloudflare cache purge failed:", err); console.error("Cloudflare cache purge failed:", err);
Sentry.captureException(err, { extra: { stage: "cloudflare-purge", miiId } });
}); });
return rateLimit.sendResponse({ success: true }); return rateLimit.sendResponse({ success: true });

View file

@ -1,5 +1,4 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
import { z } from "zod"; import { z } from "zod";
import { Prisma, ReportReason, ReportType } from "@prisma/client"; import { Prisma, ReportReason, ReportType } from "@prisma/client";
@ -19,7 +18,6 @@ const reportSchema = z.object({
export async function POST(request: NextRequest) { export async function POST(request: NextRequest) {
const session = await auth(); const session = await auth();
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Sentry.setUser({ id: session.user?.id, name: session.user?.name });
const rateLimit = new RateLimit(request, 2); const rateLimit = new RateLimit(request, 2);
const check = await rateLimit.handle(); const check = await rateLimit.handle();
@ -85,7 +83,6 @@ export async function POST(request: NextRequest) {
}); });
} catch (error) { } catch (error) {
console.error("Report creation failed", error); console.error("Report creation failed", error);
Sentry.captureException(error, { extra: { stage: "create-report" } });
return rateLimit.sendResponse({ error: "Failed to create report" }, 500); return rateLimit.sendResponse({ error: "Failed to create report" }, 500);
} }

View file

@ -1,5 +1,4 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import * as Sentry from "@sentry/nextjs";
import { z } from "zod"; import { z } from "zod";
import fs from "fs/promises"; import fs from "fs/promises";
@ -76,7 +75,6 @@ const submitSchema = z
export async function POST(request: NextRequest) { export async function POST(request: NextRequest) {
const session = await auth(); const session = await auth();
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
Sentry.setUser({ id: session.user?.id, name: session.user?.name });
const rateLimit = new RateLimit(request, 3); const rateLimit = new RateLimit(request, 3);
const check = await rateLimit.handle(); const check = await rateLimit.handle();
@ -92,9 +90,6 @@ export async function POST(request: NextRequest) {
rawTags = JSON.parse(formData.get("tags") as string); rawTags = JSON.parse(formData.get("tags") as string);
rawQrBytesRaw = JSON.parse(formData.get("qrBytesRaw") as string); rawQrBytesRaw = JSON.parse(formData.get("qrBytesRaw") as string);
} catch (error) { } catch (error) {
Sentry.captureException(error, {
extra: { stage: "submit-json-parse" },
});
return rateLimit.sendResponse({ error: "Invalid JSON in tags or QR code data" }, 400); return rateLimit.sendResponse({ error: "Invalid JSON in tags or QR code data" }, 400);
} }
@ -128,15 +123,6 @@ export async function POST(request: NextRequest) {
const firstIssue = parsed.error.issues[0]; const firstIssue = parsed.error.issues[0];
const path = firstIssue.path.length ? firstIssue.path.join(".") : "root"; const path = firstIssue.path.length ? firstIssue.path.join(".") : "root";
const error = `${path}: ${firstIssue.message}`; const error = `${path}: ${firstIssue.message}`;
const issues = parsed.error.issues;
const hasInstructionsErrors = issues.some((issue) => issue.path[0] === "instructions");
if (hasInstructionsErrors) {
Sentry.captureException(error, {
extra: { issues, rawInstructions: formData.get("instructions"), stage: "submit-instructions" },
});
}
return rateLimit.sendResponse({ error }, 400); return rateLimit.sendResponse({ error }, 400);
} }
const { const {
@ -192,7 +178,6 @@ export async function POST(request: NextRequest) {
try { try {
conversion = convertQrCode(qrBytes); conversion = convertQrCode(qrBytes);
} catch (error) { } catch (error) {
Sentry.captureException(error, { extra: { stage: "qr-conversion" } });
return rateLimit.sendResponse({ error: error instanceof Error ? error.message : String(error) }, 400); return rateLimit.sendResponse({ error: error instanceof Error ? error.message : String(error) }, 400);
} }
} }
@ -277,7 +262,6 @@ export async function POST(request: NextRequest) {
await prisma.mii.delete({ where: { id: miiRecord.id } }); await prisma.mii.delete({ where: { id: miiRecord.id } });
console.error("Failed to download/store Mii portrait/features:", error); console.error("Failed to download/store Mii portrait/features:", error);
Sentry.captureException(error, { extra: { miiId: miiRecord.id, stage: "studio-image-download" } });
return rateLimit.sendResponse({ error: "Failed to download/store Mii portrait/features" }, 500); return rateLimit.sendResponse({ error: "Failed to download/store Mii portrait/features" }, 500);
} }
@ -285,7 +269,6 @@ export async function POST(request: NextRequest) {
await generateMetadataImage(miiRecord, session.user?.name!); await generateMetadataImage(miiRecord, session.user?.name!);
} catch (error) { } catch (error) {
console.error("Failed to generate metadata image:", error); console.error("Failed to generate metadata image:", error);
Sentry.captureException(error, { extra: { miiId: miiRecord.id, stage: "metadata-image-generation" } });
} }
if (platform === "THREE_DS") { if (platform === "THREE_DS") {
@ -311,7 +294,6 @@ export async function POST(request: NextRequest) {
await prisma.mii.delete({ where: { id: miiRecord.id } }); await prisma.mii.delete({ where: { id: miiRecord.id } });
console.error("Error processing Mii files:", error); console.error("Error processing Mii files:", error);
Sentry.captureException(error, { extra: { miiId: miiRecord.id, stage: "file-processing" } });
return rateLimit.sendResponse({ error: "Failed to process and store Mii files" }, 500); return rateLimit.sendResponse({ error: "Failed to process and store Mii files" }, 500);
} }
} }
@ -339,8 +321,6 @@ export async function POST(request: NextRequest) {
}); });
} catch (error) { } catch (error) {
console.error("Error storing user images:", error); console.error("Error storing user images:", error);
Sentry.captureException(error, { extra: { miiId: miiRecord.id, stage: "user-image-storage" } });
return rateLimit.sendResponse({ error: "Failed to store user images" }, 500); return rateLimit.sendResponse({ error: "Failed to store user images" }, 500);
} }

View file

@ -1,23 +0,0 @@
"use client";
import * as Sentry from "@sentry/nextjs";
import NextError from "next/error";
import { useEffect } from "react";
export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<html lang="en">
<body>
{/* `NextError` is the default Next.js error page component. Its type
definition requires a `statusCode` prop. However, since the App Router
does not expose status codes for errors, we simply pass 0 to render a
generic error message. */}
<NextError statusCode={0} />
</body>
</html>
);
}

View file

@ -1,12 +1,15 @@
import { Metadata } from "next"; import { Metadata } from "next";
import { redirect } from "next/navigation";
import { Suspense } from "react"; import { Suspense } from "react";
import { Icon } from "@iconify/react"; import { Icon } from "@iconify/react";
import { auth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import Countdown from "@/components/countdown"; import Countdown from "@/components/countdown";
import MiiList from "@/components/mii/list"; import MiiList from "@/components/mii/list";
import Skeleton from "@/components/mii/list/skeleton"; import Skeleton from "@/components/mii/list/skeleton";
export const dynamic = "force-static";
export const revalidate = 60; export const revalidate = 60;
interface Props { interface Props {
@ -35,8 +38,19 @@ export async function generateMetadata({ searchParams }: Props): Promise<Metadat
} }
export default async function Page({ searchParams }: Props) { export default async function Page({ searchParams }: Props) {
const session = await auth();
const { page, tags } = await searchParams; const { page, tags } = await searchParams;
if (session?.user) {
const activePunishment = await prisma.punishment.findFirst({
where: {
userId: Number(session?.user.id),
returned: false,
},
});
if (activePunishment) redirect("/off-the-island");
}
return ( return (
<> <>
<h1 className="sr-only">{tags ? `Miis tagged with '${tags}' - TomodachiShare` : "TomodachiShare - index mii list"}</h1> <h1 className="sr-only">{tags ? `Miis tagged with '${tags}' - TomodachiShare` : "TomodachiShare - index mii list"}</h1>

View file

@ -10,7 +10,7 @@ export default function PrivacyPage() {
<div className="bg-amber-50 border-2 border-amber-500 rounded-2xl p-6"> <div className="bg-amber-50 border-2 border-amber-500 rounded-2xl p-6">
<h1 className="text-2xl font-bold">Privacy Policy</h1> <h1 className="text-2xl font-bold">Privacy Policy</h1>
<h2 className="font-light"> <h2 className="font-light">
<strong className="font-medium">Effective Date:</strong> 21 February 2026 <strong className="font-medium">Effective Date:</strong> 13 April 2026
</h2> </h2>
<hr className="border-black/20 mt-1 mb-4" /> <hr className="border-black/20 mt-1 mb-4" />
@ -65,23 +65,6 @@ export default function PrivacyPage() {
</p> </p>
</section> </section>
</li> </li>
<li>
<h3 className="text-xl font-semibold mt-6 mb-2">Error Reporting</h3>
<section>
<p className="mb-2">
This website uses{" "}
<a href="https://glitchtip.com/" className="text-blue-700">
GlitchTip
</a>{" "}
(a self-hosted Sentry-like instance) to monitor errors and site performance. To protect your privacy:
</p>
<ul className="list-disc list-inside ml-4">
<li>Errors and performance data is collected.</li>
<li>Only your user ID and name are sent, no other personally identifiable information is collected.</li>
<li>You can use ad blockers or browser privacy features to opt out.</li>
</ul>
</section>
</li>
<li> <li>
<h3 className="text-xl font-semibold mt-6 mb-2">Data Sharing</h3> <h3 className="text-xl font-semibold mt-6 mb-2">Data Sharing</h3>

View file

@ -1,18 +0,0 @@
// This file configures the initialization of Sentry on the client.
// The added config here will be used whenever a users loads a page in their browser.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
tracesSampleRate: 0.1,
// Enable logs to be sent to Sentry
enableLogs: true,
// Enable sending user PII (Personally Identifiable Information)
// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
sendDefaultPii: false,
});
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;

View file

@ -1,9 +0,0 @@
import * as Sentry from "@sentry/nextjs";
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
await import("../sentry.server.config");
}
}
export const onRequestError = Sentry.captureRequestError;

View file

@ -4,7 +4,6 @@
/* eslint-disable @next/next/no-img-element */ /* eslint-disable @next/next/no-img-element */
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import * as Sentry from "@sentry/nextjs";
import fs from "fs/promises"; import fs from "fs/promises";
import path from "path"; import path from "path";
@ -55,7 +54,6 @@ export async function validateImage(file: File): Promise<{ valid: boolean; error
return { valid: true }; return { valid: true };
} catch (error) { } catch (error) {
console.error("Error validating image:", error); console.error("Error validating image:", error);
Sentry.captureException(error, { extra: { stage: "image-validation" } });
return { valid: false, error: "Failed to process image file", status: 500 }; return { valid: false, error: "Failed to process image file", status: 500 };
} }
} }
@ -217,7 +215,6 @@ export async function generateMetadataImage(mii: Mii, author: string): Promise<{
await fs.writeFile(fileLocation, buffer); await fs.writeFile(fileLocation, buffer);
} catch (error) { } catch (error) {
console.error("Error storing 'metadata' image type", error); console.error("Error storing 'metadata' image type", error);
Sentry.captureException(error, { extra: { stage: "metadata-image-storage", miiId: mii.id } });
return { error: `Failed to store metadata image for ${mii.id}`, status: 500 }; return { error: `Failed to store metadata image for ${mii.id}`, status: 500 };
} }

View file

@ -1,6 +1,5 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import { createClient, RedisClientType } from "redis"; import { createClient, RedisClientType } from "redis";
import * as Sentry from "@sentry/nextjs";
import { auth } from "./auth"; import { auth } from "./auth";
const WINDOW_SIZE = 60; const WINDOW_SIZE = 60;
@ -20,7 +19,6 @@ async function getRedisClient() {
}); });
client.on("error", (error) => { client.on("error", (error) => {
console.error("Redis client error", error); console.error("Redis client error", error);
Sentry.captureException(error, { tags: { source: "redis-client" } });
}); });
await client.connect(); await client.connect();
} }
@ -71,7 +69,6 @@ export class RateLimit {
return { success, limit: this.maxRequests, remaining, expires: expireAt }; return { success, limit: this.maxRequests, remaining, expires: expireAt };
} catch (error) { } catch (error) {
console.error("Rate limit check failed", error); console.error("Rate limit check failed", error);
Sentry.captureException(error, { tags: { source: "rate-limit-check" } });
return { return {
success: false, success: false,
limit: this.maxRequests, limit: this.maxRequests,