Compare commits

..

31 Commits

Author SHA1 Message Date
73b6c85171 ow my formatting
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m35s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-05-11 00:52:14 -04:00
037eb7fcac Possibly fix appeals? 2026-05-11 00:51:51 -04:00
abc1389dbb Bump dependencies 2026-05-11 00:51:40 -04:00
cd566248fd Bump node version 2026-05-11 00:51:09 -04:00
3d7e499ec1 Create data requests table 2026-05-06 03:18:57 -04:00
40dd0b5a5c Remove data transfer code
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m25s
Test, Build, Deploy / Create Sentry Release (push) Successful in 7s
2026-04-29 02:05:08 -04:00
229398e401 Disable button while event is submitting
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 58s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-17 01:47:42 -04:00
a9863f5680 Remove unneeded unix time param
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 55s
Test, Build, Deploy / Create Sentry Release (push) Successful in 9s
2026-04-16 04:08:20 -04:00
2e76bd9f28 Make buttons hide again when performed_at is not null
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m7s
Test, Build, Deploy / Create Sentry Release (push) Successful in 7s
2026-04-16 03:52:40 -04:00
171240bc7d Add db setup migration
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m1s
Test, Build, Deploy / Create Sentry Release (push) Successful in 7s
2026-04-15 02:45:39 -04:00
ffce17d7aa Add more stuff to gitignore 2026-04-15 02:43:38 -04:00
06fdfe9d10 Log appeal denials
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m8s
Test, Build, Deploy / Create Sentry Release (push) Successful in 7s
2026-04-14 22:09:43 -04:00
ba643bf986 Apparently these are causing problems
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m1s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-14 04:16:45 -04:00
12f91dca7d Move input button styles hook to top level
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m2s
Test, Build, Deploy / Create Sentry Release (push) Successful in 5s
2026-04-14 03:49:06 -04:00
b6de1aa462 Change order of state changes
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m2s
Test, Build, Deploy / Create Sentry Release (push) Successful in 5s
2026-04-14 03:44:06 -04:00
b65b62dac5 Upload functions sourcemaps from CI 2026-04-14 03:36:42 -04:00
0ec5399726 Accept multiple input files again
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m1s
Test, Build, Deploy / Create Sentry Release (push) Successful in 5s
2026-04-14 03:25:09 -04:00
f0c4e178aa Actually hide border this time
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m0s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-14 03:21:11 -04:00
6ad4fa0514 Remove outline from input
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m1s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-14 03:16:16 -04:00
42275fcb0f Remove old button 2026-04-14 03:15:08 -04:00
0854d72449 Try new way of fixing this nonsense
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m3s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-14 03:11:32 -04:00
cb0be09c0d Use react state to keep track of file names
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m2s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-14 02:07:15 -04:00
16ecab6881 Fix safari annoyingness
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m2s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-14 01:48:37 -04:00
7d5ec1183c Bump node version
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m20s
Test, Build, Deploy / Create Sentry Release (push) Successful in 5s
2026-04-14 00:23:24 -04:00
96d221be2a Fix this one too 2026-04-14 00:20:57 -04:00
f5e3e3cca6 Add messaging service publish method
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 59s
Test, Build, Deploy / Create Sentry Release (push) Successful in 5s
2026-04-13 03:04:02 -04:00
2d9f03c394 Fix weird token element null issue
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 1m0s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-13 02:46:17 -04:00
c51b29ce57 Upload sourcemaps to pages 2026-04-13 02:45:58 -04:00
546842c4dd These need to still be parsed
All checks were successful
Test, Build, Deploy / Test, Build, and Deploy (push) Successful in 58s
Test, Build, Deploy / Create Sentry Release (push) Successful in 6s
2026-04-12 01:34:32 -04:00
1f2a8770a1 Set keys on list elements 2026-04-12 01:30:18 -04:00
4b15c65092 Spit out as text in error console 2026-04-12 01:13:59 -04:00
30 changed files with 499 additions and 751 deletions

View File

@@ -56,7 +56,7 @@ jobs:
}'
- name: Deploy
run: wrangler pages deploy public --project-name $CLOUDFLARE_PROJECT_NAME
run: wrangler pages deploy public --upload-source-maps --project-name $CLOUDFLARE_PROJECT_NAME
Sentry-Release:
name: Create Sentry Release

2
.gitignore vendored
View File

@@ -37,5 +37,7 @@ public/build
# Wrangler data
.wrangler
wrangler.jsonc
wrangler.toml
/generated/prisma

View File

@@ -1 +1 @@
v24.14.0
v24.15.0

View File

@@ -45,6 +45,7 @@ export async function loader({ context }: { context: RequestContext }) {
id: true,
},
where: {
approved: null,
user: {
path: "id",
equals: currentUser.id,

View File

@@ -44,6 +44,7 @@ export default function () {
const [eventType, setEventType] = useState("");
const [riddleAnswer, setRiddleAnswer] = useState("");
const [submitSuccess, setSubmitSuccess] = useState(false);
const [disableSubmit, setDisableSubmit] = useState(false);
useEffect(() => {
setDatePickerMin(`${new Date().toISOString().split("T").at(0)}`);
@@ -53,6 +54,7 @@ export default function () {
}, []);
async function submit() {
setDisableSubmit(true);
let eventResp: Response;
try {
@@ -69,6 +71,7 @@ export default function () {
method: "POST",
});
} catch {
setDisableSubmit(false);
toast({
description: "Please check your internet and try again",
isClosable: true,
@@ -86,6 +89,7 @@ export default function () {
errorMessage = ((await eventResp.json()) as { error: string }).error;
} catch {}
setDisableSubmit(false);
toast({
description: errorMessage,
isClosable: true,
@@ -150,7 +154,11 @@ export default function () {
onChange={(e) => setRiddleAnswer(e.target.value)}
placeholder="Riddle answer"
/>
<Button mt="16px" onClick={async () => await submit()}>
<Button
disabled={disableSubmit}
mt="16px"
onClick={async () => await submit()}
>
Book
</Button>
</Container>

View File

@@ -1,42 +0,0 @@
import { Button, Container, Heading, Text } from "@chakra-ui/react";
export default function () {
return (
<Container maxW="container.md">
<Heading size="lg">Transfer your Save Data</Heading>
<br />
<br />
<Text>Lost your account? Want to shake off a stalker?</Text>
<br />
<br />
<Text size="lg">We can help!</Text>
<br />
<br />
<Text>Some information you should know:</Text>
<br />
<Text>
We might require your .ROBLOSECURITY cookie, depending on your
circumstances. This is because Roblox does not allow terminated accounts
to utilize OAuth. Normally this would be a very bad idea, and we don't
like doing this either, but it may be the only option. Security is also
less of a concern for terminated accounts as they are blocked from
accessing almost all Roblox API endpoints (the exceptions being login,
logout, and creating support tickets - and only the logout endpoint
doesn't require completing a captcha). If you are concerned about your
account's security, we suggest logging in to your terminated account in
a private/incognito window, copying the .ROBLOSECURITY cookie from
there, and logging out once we have verified your old account (which
normally only takes a few seconds). The ultra paranoid may also consider
resetting their password. If you are not convinced or still have
questions, join our Discord server (link is on the about page) and open
a ticket with ModMail for us to verify you manually (no cookie
required).
</Text>
<br />
<br />
<Button as="a" href="/data-transfer/start" colorScheme="blue">
Start my Transfer
</Button>
</Container>
);
}

View File

@@ -1,10 +0,0 @@
import Success from "../../components/Success.js";
export default function () {
return (
<Success
heading="Data Transfer Submitted"
message="Your request is now being processed; this normally takes 1-2 weeks."
/>
);
}

View File

@@ -1,34 +0,0 @@
import { Button, Card, Container, Heading, VStack } from "@chakra-ui/react";
import { useLoaderData } from "@remix-run/react";
export async function loader({ context }: { context: RequestContext }) {
const { host, protocol } = new URL(context.request.url);
return { client_id: context.env.ROBLOX_OAUTH_CLIENT_ID, host, protocol };
}
export default function () {
const loaderData = useLoaderData<typeof loader>();
return (
<Container pt="16vh">
<Card borderRadius="32px" p="4vh">
<VStack alignContent="center" gap="2vh">
<Heading>Verify your new Roblox account</Heading>
<br />
<Button
as="a"
borderRadius="24px"
colorScheme="blue"
href={`https://apis.roblox.com/oauth/v1/authorize?client_id=${
loaderData.client_id
}&redirect_uri=${encodeURIComponent(
`${loaderData.protocol}//${loaderData.host}/api/data-transfers/verify`,
)}&response_type=code&scope=openid%20profile`}
>
Verify
</Button>
</VStack>
</Card>
</Container>
);
}

View File

@@ -1,81 +0,0 @@
import {
Button,
Container,
Heading,
HStack,
Radio,
RadioGroup,
Text,
Textarea,
useToast,
} from "@chakra-ui/react";
import { useState } from "react";
export default function () {
const [showCookieBox, setShowCookieBox] = useState(false);
const [loading, setLoading] = useState(false);
return (
<Container maxW="container.md">
<Heading pt="36px">Let's get started</Heading>
<Text pt="128px">Is your old Roblox account banned?</Text>
<RadioGroup onChange={(val) => setShowCookieBox(JSON.parse(val))}>
<HStack>
<Radio value="false">No</Radio>
<Radio value="true">Yes</Radio>
</HStack>
</RadioGroup>
<Textarea
id="cookie-box"
placeholder="Paste your .ROBLOSECURITY cookie here"
mt="16px"
style={{ display: showCookieBox ? "initial" : "none" }}
/>
<Button
colorScheme="blue"
isLoading={loading}
loadingText="Processing..."
mt="16px"
onClick={async () => {
setLoading(true);
const createTransferReq = await fetch("/api/data-transfers/create", {
body: JSON.stringify({
can_access: !showCookieBox,
cookie: (
document.getElementById("cookie-box") as HTMLInputElement
).value,
}),
headers: {
"content-type": "application/json",
},
method: "POST",
});
if (!createTransferReq.ok) {
setLoading(false);
useToast()({
description: (
(await createTransferReq.json()) as { error: string }
).error,
isClosable: true,
status: "error",
title: "Failed to create transfer request",
});
return;
}
location.assign(
((await createTransferReq.json()) as { url: string }).url,
);
}}
>
Continue
</Button>
<br />
<Text pt="16px">
If you cannot login at all, please visit the support page and join our
server.
</Text>
</Container>
);
}

View File

@@ -271,7 +271,7 @@ export default function () {
// Technically this won't be the same as the time in the db, but that doesn't matter since this is just to hide the button
newEventData[eventData.findIndex((e) => e.id === eventId)].performed_at =
Date.now();
new Date().toISOString();
setEventData([...newEventData]);
setSelectedEvent("");
@@ -313,7 +313,8 @@ export default function () {
const newEventData = eventData;
newEventData[eventData.findIndex((e) => e.id === eventId)].performed_at = 0;
newEventData[eventData.findIndex((e) => e.id === eventId)].performed_at =
new Date(0).toISOString();
setEventData([...newEventData]);
setSelectedEvent("");
setDisableClicks(false);
@@ -664,9 +665,7 @@ export default function () {
</Button>
</>
) : null}
{can_approve &&
!event.pending &&
typeof event.performed_at !== "number" ? (
{can_approve && !event.pending && !event.performed_at ? (
<>
<Button
colorScheme="blue"

View File

@@ -268,6 +268,7 @@ export default function () {
element: (
<AppealCard
{...(entry as AppealCardProps & { port?: MessagePort })}
key={`appeal_${entry.id}`}
port={messageChannel.current?.port2}
/>
),
@@ -281,6 +282,7 @@ export default function () {
element: (
<GameAppealCard
{...(entry as GameAppealProps & { port?: MessagePort })}
key={`gma_${entry.id}`}
port={messageChannel.current?.port2}
/>
),
@@ -294,6 +296,7 @@ export default function () {
element: (
<InactivityNoticeCard
{...(entry as InactivityNoticeProps & { port?: MessagePort })}
key={`inactivity_${entry.id}`}
port={messageChannel.current?.port2}
/>
),
@@ -307,6 +310,7 @@ export default function () {
element: (
<ReportCard
{...(entry as ReportCardProps & { port?: MessagePort })}
key={`report_${entry.id}`}
port={messageChannel.current?.port2}
/>
),

View File

@@ -14,6 +14,7 @@ import {
Stack,
Text,
Textarea,
useMultiStyleConfig,
useToast,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
@@ -50,6 +51,9 @@ export default function () {
const toast = useToast();
const [uploading, setUploading] = useState(false);
const [loading, setLoading] = useState(false);
const inputSelectorProps = useMultiStyleConfig("Button", {
colorScheme: "blue",
});
const fileTypes: { [k: string]: string } = {
avif: "image/avif",
gif: "image/gif",
@@ -112,9 +116,9 @@ export default function () {
if (!logged_in) {
const tokenElem = document
.getElementsByName("cf-turnstile-response")
.item(0) as HTMLInputElement;
.item(0) as HTMLInputElement | null;
if (!tokenElem.value) {
if (!tokenElem?.value) {
setLoading(false);
return toast({
description: "Please complete the captcha and try again",
@@ -250,8 +254,8 @@ export default function () {
method: "POST",
});
setShowSuccess(true);
setLoading(false);
setShowSuccess(true);
}
useEffect(() => {
@@ -304,14 +308,19 @@ export default function () {
<br />
<FormControl isRequired>
<FormLabel>Your Evidence (Max size per file: 512MB)</FormLabel>
<Button
colorScheme="blue"
mr="8px"
onClick={() => document.getElementById("evidence")?.click()}
>
Select File
</Button>
<input id="evidence" multiple type="file" />
<Input
border="none"
id="evidence"
sx={{
"::file-selector-button": {
border: "none",
outline: "none",
...inputSelectorProps,
},
}}
multiple={true}
type="file"
/>
</FormControl>
<br />
<FormControl>

View File

@@ -91,7 +91,7 @@ export default function (props: { isOpen: boolean; onClose: () => void }) {
</Thead>
<Tbody>
{entries.map((entry) => (
<Tr>
<Tr key={`appealban_${entry.user}`}>
<Td>{entry.user}</Td>
<Td>{entry.created_by}</Td>
<Td>{new Date(entry.created_at).toUTCString()}</Td>

View File

@@ -173,7 +173,6 @@ export default function (props: {
)}
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="currentColor"
@@ -223,7 +222,6 @@ export default function (props: {
{data.id ? data.username : ""}
</Text>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="currentColor"

View File

@@ -17,13 +17,7 @@ export default function ({
>
<Flex>
<Spacer />
<svg
xmlns="http://www.w3.org/2000/svg"
width="128"
height="128"
fill="currentColor"
viewBox="0 0 16 16"
>
<svg width="128" height="128" fill="currentColor" viewBox="0 0 16 16">
<path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0z" />
<path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l7-7z" />
</svg>

View File

@@ -1,19 +0,0 @@
export async function onRequest(context: RequestContext) {
const cookies = context.request.headers.get("cookie");
if (!cookies) return await context.next();
const cookieList = cookies.split("; ").map((cookie: string) => {
const [name, value] = cookie.split("=");
return { name, value };
});
const transferId = cookieList.find(
(cookie: { name: string; value: string }) => cookie.name === "__dtid",
);
if (transferId) context.data.data_transfer_id = transferId;
return await context.next();
}

View File

@@ -1,74 +0,0 @@
import { jsonError } from "../../common.js";
export async function onRequestPost(context: RequestContext) {
const { cookie, is_banned } = context.data.body;
if (
typeof is_banned !== "boolean" ||
(is_banned && typeof cookie !== "string") ||
(is_banned &&
!cookie.match(
/_\|WARNING:-DO-NOT-SHARE-THIS\.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items\.\|_[A-F\d]+/,
))
)
return jsonError("Invalid request", 400);
const id =
(context.request.headers.get("cf-ray")?.split("-")[0] as string) +
Date.now().toString() +
crypto.randomUUID().replaceAll("-", "");
if (!is_banned) {
await context.env.DATA.put(`datatransfer_${id}`, "{}", {
expirationTtl: 3600,
});
const host = context.request.headers.get("Host") as string;
return new Response(
`{"url":"https://apis.roblox.com/oauth/v1/authorize?client_id=${
context.env.ROBLOX_OAUTH_CLIENT_ID
}&redirect_uri=${encodeURIComponent(
`http${host.startsWith(
"localhost" ? "" : "s",
)}://${host}/api/data-transfers/verify`,
)}"}`,
{
headers: {
"set-cookie": `__dtid=${id}; HttpOnly; Max-Age=3600; Path=/; SameSite=Lax; Secure`,
},
},
);
}
const authedUserReq = await fetch(
"https://users.roblox.com/v1/users/authenticated",
{
headers: {
cookie: `.ROBLOSECURITY=${cookie}`,
},
},
);
if (!authedUserReq.ok) return jsonError("Cookie is invalid", 400);
const authedUser: { id: number; name: string } = await authedUserReq.json();
await context.env.DATA.put(
`datatransfer_${id}`,
JSON.stringify({
oldUser: authedUser,
}),
{
expirationTtl: 3600,
},
);
return new Response(null, {
headers: {
location: "/data-transfer/destination-account",
"set-cookie": `__dtid=${id}; HttpOnly; Max-Age=3600; Path=/; SameSite=Lax; Secure`,
},
status: 201,
});
}

View File

@@ -1,92 +0,0 @@
import { jsonError } from "../../common.js";
import { getBanList } from "../../roblox-open-cloud.js";
export async function onRequestGet(context: RequestContext) {
const code = new URL(context.request.url).searchParams.get("code");
if (!code) return jsonError("Missing code", 400);
const dataTransferData = (await context.env.DATA.get(
`datatransfer_${context.data.data_transfer_id}`,
{ type: "json" },
)) as { [k: string]: any } | null;
if (!dataTransferData)
return jsonError("No transfer exists with that ID", 404);
const exchangeReq = await fetch("https://apis.roblox.com/oauth/v1/token", {
body: `code=${code}&grant_type=authorization_code`,
headers: {
authorization: `Basic ${
btoa(context.env.ROBLOX_OAUTH_ID) +
":" +
context.env.ROBLOX_OAUTH_SECRET
}`,
"content-type": "application/x-www-form-urlencoded",
},
method: "POST",
});
if (!exchangeReq.ok) return jsonError("Failed to redeem code", 500);
const { id_token } = (await exchangeReq.json()) as { id_token: string };
const { name, preferred_username, sub } = JSON.parse(
atob(id_token.replaceAll("-", "+").replaceAll("_", "/")),
);
if (!preferred_username) return jsonError("Username missing", 500);
const userObj = {
displayName: name,
id: parseInt(sub),
name: preferred_username,
};
let redirectLocation = "/data-transfer/complete";
if (dataTransferData.oldUser) {
let banList;
try {
banList = (await getBanList(context)).value;
} catch {
return jsonError("Failed to create data transfer request", 500);
}
if (banList[userObj.id].BanType)
return new Response(null, {
headers: {
location: redirectLocation,
},
status: 302,
});
dataTransferData.newUser = userObj;
await fetch(
`https://api.trello.com/1/cards?key=${context.env.TRELLO_API_KEY}&token=${context.env.TRELLO_API_TOKEN}`,
{
body: JSON.stringify({
desc: `${dataTransferData.oldUser.name} -> ${userObj.name}\n${dataTransferData.oldUser.id} -> ${userObj.id}\nNO MODMAIL TICKET - WEBSITE FORM SUBMISSION`,
idList: context.env.TRELLO_LIST_ID,
name: `${dataTransferData.oldUser.name} | Data Transfer`,
}),
headers: {
"content-type": "application/json",
},
method: "POST",
},
);
} else {
dataTransferData.oldUser = userObj;
redirectLocation = "/data-transfer/destination-account";
}
return new Response(null, {
headers: {
location: redirectLocation,
},
status: 302,
});
}

View File

@@ -23,7 +23,7 @@ export async function onRequestPost(context: RequestContext) {
await D1.batch([
D1.prepare(
"UPDATE events SET performed_at = CURRENT_TIMESTAMP WHERE id = ?;",
).bind(Date.now(), event.id),
).bind(event.id),
D1.prepare(
"UPDATE et_members SET points = points + 10 WHERE id = ?;",
).bind(event.created_by),

View File

@@ -1,10 +1,12 @@
import { jsonError } from "../../../common.js";
import { getBanList } from "../../../roblox-open-cloud.js";
export async function onRequestPost(context: RequestContext) {
const appealId = context.params.id as string;
const appeal = await context.data.prisma.gameAppeal.findUnique({
select: {
roblox_id: true,
type: true,
},
where: {
id: appealId,
@@ -19,6 +21,18 @@ export async function onRequestPost(context: RequestContext) {
},
});
const { value: banList } = await getBanList(context);
await context.data.prisma.gameModLog.create({
data: {
action: `deny appeal | ${banList[appeal.roblox_id]?.BanType === 2 ? "ban" : appeal.type}`,
evidence: `https://carcrushers.cc/mod-queue?id=${context.params.id}&type=gma`,
executor: context.data.current_user.id,
id: crypto.randomUUID(),
target: appeal.roblox_id,
},
});
await context.env.DATA.put(
`gameappealblock_${appeal.roblox_id}`,
`${Date.now() + 2592000000}`,

View File

@@ -17,7 +17,7 @@ export async function onRequestGet(context: RequestContext) {
);
if (!robloxUserReq.ok) {
console.log(await robloxUserReq.json());
console.log(await robloxUserReq.text());
return jsonError("Failed to resolve username", 500);
}

View File

@@ -1,5 +1,5 @@
import { jsonError, jsonResponse } from "../../../common.js";
import { JsonObject } from "../../../../generated/prisma/internal/prismaNamespace.js";
import { type JsonObject } from "../../../../generated/prisma/internal/prismaNamespace.js";
export async function onRequestGet(context: RequestContext) {
const types: { [k: string]: number[] } = {
@@ -53,7 +53,7 @@ export async function onRequestGet(context: RequestContext) {
},
});
if (item) delete (item.user as JsonObject).email;
if (item) delete (item.user as JsonObject | null)?.email;
break;
default:

View File

@@ -76,6 +76,11 @@ export async function onRequestGet(context: RequestContext): Promise<any> {
SELECT *, (SELECT COUNT(*) FROM json_each(decisions)) AS decision_count FROM inactivity_notices WHERE created_at < datetime(${before} / 1000, 'unixepoch') AND decision_count ${showClosed ? raw("=") : raw("!=")} json_array_length(departments);`;
rows.map((r) => {
// These come back as strings when using $queryRaw
r.decisions = JSON.parse(r.decisions as string);
r.departments = JSON.parse(r.departments as string);
r.user = JSON.parse(r.user as string);
delete (r.user as JsonObject).email;
return r;

View File

@@ -1,6 +1,9 @@
const DATASTORE_URL =
"https://apis.roblox.com/cloud/v2/universes/274816972/data-stores/BanData/entries/CloudBanList";
const MESSAGING_SERVICE_URL =
"https://apis.roblox.com/cloud/v2/universes/274816972:publishMessage";
const SAVE_DATA_URL =
"https://apis.roblox.com/cloud/v2/universes/274816972/data-stores/RealData/entries";
@@ -31,6 +34,28 @@ export async function getBanList(context: RequestContext) {
};
}
export async function publishMessage(
context: RequestContext,
topic: string,
message: string,
) {
const response = await fetch(MESSAGING_SERVICE_URL, {
body: JSON.stringify({
message,
topic,
}),
headers: {
"Content-Type": "application/json",
"x-api-key": context.env.ROBLOX_OPENCLOUD_KEY,
},
method: "POST",
});
if (!response.ok) {
throw new Error("Failed to publish message\n" + (await response.text()));
}
}
export async function getSaveData(
context: RequestContext,
user: number,

View File

@@ -70,10 +70,6 @@ button:focus-visible {
padding: 2em;
}
::file-selector-button {
display: none;
}
.desktop-nav {
visibility: visible;
}

View File

@@ -0,0 +1,186 @@
-- CreateTable
CREATE TABLE "appeals" (
"approved" BOOLEAN,
"ban_reason" TEXT NOT NULL,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"id" TEXT NOT NULL PRIMARY KEY,
"learned" TEXT NOT NULL,
"reason_for_unban" TEXT NOT NULL,
"user" JSONB NOT NULL
);
-- CreateTable
CREATE TABLE "appeal_bans" (
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" TEXT NOT NULL,
"user" TEXT NOT NULL PRIMARY KEY
);
-- CreateTable
CREATE TABLE "et_members" (
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" TEXT NOT NULL,
"id" TEXT NOT NULL PRIMARY KEY,
"is_management" BOOLEAN NOT NULL DEFAULT false,
"name" TEXT NOT NULL,
"points" INTEGER NOT NULL DEFAULT 0,
"roblox_id" INTEGER
);
-- CreateTable
CREATE TABLE "et_strikes" (
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" TEXT NOT NULL,
"id" TEXT NOT NULL PRIMARY KEY,
"reason" TEXT NOT NULL,
"user" TEXT NOT NULL
);
-- CreateTable
CREATE TABLE "events" (
"answer" TEXT,
"answered_at" DATETIME,
"approved" BOOLEAN NOT NULL DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" TEXT NOT NULL,
"day" INTEGER NOT NULL,
"details" TEXT NOT NULL,
"id" TEXT NOT NULL PRIMARY KEY,
"month" INTEGER NOT NULL,
"pending" BOOLEAN NOT NULL DEFAULT true,
"performed_at" DATETIME,
"reached_minimum_player_count" BOOLEAN NOT NULL DEFAULT false,
"type" TEXT NOT NULL,
"year" INTEGER NOT NULL
);
-- CreateTable
CREATE TABLE "game_appeals" (
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"id" TEXT NOT NULL PRIMARY KEY,
"reason_for_unban" TEXT NOT NULL,
"roblox_id" INTEGER NOT NULL,
"roblox_username" TEXT NOT NULL,
"type" TEXT NOT NULL,
"what_happened" TEXT NOT NULL
);
-- CreateTable
CREATE TABLE "game_mod_logs" (
"action" TEXT NOT NULL,
"evidence" TEXT NOT NULL,
"executed_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"executor" TEXT NOT NULL,
"id" TEXT NOT NULL PRIMARY KEY,
"target" INTEGER NOT NULL
);
-- CreateTable
CREATE TABLE "game_mod_notes" (
"content" TEXT NOT NULL,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" TEXT NOT NULL,
"id" TEXT NOT NULL PRIMARY KEY,
"target" INTEGER NOT NULL
);
-- CreateTable
CREATE TABLE "inactivity_notices" (
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"decisions" JSONB NOT NULL,
"departments" JSONB NOT NULL DEFAULT [],
"end" TEXT NOT NULL,
"hiatus" BOOLEAN NOT NULL DEFAULT false,
"id" TEXT NOT NULL PRIMARY KEY,
"reason" TEXT NOT NULL,
"start" TEXT NOT NULL,
"user" JSONB NOT NULL
);
-- CreateTable
CREATE TABLE "push_notifications" (
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"event_id" TEXT NOT NULL,
"event_type" TEXT NOT NULL,
"token" TEXT NOT NULL
);
-- CreateTable
CREATE TABLE "reports" (
"attachments" JSONB NOT NULL DEFAULT [],
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"id" TEXT NOT NULL PRIMARY KEY,
"open" BOOLEAN NOT NULL DEFAULT true,
"target_ids" JSONB NOT NULL DEFAULT [],
"target_usernames" JSONB NOT NULL DEFAULT [],
"type" TEXT NOT NULL DEFAULT 'exploit',
"user" JSONB
);
-- CreateTable
CREATE TABLE "short_links" (
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"destination" TEXT NOT NULL,
"path" TEXT NOT NULL PRIMARY KEY,
"user" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "appeals_id_key" ON "appeals"("id");
-- CreateIndex
CREATE INDEX "idx_appeals_approved_created_at" ON "appeals"("approved", "created_at");
-- CreateIndex
CREATE UNIQUE INDEX "appeal_bans_user_key" ON "appeal_bans"("user");
-- CreateIndex
CREATE UNIQUE INDEX "et_members_id_key" ON "et_members"("id");
-- CreateIndex
CREATE INDEX "idx_et_members_id_name" ON "et_members"("id", "name");
-- CreateIndex
CREATE UNIQUE INDEX "et_strikes_id_key" ON "et_strikes"("id");
-- CreateIndex
CREATE UNIQUE INDEX "events_id_key" ON "events"("id");
-- CreateIndex
CREATE INDEX "idx_events_month_year" ON "events"("month", "year");
-- CreateIndex
CREATE UNIQUE INDEX "game_appeals_id_key" ON "game_appeals"("id");
-- CreateIndex
CREATE INDEX "idx_game_appeals_created_at" ON "game_appeals"("created_at");
-- CreateIndex
CREATE UNIQUE INDEX "game_mod_logs_id_key" ON "game_mod_logs"("id");
-- CreateIndex
CREATE INDEX "idx_game_mod_logs_target" ON "game_mod_logs"("target");
-- CreateIndex
CREATE UNIQUE INDEX "game_mod_notes_id_key" ON "game_mod_notes"("id");
-- CreateIndex
CREATE INDEX "idx_game_mod_notes_target" ON "game_mod_notes"("target");
-- CreateIndex
CREATE UNIQUE INDEX "inactivity_notices_id_key" ON "inactivity_notices"("id");
-- CreateIndex
CREATE INDEX "idx_inactivity_notices_end_start" ON "inactivity_notices"("end", "start");
-- CreateIndex
CREATE UNIQUE INDEX "push_notifications_event_id_key" ON "push_notifications"("event_id");
-- CreateIndex
CREATE UNIQUE INDEX "reports_id_key" ON "reports"("id");
-- CreateIndex
CREATE INDEX "idx_reports_created_at_open" ON "reports"("created_at", "open");
-- CreateIndex
CREATE UNIQUE INDEX "short_links_path_key" ON "short_links"("path");

View File

@@ -0,0 +1,15 @@
-- CreateTable
CREATE TABLE "data_requests" (
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"id" TEXT NOT NULL PRIMARY KEY,
"originating_user" INTEGER,
"status" TEXT NOT NULL,
"target_user" INTEGER NOT NULL,
"type" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "data_requests_id_key" ON "data_requests"("id");
-- CreateIndex
CREATE INDEX "idx_data_requests_created_at" ON "data_requests"("created_at");

538
package-lock.json generated
View File

@@ -12,13 +12,13 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@fontsource-variable/plus-jakarta-sans": "^5.2.8",
"@prisma/adapter-d1": "^7.7.0",
"@prisma/client": "^7.7.0",
"@prisma/adapter-d1": "^7.8.0",
"@prisma/client": "^7.8.0",
"@remix-run/cloudflare": "^2.17.4",
"@remix-run/cloudflare-pages": "^2.17.4",
"@remix-run/react": "^2.17.4",
"@sentry/cloudflare": "^10.48.0",
"@sentry/remix": "^10.48.0",
"@sentry/cloudflare": "^10.52.0",
"@sentry/remix": "^10.52.0",
"aws4fetch": "^1.0.20",
"dayjs": "^1.11.20",
"framer-motion": "^12.38.0",
@@ -28,13 +28,13 @@
},
"devDependencies": {
"@remix-run/dev": "^2.17.4",
"@types/node": "^24.12.2",
"@types/node": "^24.12.3",
"@types/react": "^18.3.28",
"@types/react-big-calendar": "^1.16.3",
"@types/react-dom": "^18.3.7",
"dotenv": "^17.4.1",
"prettier": "^3.8.2",
"prisma": "^7.7.0",
"prettier": "^3.8.3",
"prisma": "^7.8.0",
"typescript": "^5.9.3"
}
},
@@ -569,9 +569,9 @@
}
},
"node_modules/@cloudflare/workers-types": {
"version": "4.20260329.1",
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260329.1.tgz",
"integrity": "sha512-LxBHrYYI/AZ6OCbUzRqRgg6Rt1qev2KxN2NNd3saye41AO2g52cYvHV+ohts5oPnrIUD7YRjbgN/J3NU7e7m5A==",
"version": "4.20260511.1",
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260511.1.tgz",
"integrity": "sha512-FA+si7cOq9i/gtCHhIc0XJL0l1F/ApF+m00752Aj7WZFJrj3ZulT2T8/+rT3BabMT0QEnqFEGIqCgrmqhgEfMg==",
"license": "MIT OR Apache-2.0"
},
"node_modules/@electric-sql/pglite": {
@@ -1177,9 +1177,9 @@
}
},
"node_modules/@fastify/otel/node_modules/brace-expansion": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
@@ -1413,22 +1413,10 @@
"node": ">=8.0.0"
}
},
"node_modules/@opentelemetry/context-async-hooks": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.6.1.tgz",
"integrity": "sha512-XHzhwRNkBpeP8Fs/qjGrAf9r9PRv67wkJQ/7ZPaBQQ68DYlTBBx5MF9LvPx7mhuXcDessKK2b+DcxqwpgkcivQ==",
"license": "Apache-2.0",
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.10.0"
}
},
"node_modules/@opentelemetry/core": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.1.tgz",
"integrity": "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz",
"integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/semantic-conventions": "^1.29.0"
@@ -1588,21 +1576,19 @@
"@opentelemetry/api": "^1.3.0"
}
},
"node_modules/@opentelemetry/instrumentation-ioredis": {
"version": "0.62.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.62.0.tgz",
"integrity": "sha512-ZYt//zcPve8qklaZX+5Z4MkU7UpEkFRrxsf2cnaKYBitqDnsCN69CPAuuMOX6NYdW2rG9sFy7V/QWtBlP5XiNQ==",
"node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.1.tgz",
"integrity": "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/instrumentation": "^0.214.0",
"@opentelemetry/redis-common": "^0.38.2",
"@opentelemetry/semantic-conventions": "^1.33.0"
"@opentelemetry/semantic-conventions": "^1.29.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": "^1.3.0"
"@opentelemetry/api": ">=1.0.0 <1.10.0"
}
},
"node_modules/@opentelemetry/instrumentation-kafkajs": {
@@ -1756,23 +1742,6 @@
"@opentelemetry/api": "^1.3.0"
}
},
"node_modules/@opentelemetry/instrumentation-redis": {
"version": "0.62.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.62.0.tgz",
"integrity": "sha512-y3pPpot7WzR/8JtHcYlTYsyY8g+pbFhAqbwAuG5bLPnR6v6pt1rQc0DpH0OlGP/9CZbWBP+Zhwp9yFoygf/ZXQ==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/instrumentation": "^0.214.0",
"@opentelemetry/redis-common": "^0.38.2",
"@opentelemetry/semantic-conventions": "^1.27.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": "^1.3.0"
}
},
"node_modules/@opentelemetry/instrumentation-tedious": {
"version": "0.33.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.33.0.tgz",
@@ -1790,39 +1759,13 @@
"@opentelemetry/api": "^1.3.0"
}
},
"node_modules/@opentelemetry/instrumentation-undici": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.24.0.tgz",
"integrity": "sha512-oKzZ3uvqP17sV0EsoQcJgjEfIp0kiZRbYu/eD8p13Cbahumf8lb/xpYeNr/hfAJ4owzEtIDcGIjprfLcYbIKBQ==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "^2.0.0",
"@opentelemetry/instrumentation": "^0.214.0",
"@opentelemetry/semantic-conventions": "^1.24.0"
},
"engines": {
"node": "^18.19.0 || >=20.6.0"
},
"peerDependencies": {
"@opentelemetry/api": "^1.7.0"
}
},
"node_modules/@opentelemetry/redis-common": {
"version": "0.38.2",
"resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.38.2.tgz",
"integrity": "sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==",
"license": "Apache-2.0",
"engines": {
"node": "^18.19.0 || >=20.6.0"
}
},
"node_modules/@opentelemetry/resources": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.1.tgz",
"integrity": "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.1.tgz",
"integrity": "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "2.6.1",
"@opentelemetry/core": "2.7.1",
"@opentelemetry/semantic-conventions": "^1.29.0"
},
"engines": {
@@ -1833,13 +1776,13 @@
}
},
"node_modules/@opentelemetry/sdk-trace-base": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.6.1.tgz",
"integrity": "sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.1.tgz",
"integrity": "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "2.6.1",
"@opentelemetry/resources": "2.6.1",
"@opentelemetry/core": "2.7.1",
"@opentelemetry/resources": "2.7.1",
"@opentelemetry/semantic-conventions": "^1.29.0"
},
"engines": {
@@ -1891,23 +1834,23 @@
}
},
"node_modules/@prisma/adapter-d1": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/adapter-d1/-/adapter-d1-7.7.0.tgz",
"integrity": "sha512-0+lJsHqm+TXxXdGCCMFouNcJMVE029g6td/vRM7EhWoJYtvakwCzdzJqCQEaGPjCAPi6lzar4DAtEi7z04qjIA==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/adapter-d1/-/adapter-d1-7.8.0.tgz",
"integrity": "sha512-JLmmuDKnPltHicr8+W0xOt4ozbTlAiaPEDe8YGAJIEgHmflOF7sr4Dsd8d+saRBKOARnODz/yxx+y+QMRm/e/g==",
"license": "Apache-2.0",
"dependencies": {
"@cloudflare/workers-types": "^4.20251014.0",
"@prisma/driver-adapter-utils": "7.7.0",
"@prisma/driver-adapter-utils": "7.8.0",
"ky": "1.7.5"
}
},
"node_modules/@prisma/client": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.7.0.tgz",
"integrity": "sha512-5Ar4OsZpJ54s21sy5oDNNW9gQtd4NuxCaiM7+JDTOU07D6VvlpLjYzAVCMB1+JzokN+08dAVomlx+b7bhJd3ww==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.8.0.tgz",
"integrity": "sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==",
"license": "Apache-2.0",
"dependencies": {
"@prisma/client-runtime-utils": "7.7.0"
"@prisma/client-runtime-utils": "7.8.0"
},
"engines": {
"node": "^20.19 || ^22.12 || >=24.0"
@@ -1926,28 +1869,28 @@
}
},
"node_modules/@prisma/client-runtime-utils": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.7.0.tgz",
"integrity": "sha512-BLyd0UpFYOtyJFTHm7jS9vesHW7P83abibodQMiIofqjBKzDHQ1VAsQkdfvXyYDkPlONPfOTz7/rv3x/+CQqvQ==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.8.0.tgz",
"integrity": "sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==",
"license": "Apache-2.0"
},
"node_modules/@prisma/config": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.7.0.tgz",
"integrity": "sha512-hmPI3tKLO2aP0Y5vugbjcnA9qqlfJndiT6ds4tw28U5hNHLWg+mHJEWAhjsSPgxjtmxhJ/EDIeIlyh+3Us0OPg==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.8.0.tgz",
"integrity": "sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"c12": "3.1.0",
"c12": "3.3.4",
"deepmerge-ts": "7.1.5",
"effect": "3.20.0",
"empathic": "2.0.0"
}
},
"node_modules/@prisma/debug": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.7.0.tgz",
"integrity": "sha512-12J62XdqCmpiwJHhHdQxZeY3ckVCWIFmcJP8hg5dPTceeiQ0wiojXGFYTluKqFQfu46fRLgb/rLALZMAx3+dTA==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.8.0.tgz",
"integrity": "sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==",
"license": "Apache-2.0"
},
"node_modules/@prisma/dev": {
@@ -1984,65 +1927,65 @@
"license": "MIT"
},
"node_modules/@prisma/driver-adapter-utils": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.7.0.tgz",
"integrity": "sha512-gZXREeu6mOk7zXfGFJgh86p7Vhj0sXNKp+4Cg1tWYo7V2dfncP2qxS2BiTmbIIha8xPqItkl0WSw38RuSq1HoQ==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.8.0.tgz",
"integrity": "sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A==",
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "7.7.0"
"@prisma/debug": "7.8.0"
}
},
"node_modules/@prisma/engines": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.7.0.tgz",
"integrity": "sha512-7fmcbT7HHXBq/b+3h/dO1JI3fd8l8q7erf7xP7pRprh58hmSSnG8mg9K3yjW3h9WaHWUwngVFpSxxxivaitQ2w==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.8.0.tgz",
"integrity": "sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==",
"devOptional": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "7.7.0",
"@prisma/engines-version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711",
"@prisma/fetch-engine": "7.7.0",
"@prisma/get-platform": "7.7.0"
"@prisma/debug": "7.8.0",
"@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a",
"@prisma/fetch-engine": "7.8.0",
"@prisma/get-platform": "7.8.0"
}
},
"node_modules/@prisma/engines-version": {
"version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711",
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711.tgz",
"integrity": "sha512-r51DLcJ8bDRSrBEJF3J4cinoWyGA7rfP2mG6lD90VqIbGNOkbfcLcXalSVjq5Y6brQS3vcjrq4GbyUb1Cb7vkw==",
"version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a",
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a.tgz",
"integrity": "sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==",
"devOptional": true,
"license": "Apache-2.0"
},
"node_modules/@prisma/engines/node_modules/@prisma/get-platform": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.7.0.tgz",
"integrity": "sha512-MEUNzvKxvYnJ7kgvd6oNRnMmmiGNS9TYLB2weMeIXplnHdL/UWEGnvavYGnN7KLJ2n0iI4dDAyzSkHI3c7AscQ==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz",
"integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "7.7.0"
"@prisma/debug": "7.8.0"
}
},
"node_modules/@prisma/fetch-engine": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.7.0.tgz",
"integrity": "sha512-TfyzveBQoK4xALzsTpVhB/0KG1N8zOK0ap+RnBMkzGUu3f98fnQ4QtXa2wlKPhsO2X8a3N5ugFQgcKNoHGmDfw==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.8.0.tgz",
"integrity": "sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "7.7.0",
"@prisma/engines-version": "7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711",
"@prisma/get-platform": "7.7.0"
"@prisma/debug": "7.8.0",
"@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a",
"@prisma/get-platform": "7.8.0"
}
},
"node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.7.0.tgz",
"integrity": "sha512-MEUNzvKxvYnJ7kgvd6oNRnMmmiGNS9TYLB2weMeIXplnHdL/UWEGnvavYGnN7KLJ2n0iI4dDAyzSkHI3c7AscQ==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz",
"integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "7.7.0"
"@prisma/debug": "7.8.0"
}
},
"node_modules/@prisma/get-platform": {
@@ -2960,66 +2903,66 @@
]
},
"node_modules/@sentry-internal/browser-utils": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.48.0.tgz",
"integrity": "sha512-SCiTLBXzugFKxev6NoKYBIhQoDk0gUh0AVVVepCBqfCJiWBG01Zvv0R5tCVohr4cWRllkQ8mlBdNQd/I7s9tdA==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.52.0.tgz",
"integrity": "sha512-x/yEPZdpH6NGQeoeQnV9tj8reAH8twNttiltGZl2o8Rk7sQeUfe7E8yuYP2XbJ2RqyZK5qRS3COrNyMPzf6KFA==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.48.0"
"@sentry/core": "10.52.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/feedback": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.48.0.tgz",
"integrity": "sha512-tGkEyOM1HDS9qebDphUMEnyk3qq/50AnuTBiFmMJyjNzowylVGmRRk0sr3xkmbVHCDXQCiYnDmSVlJ2x4SDMrQ==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.52.0.tgz",
"integrity": "sha512-5kAn1W8ZvCuHtEHXpq6iRkUMdNCilwww+YxaN2yofVrCivAbB3Ha5JJUMqmWOPW0pC27zGYmoJMIDvG+PczUxA==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.48.0"
"@sentry/core": "10.52.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.48.0.tgz",
"integrity": "sha512-sevRTePfuk4PNuz9KAKpmTZEomAU0aLXyIhOwA0OnUDdxPhkY8kq5lwDbuxTHv6DQUjUX3YgFbY45VH1JEqHKA==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.52.0.tgz",
"integrity": "sha512-diywyuc/H7VTUR+W5ryVmLF+0X4UP1OskMqb6V8RSAvJHcj2JmIm7uP+Fc6ACTno+b6AUShwT/L4xVXzO6X9Cw==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "10.48.0",
"@sentry/core": "10.48.0"
"@sentry-internal/browser-utils": "10.52.0",
"@sentry/core": "10.52.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.48.0.tgz",
"integrity": "sha512-9nWuN2z4O+iwbTfuYV5ZmngBgJU/ZxfOo47A5RJP3Nu/kl59aJ1lUhILYOKyeNOIC/JyeERmpIcTxnlPXQzZ3Q==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.52.0.tgz",
"integrity": "sha512-BI5ie4dxPuUJ344CXVSnAxY1xZCbghglPSCIlTOYODpR9so9yo5IZh+Mwspt0oWsUMaxWJiQSNYlbPWi7WDavg==",
"license": "MIT",
"dependencies": {
"@sentry-internal/replay": "10.48.0",
"@sentry/core": "10.48.0"
"@sentry-internal/replay": "10.52.0",
"@sentry/core": "10.52.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/browser": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.48.0.tgz",
"integrity": "sha512-4jt2zX2ExgFcNe2x+W+/k81fmDUsOrquGtt028CiGuDuma6kEsWBI4JbooT1jhj2T+eeUxe3YGbM23Zhh7Ghhw==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.52.0.tgz",
"integrity": "sha512-ijL9jN86oXwXQWbwhPlEb70ODJSEmjxQEQdnZkC4gDWbjswcwvRsVJPYk+1xl2ir2iZixRIHipVxDcLwian35g==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "10.48.0",
"@sentry-internal/feedback": "10.48.0",
"@sentry-internal/replay": "10.48.0",
"@sentry-internal/replay-canvas": "10.48.0",
"@sentry/core": "10.48.0"
"@sentry-internal/browser-utils": "10.52.0",
"@sentry-internal/feedback": "10.52.0",
"@sentry-internal/replay": "10.52.0",
"@sentry-internal/replay-canvas": "10.52.0",
"@sentry/core": "10.52.0"
},
"engines": {
"node": ">=18"
@@ -3206,13 +3149,13 @@
}
},
"node_modules/@sentry/cloudflare": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry/cloudflare/-/cloudflare-10.48.0.tgz",
"integrity": "sha512-i02Ps4/cJjFpbcHLMhNEFXTeVqLB9XpB3+/OFQ9aMFV3yDcxlvHwe0oo7WZf41iroArvpysotLG8Y8NBOU9omA==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry/cloudflare/-/cloudflare-10.52.0.tgz",
"integrity": "sha512-NhFpR0OKd7gZDuJWJd8C0jC6WhA+R+m1OGp0ul2ItwIASTzGMw6gGLo0XuQjC6GfuodNAGbCF1bQN3Zi3nV1Lg==",
"license": "MIT",
"dependencies": {
"@opentelemetry/api": "^1.9.1",
"@sentry/core": "10.48.0"
"@sentry/core": "10.52.0"
},
"engines": {
"node": ">=18"
@@ -3227,23 +3170,22 @@
}
},
"node_modules/@sentry/core": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.48.0.tgz",
"integrity": "sha512-h8F+fXVwYC9ro5ZaO8V+v3vqc0awlXHGblEAuVxSGgh4IV/oFX+QVzXeDTTrFOFS6v/Vn5vAyu240eJrJAS6/g==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.52.0.tgz",
"integrity": "sha512-VA/kAqLhkMnRWY2RXdBLyTemR9D4m7MVRy/gyapoq9yvllVPx9WXbvKgnMP2LQp7mFgT/oLFvw58aQKaYTGn3A==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/node": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.48.0.tgz",
"integrity": "sha512-MzyLJyYmr0Qg60K6NJ2EdwJUX1OuAYXs9tyYxnqVO3nJ8MyYwIcuN4FCYEnXkG6Jiy/4q7OuZgXWnfdQJVcaqw==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-10.52.0.tgz",
"integrity": "sha512-9+p3KJUk3rHO1HOEZuSknP2RgKCJZONDm4HWgkVDtVBtocb66KLtVlMjc59d2/bWP7tM3wc877tpG30quFfU9g==",
"license": "MIT",
"dependencies": {
"@fastify/otel": "0.18.0",
"@opentelemetry/api": "^1.9.1",
"@opentelemetry/context-async-hooks": "^2.6.1",
"@opentelemetry/core": "^2.6.1",
"@opentelemetry/instrumentation": "^0.214.0",
"@opentelemetry/instrumentation-amqplib": "0.61.0",
@@ -3254,7 +3196,6 @@
"@opentelemetry/instrumentation-graphql": "0.62.0",
"@opentelemetry/instrumentation-hapi": "0.60.0",
"@opentelemetry/instrumentation-http": "0.214.0",
"@opentelemetry/instrumentation-ioredis": "0.62.0",
"@opentelemetry/instrumentation-kafkajs": "0.23.0",
"@opentelemetry/instrumentation-knex": "0.58.0",
"@opentelemetry/instrumentation-koa": "0.62.0",
@@ -3264,16 +3205,13 @@
"@opentelemetry/instrumentation-mysql": "0.60.0",
"@opentelemetry/instrumentation-mysql2": "0.60.0",
"@opentelemetry/instrumentation-pg": "0.66.0",
"@opentelemetry/instrumentation-redis": "0.62.0",
"@opentelemetry/instrumentation-tedious": "0.33.0",
"@opentelemetry/instrumentation-undici": "0.24.0",
"@opentelemetry/resources": "^2.6.1",
"@opentelemetry/sdk-trace-base": "^2.6.1",
"@opentelemetry/semantic-conventions": "^1.40.0",
"@prisma/instrumentation": "7.6.0",
"@sentry/core": "10.48.0",
"@sentry/node-core": "10.48.0",
"@sentry/opentelemetry": "10.48.0",
"@sentry/core": "10.52.0",
"@sentry/node-core": "10.52.0",
"@sentry/opentelemetry": "10.52.0",
"import-in-the-middle": "^3.0.0"
},
"engines": {
@@ -3281,13 +3219,13 @@
}
},
"node_modules/@sentry/node-core": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.48.0.tgz",
"integrity": "sha512-D1TnPhN6vhrRqJ+bN+rdXDM+INibI6lNBm0eGx45zz7DBx9ouq2e9gm/DPx+y/hAkYYq0qTd6x84cGxtVZbKLw==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-10.52.0.tgz",
"integrity": "sha512-IG7MBtLRPQ2LuU+kbD14AFZroZgAeUmJQTP1FI/F8n56O31+p+9R703LuBTpvZr6sm+eRYDMWcGYYkfLHRVjwg==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.48.0",
"@sentry/opentelemetry": "10.48.0",
"@sentry/core": "10.52.0",
"@sentry/opentelemetry": "10.52.0",
"import-in-the-middle": "^3.0.0"
},
"engines": {
@@ -3295,11 +3233,9 @@
},
"peerDependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0",
"@opentelemetry/core": "^1.30.1 || ^2.1.0",
"@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1",
"@opentelemetry/instrumentation": ">=0.57.1 <1",
"@opentelemetry/resources": "^1.30.1 || ^2.1.0",
"@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0",
"@opentelemetry/semantic-conventions": "^1.39.0"
},
@@ -3307,9 +3243,6 @@
"@opentelemetry/api": {
"optional": true
},
"@opentelemetry/context-async-hooks": {
"optional": true
},
"@opentelemetry/core": {
"optional": true
},
@@ -3319,9 +3252,6 @@
"@opentelemetry/instrumentation": {
"optional": true
},
"@opentelemetry/resources": {
"optional": true
},
"@opentelemetry/sdk-trace-base": {
"optional": true
},
@@ -3331,32 +3261,31 @@
}
},
"node_modules/@sentry/opentelemetry": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.48.0.tgz",
"integrity": "sha512-Tn6Y0PZjRJ7OW8loK1ntK7wnJnIINnCfSpnwuqow0FMblaDmu5jDVOYq0U1SJBoBcMD5j9aSqrwyj6zqKwjc0A==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-10.52.0.tgz",
"integrity": "sha512-Sc7StsvC0bwhMcgDfTRWUIexO5cNzzKUurvUwtpgQUnxO7AzexU3lkY3yHYDsCbWYAEQMXAgQYQtbcqoh+Ie7g==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.48.0"
"@sentry/core": "10.52.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0",
"@opentelemetry/core": "^1.30.1 || ^2.1.0",
"@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0",
"@opentelemetry/semantic-conventions": "^1.39.0"
}
},
"node_modules/@sentry/react": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.48.0.tgz",
"integrity": "sha512-uc93vKjmu6gNns+JAX4qquuxWpAMit0uGPA1TYlMjct9NG1uX3TkDPJAr9Pgd1lOXx8mKqCmj5fK33QeExMpPw==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.52.0.tgz",
"integrity": "sha512-2m72QCsja2cJJHD0ALxRnVt0qMEC2FV4LSi6AAiEdEG4lTb6mgcxavx5pJrW90jE+6dMGPbUz4q8c9vi4jh1qQ==",
"license": "MIT",
"dependencies": {
"@sentry/browser": "10.48.0",
"@sentry/core": "10.48.0"
"@sentry/browser": "10.52.0",
"@sentry/core": "10.52.0"
},
"engines": {
"node": ">=18"
@@ -3366,9 +3295,9 @@
}
},
"node_modules/@sentry/remix": {
"version": "10.48.0",
"resolved": "https://registry.npmjs.org/@sentry/remix/-/remix-10.48.0.tgz",
"integrity": "sha512-ToJ1j9x0tHNM78UrdbjMDNL31nvbRUDdE2rTfeUEt7cQUo7vio68mmqrdnrIo0j6g5rwewWPXkNP+ENBeuzLOQ==",
"version": "10.52.0",
"resolved": "https://registry.npmjs.org/@sentry/remix/-/remix-10.52.0.tgz",
"integrity": "sha512-k6WguxtHupGKDlYW49kJAi7gWUt7uEWP3EpJ2hzdpIZwARcU4Mv5aCZm0tgtQs5O9c+Gq9EJsr+ASoDgM39Lng==",
"license": "MIT",
"dependencies": {
"@opentelemetry/api": "^1.9.1",
@@ -3376,9 +3305,9 @@
"@opentelemetry/semantic-conventions": "^1.40.0",
"@remix-run/router": "^1.23.2",
"@sentry/cli": "^2.58.5",
"@sentry/core": "10.48.0",
"@sentry/node": "10.48.0",
"@sentry/react": "10.48.0",
"@sentry/core": "10.52.0",
"@sentry/node": "10.52.0",
"@sentry/react": "10.52.0",
"yargs": "^17.6.0"
},
"bin": {
@@ -3495,9 +3424,9 @@
}
},
"node_modules/@types/node": {
"version": "24.12.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.2.tgz",
"integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==",
"version": "24.12.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.3.tgz",
"integrity": "sha512-8oljBDGun9cIsZRJR6fkihn0TSXJI0UDOOhncYaERq6M0JMDoPLxyscwruJcb4GKS6dvK/d8xebYBg27h/duaQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
@@ -4082,27 +4011,27 @@
}
},
"node_modules/c12": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz",
"integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==",
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz",
"integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"chokidar": "^4.0.3",
"confbox": "^0.2.2",
"defu": "^6.1.4",
"dotenv": "^16.6.1",
"exsolve": "^1.0.7",
"giget": "^2.0.0",
"jiti": "^2.4.2",
"chokidar": "^5.0.0",
"confbox": "^0.2.4",
"defu": "^6.1.6",
"dotenv": "^17.3.1",
"exsolve": "^1.0.8",
"giget": "^3.2.0",
"jiti": "^2.6.1",
"ohash": "^2.0.11",
"pathe": "^2.0.3",
"perfect-debounce": "^1.0.0",
"pkg-types": "^2.2.0",
"rc9": "^2.1.2"
"perfect-debounce": "^2.1.0",
"pkg-types": "^2.3.0",
"rc9": "^3.0.1"
},
"peerDependencies": {
"magicast": "^0.3.5"
"magicast": "*"
},
"peerDependenciesMeta": {
"magicast": {
@@ -4111,34 +4040,21 @@
}
},
"node_modules/c12/node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
"readdirp": "^5.0.0"
},
"engines": {
"node": ">= 14.16.0"
"node": ">= 20.19.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/c12/node_modules/dotenv": {
"version": "16.6.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
"devOptional": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/c12/node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
@@ -4147,13 +4063,13 @@
"license": "MIT"
},
"node_modules/c12/node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 14.18.0"
"node": ">= 20.19.0"
},
"funding": {
"type": "individual",
@@ -4369,16 +4285,6 @@
"node": ">=10"
}
},
"node_modules/citty": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
"integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"consola": "^3.2.3"
}
},
"node_modules/cjs-module-lexer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz",
@@ -4534,16 +4440,6 @@
"devOptional": true,
"license": "MIT"
},
"node_modules/consola": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz",
"integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": "^14.18.0 || >=16.10.0"
}
},
"node_modules/content-disposition": {
"version": "0.5.4",
"dev": true,
@@ -4838,7 +4734,7 @@
"version": "17.4.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz",
"integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==",
"dev": true,
"devOptional": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
@@ -5701,30 +5597,15 @@
}
},
"node_modules/giget": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz",
"integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/giget/-/giget-3.2.0.tgz",
"integrity": "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"citty": "^0.1.6",
"consola": "^3.4.0",
"defu": "^6.1.4",
"node-fetch-native": "^1.6.6",
"nypm": "^0.6.0",
"pathe": "^2.0.3"
},
"bin": {
"giget": "dist/cli.mjs"
}
},
"node_modules/giget/node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"devOptional": true,
"license": "MIT"
},
"node_modules/glob": {
"version": "10.5.0",
"dev": true,
@@ -6374,9 +6255,9 @@
"license": "MIT"
},
"node_modules/jiti": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
"integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
"devOptional": true,
"license": "MIT",
"bin": {
@@ -7819,13 +7700,6 @@
}
}
},
"node_modules/node-fetch-native": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
"integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
"devOptional": true,
"license": "MIT"
},
"node_modules/node-releases": {
"version": "2.0.27",
"dev": true,
@@ -7911,38 +7785,6 @@
"node": ">=8"
}
},
"node_modules/nypm": {
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.5.tgz",
"integrity": "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"citty": "^0.2.0",
"pathe": "^2.0.3",
"tinyexec": "^1.0.2"
},
"bin": {
"nypm": "dist/cli.mjs"
},
"engines": {
"node": ">=18"
}
},
"node_modules/nypm/node_modules/citty": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz",
"integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==",
"devOptional": true,
"license": "MIT"
},
"node_modules/nypm/node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"devOptional": true,
"license": "MIT"
},
"node_modules/object-assign": {
"version": "4.1.1",
"license": "MIT",
@@ -8231,9 +8073,9 @@
}
},
"node_modules/perfect-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
"integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
"devOptional": true,
"license": "MIT"
},
@@ -8556,9 +8398,9 @@
}
},
"node_modules/prettier": {
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.2.tgz",
"integrity": "sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==",
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
"dev": true,
"license": "MIT",
"bin": {
@@ -8586,16 +8428,16 @@
}
},
"node_modules/prisma": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-7.7.0.tgz",
"integrity": "sha512-HlgwRBt1uEFB9LStHL4HLYDvoi4BNu1rYA0hPG0zCAEyK9SaZBqp7E5Rjpc3Qh8Lex/ye/svoHZ0OWoFNhWxuQ==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-7.8.0.tgz",
"integrity": "sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==",
"devOptional": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/config": "7.7.0",
"@prisma/config": "7.8.0",
"@prisma/dev": "0.24.3",
"@prisma/engines": "7.7.0",
"@prisma/engines": "7.8.0",
"@prisma/studio-core": "0.27.3",
"mysql2": "3.15.3",
"postgres": "3.4.7"
@@ -8794,14 +8636,14 @@
}
},
"node_modules/rc9": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz",
"integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz",
"integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"defu": "^6.1.4",
"destr": "^2.0.3"
"defu": "^6.1.6",
"destr": "^2.0.5"
}
},
"node_modules/react": {
@@ -9920,16 +9762,6 @@
"safe-buffer": "~5.1.0"
}
},
"node_modules/tinyexec": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz",
"integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"dev": true,

View File

@@ -7,20 +7,20 @@
"build": "remix build --sourcemap",
"check-format": "prettier -c .",
"format": "prettier -wc .",
"publish": "remix build --sourcemap && wrangler pages deploy public"
"publish": "remix build --sourcemap && wrangler pages deploy --upload-source-maps public"
},
"dependencies": {
"@chakra-ui/react": "^2.10.9",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@fontsource-variable/plus-jakarta-sans": "^5.2.8",
"@prisma/adapter-d1": "^7.7.0",
"@prisma/client": "^7.7.0",
"@prisma/adapter-d1": "^7.8.0",
"@prisma/client": "^7.8.0",
"@remix-run/cloudflare": "^2.17.4",
"@remix-run/cloudflare-pages": "^2.17.4",
"@remix-run/react": "^2.17.4",
"@sentry/cloudflare": "^10.48.0",
"@sentry/remix": "^10.48.0",
"@sentry/cloudflare": "^10.52.0",
"@sentry/remix": "^10.52.0",
"aws4fetch": "^1.0.20",
"dayjs": "^1.11.20",
"framer-motion": "^12.38.0",
@@ -30,17 +30,17 @@
},
"devDependencies": {
"@remix-run/dev": "^2.17.4",
"@types/node": "^24.12.2",
"@types/node": "^24.12.3",
"@types/react": "^18.3.28",
"@types/react-big-calendar": "^1.16.3",
"@types/react-dom": "^18.3.7",
"dotenv": "^17.4.1",
"prettier": "^3.8.2",
"prisma": "^7.7.0",
"prettier": "^3.8.3",
"prisma": "^7.8.0",
"typescript": "^5.9.3"
},
"overrides": {
"@cloudflare/workers-types": "^4.20260329.1"
"@cloudflare/workers-types": "^4.20260511.1"
},
"prettier": {
"endOfLine": "auto"

View File

@@ -29,6 +29,18 @@ model AppealBan {
@@map("appeal_bans")
}
model DataRequest {
created_at DateTime @default(now())
id String @id @unique
originating_user Int?
status String
target_user Int
type String
@@index([created_at], name: "idx_data_requests_created_at")
@@map("data_requests")
}
model EtMember {
created_at DateTime @default(now())
created_by String