Compare commits

..

13 Commits

Author SHA1 Message Date
017ce48835 Finally fix leaderboard hiding 2025-11-24 12:02:16 -05:00
72f8791276 Bump packages 2025-10-23 16:29:33 -04:00
63b1926056 Strip out datacenter code from report ids 2025-10-23 15:34:36 -04:00
25dc50e05c Space out departments 2025-10-23 15:28:34 -04:00
a403832735 Only apply decisions to departments the notice covers 2025-10-23 15:22:45 -04:00
e1f1093d84 Hopefully last one 2025-10-14 02:45:06 -04:00
243a4d1ceb Even more le fixes 2025-10-14 02:38:31 -04:00
54d9bd5e82 More le fixes 2025-10-14 02:28:22 -04:00
a1f4b4eabe Le fixes 2025-10-14 02:14:41 -04:00
64edc6169b New page 2025-10-14 02:10:25 -04:00
cf84722418 Remove old game mod management modal 2025-10-14 02:10:07 -04:00
102b29c54f Bump node version 2025-10-13 13:52:39 -04:00
42f13612b1 Make note creation 2025-10-13 13:49:30 -04:00
14 changed files with 326 additions and 249 deletions

View File

@@ -1 +1 @@
v22.19.0
v22.20.0

209
app/routes/gmm.tsx Normal file
View File

@@ -0,0 +1,209 @@
import {
Button,
Container,
FormControl,
FormLabel,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Table,
TableCaption,
TableContainer,
Tbody,
Td,
Th,
Thead,
Tr,
useDisclosure,
useToast,
} from "@chakra-ui/react";
import { useLoaderData } from "@remix-run/react";
import { useState } from "react";
export async function loader({ context }: { context: RequestContext }) {
if (!context.data.current_user)
throw new Response(null, {
status: 401,
});
if (
![
"165594923586945025",
"289372404541554689",
"396347223736057866",
].includes(context.data.current_user.id)
)
throw new Response(null, {
status: 403,
});
return (await context.env.DATA.list({ prefix: "gamemod_" }))?.keys ?? [];
}
export default function () {
const data: { [k: string]: any }[] = useLoaderData<typeof loader>();
const [gameModData, setGameModData] = useState(data);
const { isOpen, onClose, onOpen } = useDisclosure();
const [idToAdd, setIdToAdd] = useState<string>("");
const [nameToAdd, setNameToAdd] = useState<string>("");
const toast = useToast();
async function addMod(id: string, name: string) {
const response = await fetch("/api/gme/add", {
body: JSON.stringify({ name, user: id }),
headers: {
"content-type": "application/json",
},
method: "POST",
});
if (!response.ok) {
let msg = "Unknown error";
try {
msg = ((await response.json()) as { error: string }).error;
} catch {}
toast({
description: msg,
status: "error",
title: "Cannot add game mod",
});
} else {
onClose();
location.reload();
}
setIdToAdd("");
setNameToAdd("");
}
async function removeMod(user: string) {
const response = await fetch("/api/gme/remove", {
body: JSON.stringify({ user }),
headers: {
"content-type": "application/json",
},
method: "POST",
});
if (!response.ok) {
let msg = "Unknown error";
try {
msg = ((await response.json()) as { error: string }).error;
} catch {}
toast({
description: msg,
status: "error",
title: "Cannot remove game mod",
});
return;
}
toast({
description: `${data.find((i) => i.metadata.id === user)?.name} was removed as a game mod`,
status: "success",
title: "Game mod removed",
});
setGameModData(gameModData.filter((i) => i.metadata.id !== user));
}
return (
<Container maxW="container.lg">
<TableContainer>
<Table variant="simple">
<TableCaption>Currently active game mods</TableCaption>
<Thead>
<Tr>
<Th>ID</Th>
<Th>Name</Th>
<Th>Added At</Th>
<Th>Added By</Th>
<Th>Remove</Th>
</Tr>
</Thead>
<Tbody>
{gameModData.map((item) => {
return (
<Tr key={item.metadata.id}>
<Td>{item.metadata.id}</Td>
<Td>{item.metadata.name}</Td>
<Td>{item.metadata.created_at}</Td>
<Td>{item.metadata.created_by}</Td>
<Td>
<Button
onClick={async () => await removeMod(item.metadata.id)}
>
Remove
</Button>
</Td>
</Tr>
);
})}
</Tbody>
</Table>
</TableContainer>
<Button alignSelf="end" mt="16px" onClick={onOpen}>
Add
</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Add Game Mod</ModalHeader>
<ModalCloseButton />
<ModalBody>
<FormControl>
<FormLabel>Name</FormLabel>
<Input
maxLength={32}
onChange={(e) => setNameToAdd(e.target.value)}
value={nameToAdd}
/>
</FormControl>
<br />
<FormControl pt="16px">
<FormLabel>ID</FormLabel>
<Input
maxLength={19}
onChange={(e) => setIdToAdd(e.target.value)}
value={idToAdd}
/>
</FormControl>
</ModalBody>
<ModalFooter gap="8px">
<Button
onClick={() => {
onClose();
setIdToAdd("");
setNameToAdd("");
}}
>
Cancel
</Button>
<Button
colorScheme="blue"
disabled={
!idToAdd.match(/\d{17,19}/) ||
nameToAdd.length < 1 ||
nameToAdd.length > 32
}
onClick={async () => {
await addMod(idToAdd, nameToAdd);
}}
>
Add
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Container>
);
}

View File

@@ -169,20 +169,22 @@ export default function () {
Decisions:
<br />
Approved:
{Object.keys(currentInactivity.decisions ?? {}).filter(
(d) => currentInactivity.decisions[d],
)}
{Object.keys(currentInactivity.decisions ?? {})
.filter((d) => currentInactivity.decisions[d])
.join(", ")}
<br />
Denied:
{Object.keys(currentInactivity.decisions ?? {}).filter(
(d) => !currentInactivity.decisions[d],
)}
{Object.keys(currentInactivity.decisions ?? {})
.filter((d) => !currentInactivity.decisions[d])
.join(", ")}
<br />
Pending:
{currentInactivity.departments?.filter(
{currentInactivity.departments
?.filter(
(d: "DM" | "ET" | "FM" | "WM") =>
typeof currentInactivity.decisions[d] === "undefined",
)}
)
.join(", ")}
</ListItem>
</UnorderedList>
</ModalBody>

View File

@@ -30,7 +30,6 @@ import { useLoaderData } from "@remix-run/react";
import AppealBans from "../../components/AppealBans.js";
import AppealCard from "../../components/AppealCard.js";
import GameAppealCard from "../../components/GameAppealCard.js";
import GameModManagementModal from "../../components/GameModManagementModal.js";
import NewGameBan from "../../components/NewGameBan.js";
import NewInfractionModal from "../../components/NewInfractionModal.js";
import ReportCard from "../../components/ReportCard.js";
@@ -151,7 +150,7 @@ export default function () {
useEffect(() => {
if (messageChannel.current) {
messageChannel.current.port1.onmessage = function (ev) {
messageChannel.current.port1.onmessage = function (ev: any) {
const { data }: { data: string } = ev;
setEntries([...entries].filter((entry) => entry.id !== data));
@@ -337,7 +336,11 @@ export default function () {
},
appeal_bans: useDisclosure(),
game_ban: useDisclosure(),
gme: useDisclosure(),
gme: {
isOpen: false,
onClose: () => {},
onOpen: () => location.assign("/gmm"),
},
inactivity: useDisclosure(),
infraction: useDisclosure(),
user_lookup: {
@@ -431,10 +434,6 @@ export default function () {
isOpen={itemModals.appeal_bans.isOpen}
onClose={itemModals.appeal_bans.onClose}
/>
<GameModManagementModal
isOpen={itemModals.gme.isOpen}
onClose={itemModals.gme.onClose}
/>
<NewGameBan
isOpen={itemModals.game_ban.isOpen}
onClose={itemModals.game_ban.onClose}

View File

@@ -1,157 +0,0 @@
import {
Button,
HStack,
Input,
Link,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
Table,
TableContainer,
Tbody,
Td,
Th,
Thead,
Tr,
useToast,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
export default function (props: { isOpen: boolean; onClose: () => void }) {
const [mods, setMods] = useState([]);
const [userToAdd, setUserToAdd] = useState("");
const toast = useToast();
useEffect(() => {
if (!props.isOpen) return;
(async function () {
const gmeResp = await fetch("/api/gme/list");
if (!gmeResp.ok) {
toast({
description: "Failed to load GME data",
status: "error",
title: "Oops",
});
return;
}
setMods(await gmeResp.json());
})();
}, [props.isOpen]);
async function addUser() {
if (!userToAdd || !userToAdd.match(/^\d{17,19}$/)) {
toast({
description: "Please check your input and try again",
status: "error",
title: "Invalid user",
});
return;
}
const addResp = await fetch("/api/gme/add", {
body: JSON.stringify({ user: userToAdd }),
headers: {
"content-type": "application/json",
},
method: "POST",
});
if (!addResp.ok) {
toast({
description: ((await addResp.json()) as { error: string }).error,
status: "error",
title: "Oops",
});
return;
}
toast({
description: `User ${userToAdd} added`,
status: "success",
title: "Success",
});
props.onClose();
}
async function removeUser(user: string) {
const removeResp = await fetch("/api/gme/remove", {
body: JSON.stringify({ user }),
headers: {
"content-type": "application/json",
},
method: "POST",
});
if (!removeResp.ok) {
toast({
description: ((await removeResp.json()) as { error: string }).error,
status: "error",
title: "Oops",
});
} else {
toast({
description: `User ${user} removed`,
status: "success",
title: "Success",
});
setMods(mods.filter((mod: any) => mod.user !== user));
}
}
return (
<Modal isCentered isOpen={props.isOpen} onClose={props.onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Game Moderators</ModalHeader>
<ModalCloseButton />
<ModalBody>
<TableContainer>
<Table variant="simple">
<Thead>
<Tr>
<Th>User</Th>
<Th>Added At</Th>
<Th>Added By</Th>
<Th>Remove</Th>
</Tr>
</Thead>
<Tbody>
{mods.map((mod: any) => (
<Tr>
<Td>{mod.user}</Td>
<Td>{new Date(mod.metadata.time).toLocaleString()}</Td>
<Td>{mod.metadata.user}</Td>
<Td>
<Link onClick={async () => await removeUser(mod.user)}>
Remove
</Link>
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
<HStack mt="8px">
<Input
maxLength={19}
onChange={(e) => setUserToAdd(e.target.value)}
placeholder="1234567890987654321"
/>
<Button onClick={async () => await addUser()}>Add</Button>
</HStack>
</ModalBody>
</ModalContent>
</Modal>
);
}

View File

@@ -0,0 +1,8 @@
import { jsonError } from "../../../common.js";
export async function onRequest(context: RequestContext) {
if (!(context.data.current_user?.permissions & (1 << 5)))
return jsonError("Forbidden", 403);
return await context.next();
}

View File

@@ -0,0 +1,23 @@
import { jsonError } from "../../../common.js";
export async function onRequestPost(context: RequestContext) {
const { content, target } = context.data.body;
if (typeof content !== "string")
return jsonError("'content' property is not a string", 400);
if (typeof target !== "number" || !Number.isSafeInteger(target))
return jsonError("'target' property is not a valid number", 400);
if (content.length > 1000)
return jsonError(
"'content' property must be less than 1000 characters",
400,
);
const id = `${Date.now()}${crypto.randomUUID().replaceAll("-", "")}`;
await context.env.D1.prepare(
"INSERT INTO game_mod_notes (content, created_at, created_by, id, target) VALUES (?, ?, ?, ?, ?);",
).bind(content, Date.now(), context.data.current_user.id, id, target).first();
}

View File

@@ -1,10 +1,13 @@
import { jsonError } from "../../common.js";
export async function onRequestPost(context: RequestContext) {
const { user } = context.data.body;
const { user, name } = context.data.body;
if (!user) return jsonError("No user provided", 400);
if (typeof name !== "string" || name.length > 32)
return jsonError("Invalid name", 400);
const existingUser = await context.env.DATA.get(`gamemod_${user}`);
if (existingUser) return jsonError("Cannot add an existing user", 400);
@@ -21,9 +24,10 @@ export async function onRequestPost(context: RequestContext) {
if (!user.match(/^\d{17,19}$/)) return jsonError("Invalid User ID", 400);
const data = {
time: Date.now(),
user: context.data.current_user.id,
name: context.data.current_user.username,
created_at: Date.now(),
created_by: context.data.current_user.id,
id: user,
name,
};
await context.env.DATA.put(`gamemod_${user}`, JSON.stringify(data), {

View File

@@ -1,14 +0,0 @@
import { jsonResponse } from "../../common.js";
export async function onRequestGet(context: RequestContext) {
const list = await context.env.DATA.list({ prefix: "gamemod_" });
const entries = [];
for (const key of list.keys)
entries.push({
metadata: key.metadata,
user: key.name.replace("gamemod_", ""),
});
return jsonResponse(JSON.stringify(entries));
}

View File

@@ -91,8 +91,10 @@ export async function onRequestPost(context: RequestContext) {
requestedNotice.decisions,
);
for (const department of userAdminDepartments)
for (const department of userAdminDepartments) {
if (!JSON.parse(requestedNotice.departments).includes(department)) continue;
decisions[department] = accepted;
}
const applicableDepartments = JSON.parse(requestedNotice.departments).length;

View File

@@ -69,10 +69,10 @@ export async function onRequestPost(context: RequestContext) {
// If not a ban action
if (v === 1) {
newActions[user].hidden_from_leaderboards = true;
newActions[k].hidden_from_leaderboards = true;
} else if (v === 3) {
newActions[user].serverconfigurator_blacklist = true;
newActions[user].BanType = 1;
newActions[k].serverconfigurator_blacklist = true;
newActions[k].BanType = 1;
}
}

View File

@@ -183,9 +183,10 @@ export async function onRequestPost(context: RequestContext) {
const uploadUrlResults = await Promise.allSettled(uploadUrlPromises);
const reportId = `${Date.now()}${context.request.headers.get(
"cf-ray",
)}${crypto.randomUUID().replaceAll("-", "")}`;
const reportId = `${Date.now()}${context.request.headers
.get("cf-ray")
?.split("-")
?.at(0)}${crypto.randomUUID().replaceAll("-", "")}`;
const { current_user: currentUser } = context.data;
if (filesToProcess.length)

92
package-lock.json generated
View File

@@ -15,7 +15,7 @@
"@remix-run/cloudflare": "^2.17.1",
"@remix-run/cloudflare-pages": "^2.17.1",
"@remix-run/react": "^2.17.1",
"@sentry/react": "^10.19.0",
"@sentry/react": "^10.21.0",
"aws4fetch": "^1.0.20",
"dayjs": "^1.11.18",
"framer-motion": "^12.23.24",
@@ -25,7 +25,7 @@
},
"devDependencies": {
"@remix-run/dev": "^2.17.1",
"@types/node": "^24.7.2",
"@types/node": "^24.9.1",
"@types/react": "^18.3.26",
"@types/react-big-calendar": "^1.16.3",
"@types/react-dom": "^18.3.7",
@@ -649,9 +649,9 @@
}
},
"node_modules/@cloudflare/workers-types": {
"version": "4.20251011.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20251011.0.tgz",
"integrity": "sha512-gQpih+pbq3sP4uXltUeCSbPgZxTNp2gQd8639SaIbQMwgA6oJNHLhIART1fWy6DQACngiRzDVULA2x0ohmkGTQ==",
"version": "4.20251014.0",
"resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20251014.0.tgz",
"integrity": "sha512-tEW98J/kOa0TdylIUOrLKRdwkUw0rvvYVlo+Ce0mqRH3c8kSoxLzUH9gfCvwLe0M89z1RkzFovSKAW2Nwtyn3w==",
"license": "MIT OR Apache-2.0",
"peer": true
},
@@ -2065,88 +2065,88 @@
]
},
"node_modules/@sentry-internal/browser-utils": {
"version": "10.19.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.19.0.tgz",
"integrity": "sha512-E3H6R+tX7sYMIjfCRAMO0qIH43dtUqv2rSo0vv6eHDi4lDXtlDc+Vb67n4VIesT7YVxQD7GIkNhMk3hmRDIwww==",
"version": "10.21.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.21.0.tgz",
"integrity": "sha512-QRHpCBheLd/88Z2m3ABMriV0MweW+pcGKuVsH61/UdziKcQLdoQpOSvGg0/0CuqFm2UjL7237ZzLdZrWaCOlfQ==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.19.0"
"@sentry/core": "10.21.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/feedback": {
"version": "10.19.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.19.0.tgz",
"integrity": "sha512-AJ8rpzNYgfmWzovmFss51q9FtBaa2qYTLwkbVdTf58fZbLMUrgZ6qf9qMk0ePiS3nB87w9+mpbLzRObYOsK9RA==",
"version": "10.21.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.21.0.tgz",
"integrity": "sha512-6SnRR2FiW6TMwCE0PqbueHkkpeVnjOjz00R+/mX25Dp1U5BU5TzbXHzn9Y4wKnaD3Rzz4+nnzVkpHAOL3SppGw==",
"license": "MIT",
"dependencies": {
"@sentry/core": "10.19.0"
"@sentry/core": "10.21.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay": {
"version": "10.19.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.19.0.tgz",
"integrity": "sha512-bOWsm/t+d2LCYa3gUjgwFds6kKSW+K6i4pssgDY4XiV/MxHsQtQ2rbHX80chLRQe2HFCX2njvjVSJN+Nsdjmpg==",
"version": "10.21.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.21.0.tgz",
"integrity": "sha512-5tfiKZJzZf9+Xk8SyvoC4ZEVLNmjBZZEaKhVyNo53CLWUWfWOqDc3DB9fj85i/yHFQ0ImdRnaPBc0CIeN00CcA==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "10.19.0",
"@sentry/core": "10.19.0"
"@sentry-internal/browser-utils": "10.21.0",
"@sentry/core": "10.21.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "10.19.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.19.0.tgz",
"integrity": "sha512-DulLU4lvtrGPExKtpbCveLxPACrFmGx4eEYhzIn35UH8iIx6ONRSLemQyiUJQoLau7KXJy0I8AWxN+SagfebEA==",
"version": "10.21.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.21.0.tgz",
"integrity": "sha512-TOLo5mAjJSOuJId8Po44d1hwJ5bIZDtRSoupWpYWqLw1tuUh1tc4vqID11ZXsw9pBzjVIK653BPDX/z/9+Um+Q==",
"license": "MIT",
"dependencies": {
"@sentry-internal/replay": "10.19.0",
"@sentry/core": "10.19.0"
"@sentry-internal/replay": "10.21.0",
"@sentry/core": "10.21.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/browser": {
"version": "10.19.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.19.0.tgz",
"integrity": "sha512-/+B84qFOLg1vJhg4YSA4a7Pneq5Pbt1BXEdrp/UW4tJmtGPZb28qXlMdoPfmFWZgVezrawaPkxLmbu+47/+rsQ==",
"version": "10.21.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.21.0.tgz",
"integrity": "sha512-z/63bUFBQkTfJ5ElhWTYvomz+gZ1GsoH16v4/RGoPY5qZgYxcVO3fkp0opnu3gcbXS0ZW7TLRiHpqhvipDdP6g==",
"license": "MIT",
"dependencies": {
"@sentry-internal/browser-utils": "10.19.0",
"@sentry-internal/feedback": "10.19.0",
"@sentry-internal/replay": "10.19.0",
"@sentry-internal/replay-canvas": "10.19.0",
"@sentry/core": "10.19.0"
"@sentry-internal/browser-utils": "10.21.0",
"@sentry-internal/feedback": "10.21.0",
"@sentry-internal/replay": "10.21.0",
"@sentry-internal/replay-canvas": "10.21.0",
"@sentry/core": "10.21.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/core": {
"version": "10.19.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.19.0.tgz",
"integrity": "sha512-OqZjYDYsK6ZmBG5UzML0uKiKq//G6mMwPcszfuCsFgPt+pg5giUCrCUbt5VIVkHdN1qEEBk321JO2haU5n2Eig==",
"version": "10.21.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.21.0.tgz",
"integrity": "sha512-/+gpOOb2Wr1UbW59WKqNAVVIqFz9FjtUJuPtVh4UanxGCfavMPaKpFzSlaEKJSKDkiCQgANP4O2y8Y5Bh3tvEA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@sentry/react": {
"version": "10.19.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.19.0.tgz",
"integrity": "sha512-LgADcXfJ4hVVtOSW6IkY3Wsefw4xPHIQpiEux28GHf2EAYkWxyCWWb9uQH4voAacG+FcX63XfJkpUMZjadE9qw==",
"version": "10.21.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-10.21.0.tgz",
"integrity": "sha512-BSCGKkepg9QPJRS8AUjtSAFd4lYJLmz3+P+oehViEHQDtRqqmXbVIBLhqwPc05KvRGIl4/kIDjyfDuHCFCJigQ==",
"license": "MIT",
"dependencies": {
"@sentry/browser": "10.19.0",
"@sentry/core": "10.19.0",
"@sentry/browser": "10.21.0",
"@sentry/core": "10.21.0",
"hoist-non-react-statics": "^3.3.2"
},
"engines": {
@@ -2256,13 +2256,13 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.7.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz",
"integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==",
"version": "24.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz",
"integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.14.0"
"undici-types": "~7.16.0"
}
},
"node_modules/@types/parse-json": {
@@ -8918,9 +8918,9 @@
}
},
"node_modules/undici-types": {
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
"integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},

View File

@@ -16,7 +16,7 @@
"@remix-run/cloudflare": "^2.17.1",
"@remix-run/cloudflare-pages": "^2.17.1",
"@remix-run/react": "^2.17.1",
"@sentry/react": "^10.19.0",
"@sentry/react": "^10.21.0",
"aws4fetch": "^1.0.20",
"dayjs": "^1.11.18",
"framer-motion": "^12.23.24",
@@ -26,7 +26,7 @@
},
"devDependencies": {
"@remix-run/dev": "^2.17.1",
"@types/node": "^24.7.2",
"@types/node": "^24.9.1",
"@types/react": "^18.3.26",
"@types/react-big-calendar": "^1.16.3",
"@types/react-dom": "^18.3.7",
@@ -35,7 +35,7 @@
"typescript": "^5.9.3"
},
"overrides": {
"@cloudflare/workers-types": "^4.20251011.0"
"@cloudflare/workers-types": "^4.20251014.0"
},
"prettier": {
"endOfLine": "auto"