Compare commits

...

4 Commits

Author SHA1 Message Date
7d0bb44568 fix: add opposites CORRECTLY. 2025-04-29 19:03:31 -05:00
b62f79e010 feat(v2): some changes 2025-04-29 19:00:26 -05:00
f21ce33b27 fix: layout controls 2025-04-29 19:00:22 -05:00
bbc092be1f feat: add back not found page 2025-04-22 17:26:01 -05:00
37 changed files with 1205 additions and 717 deletions

@ -63,7 +63,6 @@ const nextConfig = {
ignoreBuildErrors: true, ignoreBuildErrors: true,
}, },
experimental: { experimental: {
missingSuspenseWithCSRBailout: false,
}, },
}; };

@ -2,6 +2,7 @@
"name": "mhsf", "name": "mhsf",
"version": "1.3.0", "version": "1.3.0",
"private": true, "private": true,
"type": "module",
"packageManager": "yarn@1.22.22", "packageManager": "yarn@1.22.22",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@ -43,8 +44,8 @@
"@trpc/react-query": "^11.0.0", "@trpc/react-query": "^11.0.0",
"@trpc/server": "^11.0.0", "@trpc/server": "^11.0.0",
"@types/lodash": "^4.17.16", "@types/lodash": "^4.17.16",
"@types/react": "^19.0.8", "@types/react": "19.0.10",
"@types/react-dom": "^19.0.3", "@types/react-dom": "19.0.4",
"@types/request-ip": "^0.0.41", "@types/request-ip": "^0.0.41",
"@unocss/eslint-plugin": "^0.61.5", "@unocss/eslint-plugin": "^0.61.5",
"@unocss/postcss": "^0.61.5", "@unocss/postcss": "^0.61.5",
@ -71,7 +72,7 @@
"monaco-editor": "^0.52.2", "monaco-editor": "^0.52.2",
"mongodb": "^6.8.0", "mongodb": "^6.8.0",
"motion": "^12.7.4", "motion": "^12.7.4",
"next": "15.2.0", "next": "^15.3.1",
"next-contentlayer": "^0.3.4", "next-contentlayer": "^0.3.4",
"next-css-obfuscator": "^2.2.16", "next-css-obfuscator": "^2.2.16",
"next-sitemap": "^4.2.3", "next-sitemap": "^4.2.3",
@ -81,8 +82,8 @@
"nuqs": "^2.4.1", "nuqs": "^2.4.1",
"postcss-obfuscator": "^1.6.1", "postcss-obfuscator": "^1.6.1",
"prettier": "^3.3.1", "prettier": "^3.3.1",
"react": "19.0.0", "react": "^19.1.0",
"react-dom": "19.0.0", "react-dom": "^19.1.0",
"react-fade-in": "^2.0.1", "react-fade-in": "^2.0.1",
"react-fast-marquee": "^1.6.5", "react-fast-marquee": "^1.6.5",
"react-hot-toast": "^2.4.1", "react-hot-toast": "^2.4.1",
@ -109,18 +110,18 @@
"@clerk/themes": "^2.1.19", "@clerk/themes": "^2.1.19",
"@hookform/resolvers": "^3.9.0", "@hookform/resolvers": "^3.9.0",
"@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-context-menu": "^2.1.5", "@radix-ui/react-context-menu": "^2.2.6",
"@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dialog": "^1.1.6",
"@radix-ui/react-dropdown-menu": "^2.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-label": "^2.1.0", "@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.2.0", "@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-scroll-area": "^1.1.0", "@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-slot": "^1.2.0",
"@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.3", "@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/postcss": "^4.0.7", "@tailwindcss/postcss": "^4.0.7",
"@tailwindcss/typography": "^0.5.13", "@tailwindcss/typography": "^0.5.13",
"@types/canvas-confetti": "^1.6.4", "@types/canvas-confetti": "^1.6.4",
@ -135,12 +136,12 @@
"@vercel/analytics": "^1.3.1", "@vercel/analytics": "^1.3.1",
"@vercel/speed-insights": "^1.0.12", "@vercel/speed-insights": "^1.0.12",
"canvas-confetti": "^1.9.3", "canvas-confetti": "^1.9.3",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "^1.0.0", "cmdk": "^1.0.0",
"eslint": "^8", "eslint": "^8",
"eslint-config-next": "15.2.0", "eslint-config-next": "15.2.0",
"framer-motion": "^11.3.8", "framer-motion": "^12.7.4",
"geist": "^1.3.0", "geist": "^1.3.0",
"mangle-css-class-webpack-plugin": "^5.1.0", "mangle-css-class-webpack-plugin": "^5.1.0",
"postcss": "^8", "postcss": "^8",
@ -149,12 +150,12 @@
"react-infinite-scroll-component": "^6.1.0", "react-infinite-scroll-component": "^6.1.0",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-resizable-panels": "^2.0.23", "react-resizable-panels": "^2.0.23",
"recharts": "^2.12.7", "recharts": "^2.15.1",
"shiki": "^1.23.0", "shiki": "^1.23.0",
"tailwindcss": "^3.4.1", "tailwindcss": "^4.0.7",
"typescript": "^5", "typescript": "^5",
"vaul": "^0.9.1", "vaul": "^1.1.2",
"zod": "^3.23.8" "zod": "^3.24.2"
}, },
"resolutions": { "resolutions": {
"@types/react": "19.0.10", "@types/react": "19.0.10",

@ -1,148 +0,0 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2025 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
"use client";
import "../../globals.css";
import { useSearchParams } from "next/navigation";
import { Placeholder } from "@/components/ui/placeholder";
import { Command, X } from "lucide-react";
import { IsScript } from "@/components/util/is-script";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { NavBar } from "@/components/feat/navbar/navbar";
import { TooltipProvider } from "@/components/ui/tooltip";
import { ThemeProvider } from "@/components/util/theme-provider";
import { FontBoundary } from "@/components/util/font-boundary";
import { ClerkProvider } from "@/components/util/clerk-provider";
import { Toaster } from "sonner";
import { Footer } from "@/components/feat/footer/footer";
import { NuqsAdapter } from "nuqs/adapters/next/app";
import { IframeProtector } from "@/components/util/iframe-protector";
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@/components/ui/sidebar";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const searchParams = useSearchParams();
const search = searchParams?.get("theme") || "light";
return (
<html lang="en">
<noscript>
<main className="flex justify-center items-center text-center min-h-screen h-max">
<Placeholder
icon={<X />}
title="JavaScript is required for MHSF"
description="MHSF cannot grab servers or do other external requests without JavaScript."
>
<Link href="https://www.enable-javascript.com/">
<Button>Here's how</Button>
</Link>
</Placeholder>
</main>
</noscript>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<ClerkProvider>
<IsScript>
<NuqsAdapter>
<FontBoundary>
<TooltipProvider>
<SidebarProvider>
<Sidebar variant="inset">
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton size="lg" asChild>
<a href="#">
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
<Command className="size-4" />
</div>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">
Acme Inc
</span>
<span className="truncate text-xs">
Enterprise
</span>
</div>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton asChild size="sm">
<a href="#">
<span>a</span>
</a>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<Toaster richColors position="bottom-center" />
<div className="overflow-x-hidden">{children}</div>
</SidebarInset>
</SidebarProvider>
</TooltipProvider>
</FontBoundary>
</NuqsAdapter>
</IsScript>
</ClerkProvider>
</ThemeProvider>
</html>
);
}

@ -46,8 +46,7 @@ export default function RootLayout({
const search = searchParams?.get("theme") || "light"; const search = searchParams?.get("theme") || "light";
return ( return (
<html lang="en"> <>
<body className={inter.className}>
<ThemeProvider <ThemeProvider
attribute="class" attribute="class"
disableTransitionOnChange disableTransitionOnChange
@ -55,7 +54,6 @@ export default function RootLayout({
> >
<TooltipProvider>{children}</TooltipProvider> <TooltipProvider>{children}</TooltipProvider>
</ThemeProvider> </ThemeProvider>
</body> </>
</html>
); );
} }

@ -28,14 +28,8 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
"use client";
import "../globals.css"; import "../globals.css";
import { useSearchParams } from "next/navigation";
import { Placeholder } from "@/components/ui/placeholder";
import { X } from "lucide-react";
import { IsScript } from "@/components/util/is-script"; import { IsScript } from "@/components/util/is-script";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { NavBar } from "@/components/feat/navbar/navbar"; import { NavBar } from "@/components/feat/navbar/navbar";
import { TooltipProvider } from "@/components/ui/tooltip"; import { TooltipProvider } from "@/components/ui/tooltip";
import { ThemeProvider } from "@/components/util/theme-provider"; import { ThemeProvider } from "@/components/util/theme-provider";
@ -50,24 +44,9 @@ export default function RootLayout({
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
const searchParams = useSearchParams();
const search = searchParams?.get("theme") || "light";
return ( return (
<html lang="en"> <>
<noscript>
<main className="flex justify-center items-center text-center min-h-screen h-max">
<Placeholder
icon={<X />}
title="JavaScript is required for MHSF"
description="MHSF cannot grab servers or do other external requests without JavaScript."
>
<Link href="https://www.enable-javascript.com/">
<Button>Here's how</Button>
</Link>
</Placeholder>
</main>
</noscript>
<ThemeProvider <ThemeProvider
attribute="class" attribute="class"
defaultTheme="system" defaultTheme="system"
@ -91,6 +70,6 @@ export default function RootLayout({
</IsScript> </IsScript>
</ClerkProvider> </ClerkProvider>
</ThemeProvider> </ThemeProvider>
</html> </>
); );
} }

@ -56,20 +56,7 @@ export default function RootLayout({
const search = searchParams?.get("theme") || "light"; const search = searchParams?.get("theme") || "light";
return ( return (
<html lang="en"> <>
<noscript>
<main className="flex justify-center items-center text-center min-h-screen h-max">
<Placeholder
icon={<X />}
title="JavaScript is required for MHSF"
description="MHSF cannot grab servers or do other external requests without JavaScript."
>
<Link href="https://www.enable-javascript.com/">
<Button>Here's how</Button>
</Link>
</Placeholder>
</main>
</noscript>
<ThemeProvider <ThemeProvider
attribute="class" attribute="class"
defaultTheme="system" defaultTheme="system"
@ -93,6 +80,6 @@ export default function RootLayout({
</IsScript> </IsScript>
</ClerkProvider> </ClerkProvider>
</ThemeProvider> </ThemeProvider>
</html> </>
); );
} }

@ -134,6 +134,7 @@ export default function ModificationPage({
activatedModifications: modificationArray activatedModifications: modificationArray
} }
}); });
communicator.send("rerender-servers", {});
}}> }}>
{modObj?.active ? "Disable" : "Enable"} {modObj?.active ? "Disable" : "Enable"}
</Button> </Button>
@ -165,6 +166,7 @@ export default function ModificationPage({
}); });
toast.success(`Deleted in ${Date.now() - time}ms`); toast.success(`Deleted in ${Date.now() - time}ms`);
router.push(backRoute); router.push(backRoute);
communicator.send("rerender-servers", {});
}} }}
> >
<Trash size={16} /> Delete <Trash size={16} /> Delete

@ -32,6 +32,7 @@
@plugin 'tailwindcss-animate'; @plugin 'tailwindcss-animate';
@config '../../tailwind-hero.config.ts'; @config '../../tailwind-hero.config.ts';
@plugin "@tailwindcss/typography";
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@ -78,8 +79,10 @@
border-color: hsl(214.3 31.8% 91.4%); border-color: hsl(214.3 31.8% 91.4%);
} }
--sidebar: hsl(0 0% 98%) --sidebar: hsl(0 0% 98%);
} }
.dark { .dark {
--border: 216 34% 17%; --border: 216 34% 17%;
--background: 0 0% 3.9%; --background: 0 0% 3.9%;
@ -404,6 +407,9 @@ body {
padding-left: 20px; padding-left: 20px;
color: var(--mauve-11); color: var(--mauve-11);
} }
.slot[data-swapy-highlighted] {
@apply bg-muted rounded transition-all
}
.icon-minecraft, .icon-minecraft,
.icon-minecraft-sm { .icon-minecraft-sm {
display: inline-block; display: inline-block;

@ -28,27 +28,38 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
"use client"; import { Placeholder } from "@/components/ui/placeholder";
import "./globals.css"; import "./globals.css";
import { useSearchParams } from "next/navigation";
import { Inter } from "next/font/google"; import { Inter } from "next/font/google";
import { X } from "lucide-react";
import { Link } from "@/components/util/link";
import { Button } from "@/components/ui/button";
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
export default function RootLayout({ export default function RootLayout({
children, children,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }) {
const searchParams = useSearchParams(); return (
const search = searchParams?.get("theme") || "light"; <html lang="en">
<body className={inter.className}>
return ( <noscript>
<html lang="en"> <main className="flex justify-center items-center text-center min-h-screen h-max">
<body className={inter.className}> <Placeholder
<noscript>{children}</noscript> icon={<X />}
{children} title="JavaScript is required for MHSF"
</body> description="MHSF cannot grab servers or do other external requests without JavaScript."
</html> >
); <Link href="https://www.enable-javascript.com/" noExtraIcons>
<Button>Here's how</Button>
</Link>
</Placeholder>
</main>
</noscript>
{children}
</body>
</html>
);
} }

@ -27,7 +27,17 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
"use client";
export default function Dashboard() { import { NotFoundComponent } from "@/components/util/not-found";
return <>Hello world</> import type { Metadata } from "next";
}
export const metadata: Metadata = {
applicationName: "MHSF",
title: "Page not found · MHSF",
description: "Couldn't find the page that was requested.",
};
export default function NotFoundPage() {
return <NotFoundComponent />;
}

@ -1,69 +0,0 @@
import { ComponentPropsWithoutRef, ReactNode } from "react";
import { cn } from "@/lib/utils";
interface BentoGridProps extends ComponentPropsWithoutRef<"div"> {
children: ReactNode;
className?: string;
}
interface BentoCardProps extends ComponentPropsWithoutRef<"div"> {
name: string;
className: string;
background: ReactNode;
Icon: React.ElementType;
description: string;
href: string;
cta: string;
}
const BentoGrid = ({ children, className, ...props }: BentoGridProps) => {
return (
<div
className={cn(
"grid w-full auto-rows-[22rem] grid-cols-3 gap-4",
className
)}
{...props}
>
{children}
</div>
);
};
const BentoCard = ({
name,
className,
background,
Icon,
description,
href,
cta,
...props
}: BentoCardProps) => (
<div
key={name}
className={cn(
"group relative col-span-3 flex flex-col justify-between overflow-hidden rounded-xl",
// light styles
"bg-background [box-shadow:0_0_0_1px_rgba(0,0,0,.03),0_2px_4px_rgba(0,0,0,.05),0_12px_24px_rgba(0,0,0,.05)]",
// dark styles
"transform-gpu dark:bg-background dark:[border:1px_solid_rgba(255,255,255,.1)] dark:[box-shadow:0_-20px_80px_-20px_#ffffff1f_inset]",
className
)}
{...props}
>
<div>{background}</div>
<div className="pointer-events-none z-10 flex transform-gpu flex-col gap-1 p-6 transition-all duration-300 group-hover:-translate-y-10">
<Icon className="h-12 w-12 origin-left transform-gpu text-neutral-700 transition-all duration-300 ease-in-out group-hover:scale-75" />
<h3 className="text-xl font-semibold text-neutral-700 dark:text-neutral-300">
{name}
</h3>
<p className="max-w-lg text-neutral-400">{description}</p>
</div>
<div className="pointer-events-none absolute inset-0 transform-gpu transition-all duration-300 group-hover:bg-black/[.03] group-hover:dark:bg-neutral-800/10" />
</div>
);
export { BentoCard, BentoGrid };

@ -1,3 +1,4 @@
"use client";
import { BrandingGenericIcon, Discord } from "../icons/branding-icons"; import { BrandingGenericIcon, Discord } from "../icons/branding-icons";
import { Link } from "../../util/link"; import { Link } from "../../util/link";
import { FooterStatus } from "./status"; import { FooterStatus } from "./status";
@ -7,10 +8,11 @@ import Github from "@/components/ui/github";
import Image from "next/image" import Image from "next/image"
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
const hideFooterPages = ["/home"]; const hideFooterPages = ["/home"]
export function Footer() { export function Footer() {
const pathname = usePathname(); const pathname = usePathname();
if (!hideFooterPages.includes(pathname ?? "")) if (!hideFooterPages.includes(pathname ?? ""))
return ( return (
<footer className="w-full mt-15 border-t border-neutral-500/20 bg-neutral-100 dark:border-neutral-700/50 dark:bg-neutral-900 text-muted-foreground"> <footer className="w-full mt-15 border-t border-neutral-500/20 bg-neutral-100 dark:border-neutral-700/50 dark:bg-neutral-900 text-muted-foreground">
@ -50,7 +52,7 @@ export function Footer() {
<div className="flex items-center mb-2 justify-end gap-2"> <div className="flex items-center mb-2 justify-end gap-2">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger> <DropdownMenuTrigger asChild>
<Button variant="tertiary" size="square-md" className="flex items-center"> <Button variant="tertiary" size="square-md" className="flex items-center">
<Discord className="w-[1.25em] h-[1.25em]" /> <Discord className="w-[1.25em] h-[1.25em]" />
</Button> </Button>

@ -90,8 +90,6 @@ export function FontChanger({
return () => clearInterval(interval); return () => clearInterval(interval);
}, []); }, []);
console.log(position);
return ( return (
<div className="h-[1.2em] overflow-hidden flex items-center justify-center"> <div className="h-[1.2em] overflow-hidden flex items-center justify-center">
<span <span

@ -106,13 +106,13 @@ export default function HomePageComponent() {
style={ style={
{ {
"--gradient-color-1": "--gradient-color-1":
resolvedTheme === "dark" ? "#043D5D" : "#1F9EA3", resolvedTheme === "dark" ? "#470061" : "#610034",
"--gradient-color-2": "--gradient-color-2":
resolvedTheme === "dark" ? "#032E46" : "#F8BD97", resolvedTheme === "dark" ? "#001299" : "#700099",
"--gradient-color-3": "--gradient-color-3":
resolvedTheme === "dark" ? "#23B684" : "#9E5428", resolvedTheme === "dark" ? "#8d00eb" : "#eb00ac",
"--gradient-color-4": "--gradient-color-4":
resolvedTheme === "dark" ? "#0F595E" : "#EEEEEE", resolvedTheme === "dark" ? "#009de0" : "#0007e0",
webKitMaskImage: webKitMaskImage:
"linear-gradient(to top, black, black, transparent)", "linear-gradient(to top, black, black, transparent)",
maskImage: "linear-gradient(to top, black, black, transparent)", maskImage: "linear-gradient(to top, black, black, transparent)",

@ -30,22 +30,22 @@
"use client"; "use client";
import { import {
BrandingGenericIcon, BrandingGenericIcon,
brandingIconClipboard, brandingIconClipboard,
} from "@/components/feat/icons/branding-icons"; } from "@/components/feat/icons/branding-icons";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
ContextMenu, ContextMenu,
ContextMenuContent, ContextMenuContent,
ContextMenuItem, ContextMenuItem,
ContextMenuSeparator, ContextMenuSeparator,
ContextMenuTrigger, ContextMenuTrigger,
} from "@/components/ui/context-menu"; } from "@/components/ui/context-menu";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import Github from "@/components/ui/github"; import Github from "@/components/ui/github";
import { Link } from "@/components/util/link"; import { Link } from "@/components/util/link";
@ -63,143 +63,147 @@ import { usePathname } from "next/navigation";
const animatedTopbarPages = ["/home"]; const animatedTopbarPages = ["/home"];
export function NavBar() { export function NavBar() {
const showBorder = useScroll(40); const showBorder = useScroll(40);
const clipboard = useClipboard(); const clipboard = useClipboard();
const pathname = usePathname(); const pathname = usePathname();
const { user } = useUser(); const { user } = useUser();
return ( return (
<div <div
className={cn( className={cn(
"w-screen h-[3rem] grid-cols-3 fixed z-10 flex", "w-screen h-[3rem] grid-cols-3 fixed z-10 flex",
"items-center justify-self-start me-auto pl-4 flex-1 transition-all justify-between", "items-center justify-self-start me-auto pl-4 flex-1 transition-all justify-between",
"lg:top-0 max-lg:bottom-0", "lg:top-0 max-lg:bottom-0",
showBorder ? "border-b backdrop-blur-xl" : "max-lg:border-b max-lg:backdrop-blur-xl", showBorder
pathname !== null && animatedTopbarPages.includes(pathname) ? "border-b backdrop-blur-xl"
? "[--animation-delay:1000ms] opacity-0 animate-fade-in" : "max-lg:border-b max-lg:backdrop-blur-xl",
: "" pathname !== null && animatedTopbarPages.includes(pathname)
)} ? "[--animation-delay:1000ms] opacity-0 animate-fade-in"
> : "",
<span> )}
<ContextMenu> >
<ContextMenuTrigger> <span>
<Link className="gap-5 flex items-center " href="/"> <ContextMenu>
<BrandingGenericIcon className="max-w-[32px] max-h-[32px] mt-0.5" /> <ContextMenuTrigger>
<span className="gap-2 flex group hover:text-blue-500 hover:underline transition-all"> <Link className="gap-5 flex items-center " href="/">
<strong className="">MHSF</strong> <BrandingGenericIcon className="max-w-[32px] max-h-[32px] mt-0.5" />
<span className="text-muted-foreground group-hover:text-blue-500 transition-all"> <span className="gap-2 flex group hover:text-blue-500 hover:underline transition-all">
v{version} <strong className="">MHSF</strong>
</span> <span className="text-muted-foreground group-hover:text-blue-500 transition-all">
</span> v{version}
</Link> </span>
</ContextMenuTrigger> </span>
<ContextMenuContent className="overflow-hidden min-w-[300px]"> </Link>
<DropdownMenuSeparator>Platform</DropdownMenuSeparator> </ContextMenuTrigger>
<Link href="Special:Root"> <ContextMenuContent className="overflow-hidden min-w-[300px]">
<ContextMenuItem> <DropdownMenuSeparator>Platform</DropdownMenuSeparator>
<span className="pl-2 flex gap-2 items-center"> <Link href="Special:Root">
<ServerCrash size={16} /> Go to Dynamic Home Page <ContextMenuItem>
</span> <span className="pl-2 flex gap-2 items-center">
</ContextMenuItem> <ServerCrash size={16} /> Go to Dynamic Home Page
</Link> </span>
</ContextMenuItem>
</Link>
<Link href="/home"> <Link href="/home">
<ContextMenuItem> <ContextMenuItem>
<span className="pl-2 flex gap-2 items-center"> <span className="pl-2 flex gap-2 items-center">
<Home size={16} /> Go to Home Page <Home size={16} /> Go to Home Page
</span> </span>
</ContextMenuItem> </ContextMenuItem>
</Link> </Link>
<ContextMenuSeparator /> <ContextMenuSeparator />
<ContextMenuItem <ContextMenuItem
onClick={() => { onClick={() => {
clipboard.writeText(brandingIconClipboard); clipboard.writeText(brandingIconClipboard);
toast.success("Copied icon to clipboard!"); toast.success("Copied icon to clipboard!");
}} }}
> >
<span className="pl-2 flex gap-2 items-center"> <span className="pl-2 flex gap-2 items-center">
<Image size={16} /> Copy Logo as SVG <Image size={16} /> Copy Logo as SVG
</span> </span>
</ContextMenuItem> </ContextMenuItem>
<ContextMenuSeparator /> <ContextMenuSeparator />
<Link href="Special:GitHub"> <Link href="Special:GitHub">
<ContextMenuItem> <ContextMenuItem>
<span className="pl-2 flex gap-2 items-center"> <span className="pl-2 flex gap-2 items-center">
<Github /> Open GitHub <Github /> Open GitHub
</span> </span>
</ContextMenuItem> </ContextMenuItem>
</Link> </Link>
<Link href="Special:GitHub/releases"> <Link href="Special:GitHub/releases">
<ContextMenuItem> <ContextMenuItem>
<span className="pl-2 flex gap-2 items-center"> <span className="pl-2 flex gap-2 items-center">
<Github /> Open GitHub Releases <Github /> Open GitHub Releases
</span> </span>
</ContextMenuItem> </ContextMenuItem>
</Link> </Link>
</ContextMenuContent> </ContextMenuContent>
</ContextMenu> </ContextMenu>
</span> </span>
<span className="mr-3 flex items-center"> <span className="mr-3 flex items-center">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger> <SignedOut>
<SignedOut> <DropdownMenuTrigger asChild>
<Button <Button
className={cn( className={cn(
"rounded-full flex items-center", "rounded-full flex items-center",
pathname !== null && animatedTopbarPages.includes(pathname) pathname !== null && animatedTopbarPages.includes(pathname)
? "[--animation-delay:2000ms] opacity-0 animate-fade-in" ? "[--animation-delay:2000ms] opacity-0 animate-fade-in"
: "" : "",
)} )}
size="square-lg" size="square-lg"
variant="secondary" variant="secondary"
> >
<Menu size={16} /> <Menu size={16} />
</Button> </Button>
</SignedOut> </DropdownMenuTrigger>
<SignedIn> </SignedOut>
<Button <SignedIn>
size="square-lg" <DropdownMenuTrigger asChild>
variant="tertiary" <Button
className={cn( size="square-lg"
"rounded-full flex items-center", variant="tertiary"
pathname !== null && animatedTopbarPages.includes(pathname) className={cn(
? "[--animation-delay:2000ms] opacity-0 animate-fade-in" "rounded-full flex items-center",
: "" pathname !== null && animatedTopbarPages.includes(pathname)
)} ? "[--animation-delay:2000ms] opacity-0 animate-fade-in"
> : "",
<NextImage )}
alt="Clerk Image" >
src={ <NextImage
user?.imageUrl === undefined alt="Clerk Image"
? "https://img.clerk.com/preview.png?size=144&seed=seed&initials=AD&isSquare=true&bgType=marble&bgColor=6c47ff&fgType=silhouette&fgColor=FFFFFF&type=user&w=48&q=75" src={
: user?.imageUrl user?.imageUrl === undefined
} ? "https://img.clerk.com/preview.png?size=144&seed=seed&initials=AD&isSquare=true&bgType=marble&bgColor=6c47ff&fgType=silhouette&fgColor=FFFFFF&type=user&w=48&q=75"
width={26} : user?.imageUrl
height={26} }
className="rounded-full" width={26}
/> height={26}
</Button> className="rounded-full"
</SignedIn> />
</DropdownMenuTrigger> </Button>
<DropdownMenuContent className="max-w-[280px] w-[280px] mt-2 mr-2"> </DropdownMenuTrigger>
<MenuDropdown /> </SignedIn>
</DropdownMenuContent> <DropdownMenuContent className="max-w-[280px] w-[280px] mt-2 mr-2">
</DropdownMenu> <MenuDropdown />
<SignedIn> </DropdownMenuContent>
<div </DropdownMenu>
className="absolute right-0 -z-10 h-full <SignedIn>
<div
className="absolute right-0 -z-10 h-full
overflow-hidden w-full ml-auto" overflow-hidden w-full ml-auto"
style={{ borderRadius: "inherit" }} style={{ borderRadius: "inherit" }}
> >
<img <img
src={user?.imageUrl ?? ""} src={user?.imageUrl ?? ""}
className="blur-2xl -z-10 object-cover w-48 h-48 opacity-20 dark:opacity-50 ml-auto" className="blur-2xl -z-10 object-cover w-48 h-48 opacity-20 dark:opacity-50 ml-auto"
alt="" alt=""
/> />
</div> </div>
</SignedIn> </SignedIn>
</span> </span>
</div> </div>
); );
} }

@ -2,25 +2,135 @@ import { Button } from "@/components/ui/button";
import type { Filter } from "@/lib/types/filter"; import type { Filter } from "@/lib/types/filter";
import type { Sort } from "@/lib/types/sort"; import type { Sort } from "@/lib/types/sort";
import { ModificationFileCreationDialog } from "./modification-file-creation-dialog"; import { ModificationFileCreationDialog } from "./modification-file-creation-dialog";
import { useUser } from "@clerk/nextjs";
import { useEffect, useState } from "react";
import { useIframeCommunication } from "@/lib/hooks/use-iframe-communication";
type Action = Filter | Sort | { customAction: string }; type Action = Filter | Sort | { customAction: string };
export type ClerkEmbeddedFilter<T> = {
type: string;
metadata: T;
};
export function ModificationAction({ value }: { value?: Action }) { export function ModificationAction({ value }: { value?: Action }) {
return ( const { isSignedIn, user } = useUser();
<> const [applied, setApplied] = useState<number | undefined>();
{value !== undefined && "customAction" in value ? ( const communication = useIframeCommunication();
<ModificationFileCreationDialog
type={value.customAction.endsWith("sort") ? "sort" : "filter"} const findExisting = () => {
> if (!(value !== undefined && "customAction" in value)) {
<Button size="sm" className="mt-1"> const filter = value as Filter;
{value.customAction === "custom-sort" let existing = -1;
? "Create Sort" if (isSignedIn)
: "Create Filter"} existing = (
</Button> (user.unsafeMetadata.filters as Array<
</ModificationFileCreationDialog> ClerkEmbeddedFilter<unknown>
) : ( >) ?? []
<Button size="sm">Apply</Button> ).findIndex(
)} (c) =>
</> JSON.stringify(c.metadata) ===
); JSON.stringify(filter.toIdentifier()) &&
c.type === filter.getSpecificFilterId(),
);
else
existing = (
(JSON.parse(localStorage.getItem("mhsf__filters") ?? "[]") as Array<
ClerkEmbeddedFilter<unknown>
>) ?? []
).findIndex(
(c) =>
JSON.stringify(c.metadata) === JSON.stringify(filter.toIdentifier()) &&
c.type === filter.getSpecificFilterId(),
);
return existing;
}
return -1;
};
useEffect(() => setApplied(findExisting()))
return (
<>
{value !== undefined && "customAction" in value ? (
<ModificationFileCreationDialog
type={value.customAction.endsWith("sort") ? "sort" : "filter"}
>
<Button size="sm" className="mt-1">
{value.customAction === "custom-sort"
? "Create Sort"
: "Create Filter"}
</Button>
</ModificationFileCreationDialog>
) : (
<Button
size="sm"
className="mt-1"
onClick={async () => {
if (value?.type() === "filter") {
const filter = value as Filter;
const existing = findExisting();
if (isSignedIn) {
const existingArray =
(user.unsafeMetadata.filters as Array<
ClerkEmbeddedFilter<unknown>
>) ?? [];
existingArray.splice(existing, 1);
if (existing === -1)
await user.update({
unsafeMetadata: {
...user.unsafeMetadata,
filters: [
{
type: filter.getSpecificFilterId(),
metadata: filter.toIdentifier(),
},
...((user.unsafeMetadata.filters as Array<
ClerkEmbeddedFilter<unknown>
>) ?? []),
] as Array<ClerkEmbeddedFilter<unknown>>,
},
});
else
await user.update({
unsafeMetadata: {
filters: existingArray,
...user.unsafeMetadata,
},
});
} else {
const existingArray =
(JSON.parse(
localStorage.getItem("mhsf__filters") ?? "[]",
) as Array<ClerkEmbeddedFilter<unknown>>) ?? [];
existingArray.splice(existing, 1);
if (existing === -1)
localStorage.setItem(
"mhsf__filters",
JSON.stringify([
{
type: filter.getSpecificFilterId(),
metadata: filter.toIdentifier(),
},
...((JSON.parse(
localStorage.getItem("mhsf__filters") ?? "[]",
) as Array<ClerkEmbeddedFilter<unknown>>) ?? []),
]),
);
else
localStorage.setItem("mhsf__filters", JSON.stringify(existingArray));
}
setApplied(findExisting());
}
communication.fromIframe.send("rerender-servers", {});
}}
>
{applied === -1 ? "A" : "Una"}pply
</Button>
)}
</>
);
} }

@ -41,6 +41,9 @@ export function ModificationFrame() {
if (c.from === "iframe") if (c.from === "iframe")
communication.toIframe.send("ping", {from: "top-layer"}) communication.toIframe.send("ping", {from: "top-layer"})
}) })
communication.toIframe.handle("rerender-servers", (c) => {
window.dispatchEvent(new Event("update-modification-stack"))
})
}, [ref]) }, [ref])
return <iframe ref={ref} src="/servers/embedded/sl-modification-frame" height={800} title="Server-list Modification Frame" /> return <iframe ref={ref} src="/servers/embedded/sl-modification-frame" height={800} title="Server-list Modification Frame" />

@ -36,37 +36,92 @@ import { miniMessage } from "minimessage-js";
import { toast } from "sonner"; import { toast } from "sonner";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Material } from "@/components/ui/material"; import { Material } from "@/components/ui/material";
import { useState } from "react";
import { useMHSFServer } from "@/lib/hooks/use-mhsf-server";
import Markdown from "react-markdown";
import { Button } from "@/components/ui/button";
import { Ellipsis, EllipsisVertical, Shuffle } from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { RearrangeDrawer } from "../rearrange/rearrange-drawer";
export function MOTDRow({ server }: { server: ServerResponse }) { export function MOTDRow({
const clipboard = useClipboard(); server,
mhsfData,
}: { server: ServerResponse; mhsfData: ReturnType<typeof useMHSFServer> }) {
const clipboard = useClipboard();
const [tab, setTab] = useState("motd");
return ( return (
<Material className="p-4 relative h-[250px]"> <Material className="p-4 relative h-[250px]">
<strong className="text-lg">MOTD</strong> <span className="flex gap-4 justify-between items-center">
<br /> <span className="flex gap-4 items-center">
<Separator className="my-2" /> <strong className="text-lg max-lg:hidden">
<MOTDRenderer {tab === "motd" ? "MOTD" : "Description"}
className={cn("mt-2 break-all overflow-y-auto max-h-[150px]")} </strong>
minecraftFont <button
> type="button"
{server.motd} className={cn(
</MOTDRenderer> "text-sm cursor-pointer hover:bg-slate-100 dark:hover:bg-zinc-700/30 transition-all duration-75 disabled:opacity-50 disabled:pointer-events-none",
<br /> "rounded-xl px-2 flex items-center gap-2",
<small className="absolute bottom-[10px]"> tab === "motd" && "bg-slate-100 dark:bg-zinc-700/30 font-medium",
{server.motd.length} characters,{" "} )}
<button onClick={() => setTab("motd")}
className="cursor-pointer underline" >
type="button" MOTD
onClick={() => { </button>
clipboard.writeText( {mhsfData.server?.customizationData.description !== undefined && (
miniMessage().toHTML(miniMessage().deserialize(server.motd)) <button
); type="button"
toast.success("Copied to clipboard."); className={cn(
}} "text-sm cursor-pointer hover:bg-slate-100 dark:hover:bg-zinc-700/30 transition-all duration-75 disabled:opacity-50 disabled:pointer-events-none",
> "rounded-xl px-2 flex items-center gap-2",
click to copy HTML tab === "description" &&
</button> "bg-slate-100 dark:bg-zinc-700/30 font-medium",
</small> )}
</Material> onClick={() => setTab("description")}
); >
Description
</button>
)}
</span>
</span>
<Separator className="my-2" />
{tab === "motd" && (
<>
<MOTDRenderer
className={cn("mt-2 break-all overflow-y-auto max-h-[150px]")}
minecraftFont
>
{server.motd}
</MOTDRenderer>
<br />
<small className="absolute bottom-[10px]">
{server.motd.length} characters,{" "}
<button
className="cursor-pointer underline"
type="button"
onClick={() => {
clipboard.writeText(
miniMessage().toHTML(miniMessage().deserialize(server.motd)),
);
toast.success("Copied to clipboard.");
}}
>
click to copy HTML
</button>
</small>
</>
)}
{tab === "description" && (
<div className="prose mt-2 break-words overflow-y-auto max-h-[175px] dark:prose-invert">
<Markdown>{mhsfData.server?.customizationData.description}</Markdown>
</div>
)}
</Material>
);
} }

@ -13,69 +13,69 @@ import { DebugProvider } from "./debug/debug-provider";
import { ReportingProvider } from "./reporting/reporting-provider"; import { ReportingProvider } from "./reporting/reporting-provider";
export function ServerProvider({ serverId }: { serverId: string }) { export function ServerProvider({ serverId }: { serverId: string }) {
const { server, error, loading } = useServer({ id: serverId }); const { server, error, loading } = useServer({ id: serverId });
const settings = useSettingsStore(); const settings = useSettingsStore();
const mhsf = useMHSFServer(serverId); const mhsf = useMHSFServer(serverId);
if (error !== null) if (error !== null)
return ( return (
<div className="absolute top-[50%] left-[50%]"> <div className="absolute top-[50%] left-[50%]">
<Placeholder <Placeholder
icon={<X />} icon={<X />}
title="Error while fetching server" title="Error while fetching server"
description={ description={
<> <>
Try again later <br /> If this occurs again, please contact Try again later <br /> If this occurs again, please contact
support or make a GitHub issue. <br /> {error} support or make a GitHub issue. <br /> {error}
</> </>
} }
/> />
</div> </div>
); );
return ( return (
<DebugProvider <DebugProvider
debugOptions={{ debugOptions={{
serverName: (server ?? { name: "" }).name, serverName: (server ?? { name: "" }).name,
serverId: serverId, serverId: serverId,
mhsfData: mhsf.server, mhsfData: mhsf.server,
serverData: server, serverData: server,
onlineServerData: null, onlineServerData: null,
}} }}
> >
{loading || mhsf.loading ? ( {loading || mhsf.loading ? (
<div className="absolute top-[50%] left-[50%] transform -translate-x-1/2 -translate-y-1/2 block justify-center text-center gap-2"> <div className="absolute top-[50%] left-[50%] transform -translate-x-1/2 -translate-y-1/2 block justify-center text-center gap-2">
<span className="w-full flex justify-center"> <span className="w-full flex justify-center">
<Spinner /> <Spinner />
</span> </span>
<span> <span>
<AnimatedText <AnimatedText
text={ text={
loading && mhsf.loading loading && mhsf.loading
? "Loading server and MHSF data..." ? "Loading server and MHSF data..."
: loading : loading
? "Loading server data..." ? "Loading server data..."
: "Loading MHSF data..." : "Loading MHSF data..."
} }
className="text-center w-full mt-2" className="text-center w-full mt-2"
/> />
</span> </span>
{settings.get("debug-mode") === "true" && ( {settings.get("debug-mode") === "true" && (
<Button <Button
onClick={() => window.dispatchEvent(new Event("open-debug-menu"))} onClick={() => window.dispatchEvent(new Event("open-debug-menu"))}
> >
Debug Stack Debug Stack
</Button> </Button>
)} )}
</div> </div>
) : ( ) : (
<div className="px-10"> <div className="px-10">
<ReportingProvider server={mhsf}> <ReportingProvider server={mhsf}>
<ServerMainPage server={server as ServerResponse} mhsfData={mhsf} /> <ServerMainPage server={server as ServerResponse} mhsfData={mhsf} />
</ReportingProvider> </ReportingProvider>
</div> </div>
)} )}
</DebugProvider> </DebugProvider>
); );
} }

@ -38,8 +38,8 @@ export function ServerRows({ server, mhsfData }: { server: ServerResponse, mhsfD
const clipboard = useClipboard(); const clipboard = useClipboard();
return ( return (
<span className="lg:grid lg:grid-cols-3 w-full gap-3"> <span className="lg:grid lg:grid-cols-2 w-full gap-3">
<MOTDRow server={server} /> <MOTDRow server={server} mhsfData={mhsfData}/>
<StatisticsMainRow server={server} mhsfData={mhsfData} /> <StatisticsMainRow server={server} mhsfData={mhsfData} />
</span> </span>
); );

@ -32,7 +32,7 @@ export function StatisticsMainRow({
return ( return (
<Material <Material
className="relative col-span-2 h-[250px] max-lg:mt-3" className="relative h-[250px] max-lg:mt-3"
padding="none" padding="none"
> >
<div className="p-4"> <div className="p-4">

@ -0,0 +1,62 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2025 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
import { useUser } from "@clerk/nextjs";
import { Editor } from "@monaco-editor/react";
import { useEffect, useState, type ReactNode } from "react";
export function ClerkMetadataPopup({children}: {children: ReactNode | ReactNode[] | undefined}) {
const [mdType, setMDType] = useState<"public" | "unsafe" | null>(null)
const [open, setOpen] = useState(false);
const {user} = useUser();
useEffect(() => {
window.addEventListener("open-public-clerkmd", () => {
setMDType("public")
setOpen(true);
})
window.addEventListener("open-unsafe-clerkmd", () => {
setMDType("unsafe")
setOpen(true);
})
})
return <>
{children}
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="min-w-[850px]">
<DialogTitle>{mdType?.toLocaleUpperCase()} metadata</DialogTitle>
<Editor options={{domReadOnly: true, readOnly: true}} height={500} width={800} language="json" value={JSON.stringify(mdType === "public" ? user?.publicMetadata : user?.unsafeMetadata, null, 2)}/>
</DialogContent>
</Dialog>
</>
}

@ -29,38 +29,77 @@
*/ */
import { Material } from "@/components/ui/material"; import { Material } from "@/components/ui/material";
import { Setting, SettingContent, SettingDescription, SettingMeta, SettingTitle } from "./setting"; import {
Setting,
SettingContent,
SettingDescription,
SettingMeta,
SettingTitle,
} from "./setting";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { AnimatedText } from "@/components/ui/animated-text"; import { AnimatedText } from "@/components/ui/animated-text";
import { useState } from "react"; import { useEffect, useState } from "react";
import { loadingList } from "../server-page/util"; import { loadingList } from "../server-page/util";
import { ClerkMetadataPopup } from "./clerk-metadata-popup";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Switch } from "@/components/ui/switch";
import { Link } from "@/components/util/link";
import { useSettingsStore } from "@/lib/hooks/use-settings-store";
export function DebugSettings() { export function DebugSettings() {
const [randomText, setRandomText] = useState("") const [randomText, setRandomText] = useState("");
return ( return (
<Material className="mt-6 grid gap-4"> <Material className="mt-6 grid gap-4">
<h2 className="text-xl font-semibold text-inherit">Debug Settings</h2> <h2 className="text-xl font-semibold text-inherit">Debug Settings</h2>
<Setting> <Setting>
<SettingContent> <SettingContent>
<SettingMeta> <SettingMeta>
<SettingTitle> <SettingTitle>Generate loading text</SettingTitle>
Generate loading text <SettingDescription>
</SettingTitle> Generate a random loading text
<SettingDescription> </SettingDescription>
Generate a random loading text </SettingMeta>
</SettingDescription> <div className="block pb-6">
</SettingMeta> <Button
<div className="block pb-6"> onClick={() => {
<Button onClick={() => { setRandomText(
setRandomText(loadingList[Math.floor(Math.random() * loadingList.length)]) loadingList[Math.floor(Math.random() * loadingList.length)],
}}> );
Generate }}
</Button> >
<AnimatedText className="font-bold" text={randomText + "..."}/> Generate
</div> </Button>
</SettingContent> <AnimatedText className="font-bold" text={randomText + "..."} />
</Setting> </div>
</Material> </SettingContent>
); </Setting>
<ClerkMetadataPopup>
<Setting>
<SettingContent>
<SettingMeta>
<SettingTitle>View Clerk metadata</SettingTitle>
<SettingDescription>
View any Clerk metadata for your user.
</SettingDescription>
</SettingMeta>
<DropdownMenu>
<DropdownMenuTrigger>
<Button>Open metadata</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={() => window.dispatchEvent(new Event("open-public-clerkmd"))}>Public</DropdownMenuItem>
<DropdownMenuItem onClick={() => window.dispatchEvent(new Event("open-unsafe-clerkmd"))}>Unsafe</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SettingContent>
</Setting>
</ClerkMetadataPopup>
</Material>
);
} }

@ -61,7 +61,7 @@ const badgeVariants = cva(
"purple-subtle": `bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 "purple-subtle": `bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400
ring-purple-400 dark:ring-purple-500/30`, ring-purple-400 dark:ring-purple-500/30`,
rainbow: rainbow:
"text-white ring-transparent [background:_linear-gradient(45deg,rgba(255,_0,_0,_1)_0%,rgba(255,_154,_0,_1)_10%,rgba(208,_222,_33,_1)_20%,rgba(79,_220,_74,_1)_30%,rgba(63,_218,_216,_1)_40%,rgba(47,_201,_226,_1)_50%,rgba(28,_127,_238,_1)_60%,rgba(95,_21,_242,_1)_70%,rgba(186,_12,_248,_1)_80%,rgba(251,_7,_217,_1)_90%,rgba(255,_0,_0,_1)_100%);] backdrop-blur-sm opacity-60 ", "text-white ring-transparent z-10 [background:_linear-gradient(45deg,rgba(255,_0,_0,_1)_0%,rgba(255,_154,_0,_1)_10%,rgba(208,_222,_33,_1)_20%,rgba(79,_220,_74,_1)_30%,rgba(63,_218,_216,_1)_40%,rgba(47,_201,_226,_1)_50%,rgba(28,_127,_238,_1)_60%,rgba(95,_21,_242,_1)_70%,rgba(186,_12,_248,_1)_80%,rgba(251,_7,_217,_1)_90%,rgba(255,_0,_0,_1)_100%);] backdrop-blur-sm opacity-60 ",
custom: "", custom: "",
}, },
allowIconOnly: { allowIconOnly: {

@ -28,6 +28,8 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
"use client";
import { useTheme } from "@/lib/hooks/use-theme"; import { useTheme } from "@/lib/hooks/use-theme";
import type { SVGProps } from "react"; import type { SVGProps } from "react";
const Github = (props: SVGProps<SVGSVGElement>) => { const Github = (props: SVGProps<SVGSVGElement>) => {

@ -30,11 +30,13 @@
import { import {
ArrowDownUpIcon, ArrowDownUpIcon,
ServerCog,
SlidersHorizontal, SlidersHorizontal,
type LucideIcon, type LucideIcon,
} from "lucide-react"; } from "lucide-react";
import type { Filter } from "../lib/types/filter"; import { type Filter } from "../lib/types/filter";
import type { Sort } from "../lib/types/sort"; import type { Sort } from "../lib/types/sort";
import { TagFilter } from "@/lib/types/filters/tag-filter";
type ModDBCategory = { type ModDBCategory = {
displayTitle: string; displayTitle: string;
@ -78,5 +80,18 @@ export const serverModDB: ModDBCategory[] = [
__custom: true, __custom: true,
// Entries are already pre-loaded. // Entries are already pre-loaded.
entries: [] entries: []
},
{
displayTitle: "Tag Filters",
description: "These are filters that are associated with an assortment of tags.",
entries: [
{
name: "Always Online",
description: "All servers that are always online.",
color: "#a380e0",
value: new TagFilter(2, false),
icon: ServerCog
}
]
} }
]; ];

@ -36,10 +36,12 @@ import { tryCatch } from "../try-catch";
import { transpileTypeScript } from "@/app/(sl-modification-frame)/servers/embedded/sl-modification-frame/file/[filename]/page"; import { transpileTypeScript } from "@/app/(sl-modification-frame)/servers/embedded/sl-modification-frame/file/[filename]/page";
import { useUser } from "@clerk/nextjs"; import { useUser } from "@clerk/nextjs";
import type { ClerkCustomActivatedModification } from "@/components/feat/server-list/modification/modification-file-creation-dialog"; import type { ClerkCustomActivatedModification } from "@/components/feat/server-list/modification/modification-file-creation-dialog";
import { ClerkEmbeddedFilter } from "@/components/feat/server-list/modification/modification-action";
import { supportedFilters } from "../types/filter";
type EmbeddedFilter = { type EmbeddedFilter = {
identifier: string; identifier: string;
functionFilter: (server: OnlineServer) => boolean; functionFilter: (server: OnlineServer) => (boolean | Promise<boolean>);
}; };
type SortFunction<K> = (object1: K, object2: K) => number; type SortFunction<K> = (object1: K, object2: K) => number;
@ -57,23 +59,20 @@ export function useFilters(data: OnlineServer[]) {
const [sort, setSort] = useState<SortFunction<OnlineServer> | null>(null); const [sort, setSort] = useState<SortFunction<OnlineServer> | null>(null);
const { user, isSignedIn } = useUser(); const { user, isSignedIn } = useUser();
const updateServers = (newFilters: EmbeddedFilter[]) => { const updateServers = async (newFilters: EmbeddedFilter[]) => {
const modificationMap = data.map((v) => const modificationMap = await Promise.all(data.map((v) =>
newFilters.map((c) => c.functionFilter(v)), Promise.all(newFilters.map(async (c) => c.functionFilter(v))),
); ));
const resultData = data.filter( const resultData = data.filter(
(_, i) => !modificationMap[i].includes(false), (_, i) => !modificationMap[i].includes(false),
); );
const sortedData = sort === null ? resultData : resultData.sort(sort); const sortedData = sort === null ? resultData : resultData.sort(sort);
console.table({ sortedData, modificationMap, resultData, data }); console.log({ sortedData, modificationMap, resultData, data, newFilters });
if (sortedData.length !== 0) setFilteredData(sortedData);
if (sortedData.length !== 0)
setFilteredData(sortedData);
}; };
// biome-ignore lint: bruh
useEffect(() => { useEffect(() => {
if (filteredData.length === 0 || data.length === 0) { if (filteredData.length === 0 || data.length === 0) {
window.dispatchEvent(new Event("update-modification-stack")); window.dispatchEvent(new Event("update-modification-stack"));
@ -129,18 +128,18 @@ export function useFilters(data: OnlineServer[]) {
(async () => (async () =>
type === "filter" type === "filter"
? new Function( ? new Function(
"server", "server",
`${functionBody} `${functionBody}
return filter(server)`, return filter(server)`,
) )
: new Function( : new Function(
"serverA", "serverA",
"serverB", "serverB",
`${functionBody} `${functionBody}
return sort(serverA, serverB)`, return sort(serverA, serverB)`,
))(), ))(),
); );
if (filterErr) { if (filterErr) {
setTestModeStatus( setTestModeStatus(
@ -213,7 +212,13 @@ export function useFilters(data: OnlineServer[]) {
if (!t) if (!t)
window.addEventListener("update-modification-stack", async () => { window.addEventListener("update-modification-stack", async () => {
await user?.reload(); await user?.reload();
setLoading(true);
let newFilters: EmbeddedFilter[] = []; let newFilters: EmbeddedFilter[] = [];
const filters =
((isSignedIn ? user.unsafeMetadata.filters : JSON.parse(localStorage.getItem("mhsf__filters") ?? "[]")) as Array<
ClerkEmbeddedFilter<unknown>
>) ?? [];
if (isSignedIn) { if (isSignedIn) {
const activatedModifications = const activatedModifications =
(user.unsafeMetadata (user.unsafeMetadata
@ -232,58 +237,84 @@ export function useFilters(data: OnlineServer[]) {
(async () => (async () =>
c.testMode === "filter" c.testMode === "filter"
? new Function( ? new Function(
"server", "server",
`${functionBody} `${functionBody}
return filter(server)`, return filter(server)`,
) )
: new Function( : new Function(
"serverA", "serverA",
"serverB", "serverB",
`${functionBody} `${functionBody}
return sort(serverA, serverB)`, return sort(serverA, serverB)`,
))(), ))(),
); );
if (filterErr) { if (filterErr) {
toast.error( toast.error(
`Couldn't enable modification '${c.friendlyName}'. Please lint and test again.`, `Couldn't enable modification '${c.friendlyName}'. Please lint and test again.`,
); );
return { identifier: `file-${c.originalFileName}.ts`, functionFilter: () => true }; return {
identifier: `file-${c.originalFileName}.ts`,
functionFilter: () => true,
};
} }
if (typeof filterFunc === "function") { if (typeof filterFunc === "function") {
return { identifier: `file-${c.originalFileName}.ts`, functionFilter: filterFunc }; return {
identifier: `file-${c.originalFileName}.ts`,
functionFilter: filterFunc,
};
} }
toast.error( toast.error(
`Couldn't enable modification '${c.friendlyName}'. Please lint and test again.`, `Couldn't enable modification '${c.friendlyName}'. Please lint and test again.`,
); );
return { identifier: `file-${c.originalFileName}.ts`, functionFilter: () => true }; return {
identifier: `file-${c.originalFileName}.ts`,
functionFilter: () => true,
};
}), }),
)) as EmbeddedFilter[]; )) as EmbeddedFilter[];
// avoid duplicates // avoid duplicates
// biome-ignore lint/complexity/noForEach:
resolvedModifications.forEach((item) => { resolvedModifications.forEach((item) => {
setFilters((c) => { setFilters((c) => {
if (c.findIndex((i) => i.identifier === item.identifier) === -1) if (c.findIndex((i) => i.identifier === item.identifier) === -1)
return [ return [...c, item];
...c, return c;
item
]
else return c;
}); });
}) });
newFilters = resolvedModifications.map((item) => { newFilters = resolvedModifications.map((item) => {
return item; return item;
}); });
} }
// biome-ignore lint/complexity/noForEach:
filters.forEach((filter) => {
// Get back the filter type from the namespace
const filterType = supportedFilters.find(
(t) => filter.type === t.ns,
);
// Get back a filter with associated metadata
const parsedFilter = filterType?.fi(
filter.metadata as {
[key: string]: string | number | boolean;
},
);
newFilters.push({
identifier: filterType?.ns + (Math.random() * Math.random() * Math.random()).toString(),
functionFilter: (server: OnlineServer) => parsedFilter?.applyToServer({ online: server }) ?? true
})
});
console.log(newFilters); console.log(newFilters);
updateServers(newFilters); await updateServers(newFilters);
}); });
}, [data]); }, [data]);
console.log(filters); console.log(filters);
@ -293,7 +324,9 @@ export function useFilters(data: OnlineServer[]) {
testModeEnabled, testModeEnabled,
testModeLoading, testModeLoading,
testModeStatus, testModeStatus,
filterCount: filters.filter((item, index, array) => array.indexOf(item) === index).length + (sort === null ? 1 : 0), filterCount:
filters.filter((item, index, array) => array.indexOf(item) === index)
.length + (sort === null ? 1 : 0),
loading, loading,
}; };
} }

@ -0,0 +1,44 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2025 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
import { allTags } from "@/config/tags"
import { useUser } from "@clerk/nextjs"
export function useModificationsChange() {
const {isSignedIn} = useUser()
return {
addFilterData: async (namespace: string, identifier: { [key: string]: string | number | boolean }) => {
if (isSignedIn) {
}
}
}
}

@ -74,3 +74,24 @@ export function useSettingsStore() {
}, },
}; };
} }
// An exact copy of the API without Clerk
export function useNoClerkSettingsStore() {
return {
get: (key: string) => {
if (localStorage.getItem(key) === "true")
return true;
if (localStorage.getItem(key) === "false")
return false;
return localStorage.getItem(key);
},
set: async (
key: string,
value: string | boolean,
userEntry: boolean,
__unsafeMetadata = false
) => {
localStorage.setItem(key, value.toString());
},
};
}

@ -28,10 +28,39 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
import type { OnlineServer } from "./mh-server"; import { allTags } from "@/config/tags";
import type { OnlineServer, ServerResponse } from "./mh-server";
import type { MHSFData } from "./data";
import { TagFilter } from "./filters/tag-filter";
import { CategoryFilter } from "./filters/category-filter";
/* Any filter that can be converted back and forth from a string or a Filter object */
export interface Filter { export interface Filter {
toIdentifier(): string; type(): "filter";
fromIdentifier(identifier: string): Filter; toIdentifier(): { [key: string]: string | number | boolean };
applyToServer(server: OnlineServer): boolean; getSpecificFilterId(): string;
} fromIdentifier(identifier: {
[key: string]: string | number | boolean;
}): Filter;
applyToServer(server: {
online?: OnlineServer;
server?: ServerResponse;
mhsfData?: MHSFData;
}): Promise<boolean>;
}
export const supportedFilters: {
ns: string;
fi: (identifier: {
[key: string]: string | number | boolean;
}) => Filter;
}[] = [
{
ns: "app.mhsf.filter.tagFilter",
fi: new TagFilter(0, false).fromIdentifier
},
{
ns: "app.mhsf.filter.categoryFilter",
fi: new CategoryFilter(0).fromIdentifier
}
];

@ -0,0 +1,64 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2025 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
import { allCategories } from "@/config/tags";
import type { MHSFData } from "../data";
import type { Filter } from "../filter";
import type { OnlineServer, ServerResponse } from "../mh-server";
export class CategoryFilter implements Filter {
categoryIndex: number;
type(): "filter" {
return "filter";
}
toIdentifier(): { [key: string]: string | number | boolean } {
return { categoryIndex: this.categoryIndex };
}
fromIdentifier(identifier: { [key: string]: string | number | boolean; }): Filter {
return new CategoryFilter(identifier.categoryIndex as number);
}
getSpecificFilterId(): string {
return "app.mhsf.filter.categoryFilter";
}
applyToServer(server: { online?: OnlineServer; server?: ServerResponse; mhsfData?: MHSFData; }): Promise<boolean> {
if (server.online !== undefined)
return allCategories[this.categoryIndex].condition(server.online);
return new Promise((r) => r(true));
}
constructor(categoryIndex: number) {
this.categoryIndex = categoryIndex;
}
}

@ -0,0 +1,90 @@
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://mhsf.app/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2025 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
import { allTags } from "@/config/tags";
import type { MHSFData } from "../data";
import type { OnlineServer, ServerResponse } from "../mh-server";
import type { Filter } from "../filter";
export class TagFilter implements Filter {
tagId: string;
opposite: boolean;
type(): "filter" {
return "filter";
}
toIdentifier(): { [key: string]: string | number | boolean } {
return { tagId: this.tagId, opposite: this.opposite };
}
getSpecificFilterId(): string {
return "app.mhsf.filter.tagFilter";
}
fromIdentifier(identifier: {
[key: string]: string | number | boolean;
}): Filter {
return new TagFilter(identifier.tagId as string, identifier.opposite as boolean);
}
constructor(tagIndex: number | string, opposite: boolean) {
if (typeof tagIndex === "string") this.tagId = tagIndex;
else this.tagId = btoa(allTags[tagIndex].docsName);
this.opposite = opposite;
}
applyToServer(server: {
online?: OnlineServer;
server?: ServerResponse;
mhsfData?: MHSFData;
}): Promise<boolean> {
const result = (
(
allTags.find((c) => btoa(c.docsName) === this.tagId) ?? {
condition: () => true,
}
).condition ?? (() => true)
)(server);
console.log(result, server.online?.name, (
allTags.find((c) => btoa(c.docsName) === this.tagId) ?? {
condition: () => true,
}
));
if (typeof result === "boolean")
return new Promise((r) => r(this.opposite ? !result : result))
return new Promise((r) => {
result.then((c) => r(this.opposite ? !c : c))
});
}
}

@ -31,7 +31,11 @@
import type { OnlineServer } from "./mh-server"; import type { OnlineServer } from "./mh-server";
export interface Sort { export interface Sort {
toIdentifier(): string; type(): "sort";
fromIdentifier(identifier: string): Sort; toIdentifier(): { [key: string]: string | number | boolean };
getSpecificSortId(): string;
fromIdentifier(identifier: {
[key: string]: string | number | boolean;
}): Sort;
sortToServers(serverA: OnlineServer, serverB: OnlineServer): number; sortToServers(serverA: OnlineServer, serverB: OnlineServer): number;
} }

@ -49,6 +49,8 @@ export default process.env.NEXT_PUBLIC_IS_AUTH === "true"
? clerkMiddleware(async (auth, req) => { ? clerkMiddleware(async (auth, req) => {
const authRes = await auth(); const authRes = await auth();
const client = await clerkClient(); const client = await clerkClient();
const requestHeaders = new Headers(req.headers);
requestHeaders.set("x-url", req.url);
if (isRootRoute(req)) { if (isRootRoute(req)) {
switch (authRes.userId === null) { switch (authRes.userId === null) {
@ -70,6 +72,12 @@ export default process.env.NEXT_PUBLIC_IS_AUTH === "true"
new URL(`/server/v2/minehut/${minehutRes.server._id}`, req.url), new URL(`/server/v2/minehut/${minehutRes.server._id}`, req.url),
); );
} }
return NextResponse.next({
request: {
headers: requestHeaders,
},
});
}) })
: (request: NextRequest) => {}; : (request: NextRequest) => {};

@ -45,8 +45,6 @@ export default async function handler(
const result = await betterStackResult.json(); const result = await betterStackResult.json();
const url = await betterStackURL.json(); const url = await betterStackURL.json();
console.log(result)
const filtered = result.data.filter( const filtered = result.data.filter(
(c: any) => (c: any) =>
c.attributes.ends_at === null && c.attributes.ends_at === null &&

@ -57,7 +57,7 @@ export default async function handler(
return res.status(401).json({ error: "Unauthorized" }); return res.status(401).json({ error: "Unauthorized" });
} }
if ( if (
(await (await clerkClient()).users.getUser(userId)).publicMetadata.player == (await (await clerkClient()).users.getUser(userId)).publicMetadata.player ===
undefined undefined
) { ) {
return res.status(401).json({ error: "Account not linked" }); return res.status(401).json({ error: "Account not linked" });
@ -68,7 +68,7 @@ export default async function handler(
const db = client.db(process.env.CUSTOM_MONGO_DB ?? "mhsf"); const db = client.db(process.env.CUSTOM_MONGO_DB ?? "mhsf");
const collection = db.collection("owned-servers"); const collection = db.collection("owned-servers");
if ((await collection.findOne({ server: server })) == undefined) { if ((await collection.findOne({ server: server })) === undefined) {
const mh = await fetch( const mh = await fetch(
process.env.MHSF_BACKEND_API_LOCATION ?? process.env.MHSF_BACKEND_API_LOCATION ??
"https://api.minehut.com/servers", "https://api.minehut.com/servers",
@ -116,7 +116,7 @@ export default async function handler(
.send({ message: "The linked account doesn't own the server." }); .send({ message: "The linked account doesn't own the server." });
} }
} }
if (i == servers.length) { if (i === servers.length) {
// Close the database, but don't close this // Close the database, but don't close this
// serverless instance until it happens // serverless instance until it happens
waitUntil(client.close()); waitUntil(client.close());

285
yarn.lock

@ -1059,6 +1059,13 @@
optionalDependencies: optionalDependencies:
"@img/sharp-libvips-darwin-arm64" "1.0.4" "@img/sharp-libvips-darwin-arm64" "1.0.4"
"@img/sharp-darwin-arm64@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz#e79a4756bea9a06a7aadb4391ee53cb154a4968c"
integrity sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==
optionalDependencies:
"@img/sharp-libvips-darwin-arm64" "1.1.0"
"@img/sharp-darwin-x64@0.33.5": "@img/sharp-darwin-x64@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61" resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61"
@ -1066,46 +1073,98 @@
optionalDependencies: optionalDependencies:
"@img/sharp-libvips-darwin-x64" "1.0.4" "@img/sharp-libvips-darwin-x64" "1.0.4"
"@img/sharp-darwin-x64@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.1.tgz#f1f1d386719f6933796415d84937502b7199a744"
integrity sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==
optionalDependencies:
"@img/sharp-libvips-darwin-x64" "1.1.0"
"@img/sharp-libvips-darwin-arm64@1.0.4": "@img/sharp-libvips-darwin-arm64@1.0.4":
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f"
integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg== integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==
"@img/sharp-libvips-darwin-arm64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz#843f7c09c7245dc0d3cfec2b3c83bb08799a704f"
integrity sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==
"@img/sharp-libvips-darwin-x64@1.0.4": "@img/sharp-libvips-darwin-x64@1.0.4":
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062"
integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ== integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==
"@img/sharp-libvips-darwin-x64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz#1239c24426c06a8e833815562f78047a3bfbaaf8"
integrity sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==
"@img/sharp-libvips-linux-arm64@1.0.4": "@img/sharp-libvips-linux-arm64@1.0.4":
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704"
integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA== integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==
"@img/sharp-libvips-linux-arm64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz#20d276cefd903ee483f0441ba35961679c286315"
integrity sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==
"@img/sharp-libvips-linux-arm@1.0.5": "@img/sharp-libvips-linux-arm@1.0.5":
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197"
integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g== integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==
"@img/sharp-libvips-linux-arm@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz#067c0b566eae8063738cf1b1db8f8a8573b5465c"
integrity sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==
"@img/sharp-libvips-linux-ppc64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz#682334595f2ca00e0a07a675ba170af165162802"
integrity sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==
"@img/sharp-libvips-linux-s390x@1.0.4": "@img/sharp-libvips-linux-s390x@1.0.4":
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce"
integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA== integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==
"@img/sharp-libvips-linux-s390x@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz#82fcd68444b3666384235279c145c2b28d8ee302"
integrity sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==
"@img/sharp-libvips-linux-x64@1.0.4": "@img/sharp-libvips-linux-x64@1.0.4":
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz#d4c4619cdd157774906e15770ee119931c7ef5e0" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz#d4c4619cdd157774906e15770ee119931c7ef5e0"
integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw== integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==
"@img/sharp-libvips-linux-x64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz#65b2b908bf47156b0724fde9095676c83a18cf5a"
integrity sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==
"@img/sharp-libvips-linuxmusl-arm64@1.0.4": "@img/sharp-libvips-linuxmusl-arm64@1.0.4":
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5"
integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA== integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==
"@img/sharp-libvips-linuxmusl-arm64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz#72accf924e80b081c8db83b900b444a67c203f01"
integrity sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==
"@img/sharp-libvips-linuxmusl-x64@1.0.4": "@img/sharp-libvips-linuxmusl-x64@1.0.4":
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff"
integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw== integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==
"@img/sharp-libvips-linuxmusl-x64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz#1fa052737e203f46bf44192acd01f9faf11522d7"
integrity sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==
"@img/sharp-linux-arm64@0.33.5": "@img/sharp-linux-arm64@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22" resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22"
@ -1113,6 +1172,13 @@
optionalDependencies: optionalDependencies:
"@img/sharp-libvips-linux-arm64" "1.0.4" "@img/sharp-libvips-linux-arm64" "1.0.4"
"@img/sharp-linux-arm64@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.1.tgz#c36ef964499b8cfc2d2ed88fe68f27ce41522c80"
integrity sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==
optionalDependencies:
"@img/sharp-libvips-linux-arm64" "1.1.0"
"@img/sharp-linux-arm@0.33.5": "@img/sharp-linux-arm@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff" resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff"
@ -1120,6 +1186,13 @@
optionalDependencies: optionalDependencies:
"@img/sharp-libvips-linux-arm" "1.0.5" "@img/sharp-libvips-linux-arm" "1.0.5"
"@img/sharp-linux-arm@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.1.tgz#c96e38ff028d645912bb0aa132a7178b96997866"
integrity sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==
optionalDependencies:
"@img/sharp-libvips-linux-arm" "1.1.0"
"@img/sharp-linux-s390x@0.33.5": "@img/sharp-linux-s390x@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667" resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667"
@ -1127,6 +1200,13 @@
optionalDependencies: optionalDependencies:
"@img/sharp-libvips-linux-s390x" "1.0.4" "@img/sharp-libvips-linux-s390x" "1.0.4"
"@img/sharp-linux-s390x@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.1.tgz#8ac58d9a49dcb08215e76c8d450717979b7815c3"
integrity sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==
optionalDependencies:
"@img/sharp-libvips-linux-s390x" "1.1.0"
"@img/sharp-linux-x64@0.33.5": "@img/sharp-linux-x64@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz#d806e0afd71ae6775cc87f0da8f2d03a7c2209cb" resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz#d806e0afd71ae6775cc87f0da8f2d03a7c2209cb"
@ -1134,6 +1214,13 @@
optionalDependencies: optionalDependencies:
"@img/sharp-libvips-linux-x64" "1.0.4" "@img/sharp-libvips-linux-x64" "1.0.4"
"@img/sharp-linux-x64@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.1.tgz#3d8652efac635f0dba39d5e3b8b49515a2b2dee1"
integrity sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==
optionalDependencies:
"@img/sharp-libvips-linux-x64" "1.1.0"
"@img/sharp-linuxmusl-arm64@0.33.5": "@img/sharp-linuxmusl-arm64@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b" resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b"
@ -1141,6 +1228,13 @@
optionalDependencies: optionalDependencies:
"@img/sharp-libvips-linuxmusl-arm64" "1.0.4" "@img/sharp-libvips-linuxmusl-arm64" "1.0.4"
"@img/sharp-linuxmusl-arm64@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.1.tgz#b267e6a3e06f9e4d345cde471e5480c5c39e6969"
integrity sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-arm64" "1.1.0"
"@img/sharp-linuxmusl-x64@0.33.5": "@img/sharp-linuxmusl-x64@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48" resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48"
@ -1148,6 +1242,13 @@
optionalDependencies: optionalDependencies:
"@img/sharp-libvips-linuxmusl-x64" "1.0.4" "@img/sharp-libvips-linuxmusl-x64" "1.0.4"
"@img/sharp-linuxmusl-x64@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.1.tgz#a8dee4b6227f348c4bbacaa6ac3dc584a1a80391"
integrity sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-x64" "1.1.0"
"@img/sharp-wasm32@0.33.5": "@img/sharp-wasm32@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1" resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1"
@ -1155,16 +1256,33 @@
dependencies: dependencies:
"@emnapi/runtime" "^1.2.0" "@emnapi/runtime" "^1.2.0"
"@img/sharp-wasm32@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.1.tgz#f7dfd66b6c231269042d3d8750c90f28b9ddcba1"
integrity sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==
dependencies:
"@emnapi/runtime" "^1.4.0"
"@img/sharp-win32-ia32@0.33.5": "@img/sharp-win32-ia32@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9" resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9"
integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ== integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==
"@img/sharp-win32-ia32@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.1.tgz#4bc293705df76a5f0a02df66ca3dc12e88f61332"
integrity sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==
"@img/sharp-win32-x64@0.33.5": "@img/sharp-win32-x64@0.33.5":
version "0.33.5" version "0.33.5"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342" resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342"
integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg== integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==
"@img/sharp-win32-x64@0.34.1":
version "0.34.1"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.1.tgz#8a7922fec949f037c204c79f6b83238d2482384b"
integrity sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==
"@inngest/ai@^0.1.3": "@inngest/ai@^0.1.3":
version "0.1.3" version "0.1.3"
resolved "https://registry.yarnpkg.com/@inngest/ai/-/ai-0.1.3.tgz#25a86d08a8fe7288fdcde1bb02ad084ed3fa2166" resolved "https://registry.yarnpkg.com/@inngest/ai/-/ai-0.1.3.tgz#25a86d08a8fe7288fdcde1bb02ad084ed3fa2166"
@ -1688,10 +1806,10 @@
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.1.6.tgz#2fa863d8c568a56b1c8328a86e621b8bdd4f2a20" resolved "https://registry.yarnpkg.com/@next/env/-/env-15.1.6.tgz#2fa863d8c568a56b1c8328a86e621b8bdd4f2a20"
integrity sha512-d9AFQVPEYNr+aqokIiPLNK/MTyt3DWa/dpKveiAaVccUadFbhFEvY6FXYX2LJO2Hv7PHnLBu2oWwB4uBuHjr/w== integrity sha512-d9AFQVPEYNr+aqokIiPLNK/MTyt3DWa/dpKveiAaVccUadFbhFEvY6FXYX2LJO2Hv7PHnLBu2oWwB4uBuHjr/w==
"@next/env@15.2.0": "@next/env@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.2.0.tgz#4c3508ca2c0bb2bc324066818bb8d0415f767641" resolved "https://registry.yarnpkg.com/@next/env/-/env-15.3.1.tgz#fca98dcb90d92d555972cdbf03adf9aa982e2115"
integrity sha512-eMgJu1RBXxxqqnuRJQh5RozhskoNUDHBFybvi+Z+yK9qzKeG7dadhv/Vp1YooSZmCnegf7JxWuapV77necLZNA== integrity sha512-cwK27QdzrMblHSn9DZRV+DQscHXRuJv6MydlJRpFSqJWZrTYMLzKDeyueJNN9MGd8NNiUKzDQADAf+dMLXX7YQ==
"@next/env@^13.4.3": "@next/env@^13.4.3":
version "13.5.11" version "13.5.11"
@ -1717,80 +1835,80 @@
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.6.tgz#92f99badab6cb41f4c5c11a3feffa574bd6a9276" resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.6.tgz#92f99badab6cb41f4c5c11a3feffa574bd6a9276"
integrity sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw== integrity sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw==
"@next/swc-darwin-arm64@15.2.0": "@next/swc-darwin-arm64@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.2.0.tgz#51ebba2162330ee3e8b3412bf31defd94a7b85e7" resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.1.tgz#8f9589aed9f6816687440aa36a86376b3a16af58"
integrity sha512-rlp22GZwNJjFCyL7h5wz9vtpBVuCt3ZYjFWpEPBGzG712/uL1bbSkS675rVAUCRZ4hjoTJ26Q7IKhr5DfJrHDA== integrity sha512-hjDw4f4/nla+6wysBL07z52Gs55Gttp5Bsk5/8AncQLJoisvTBP0pRIBK/B16/KqQyH+uN4Ww8KkcAqJODYH3w==
"@next/swc-darwin-x64@15.1.6": "@next/swc-darwin-x64@15.1.6":
version "15.1.6" version "15.1.6"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.6.tgz#f56f4f8d5f6cb5d3915912ac95590d387f897da5" resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.6.tgz#f56f4f8d5f6cb5d3915912ac95590d387f897da5"
integrity sha512-x1jGpbHbZoZ69nRuogGL2MYPLqohlhnT9OCU6E6QFewwup+z+M6r8oU47BTeJcWsF2sdBahp5cKiAcDbwwK/lg== integrity sha512-x1jGpbHbZoZ69nRuogGL2MYPLqohlhnT9OCU6E6QFewwup+z+M6r8oU47BTeJcWsF2sdBahp5cKiAcDbwwK/lg==
"@next/swc-darwin-x64@15.2.0": "@next/swc-darwin-x64@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.0.tgz#90fd6c6cee494d4348342434cfb9ca9506eae895" resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.1.tgz#2df013226d848394ed7307188c141f0e6da4ab3e"
integrity sha512-DiU85EqSHogCz80+sgsx90/ecygfCSGl5P3b4XDRVZpgujBm5lp4ts7YaHru7eVTyZMjHInzKr+w0/7+qDrvMA== integrity sha512-q+aw+cJ2ooVYdCEqZVk+T4Ni10jF6Fo5DfpEV51OupMaV5XL6pf3GCzrk6kSSZBsMKZtVC1Zm/xaNBFpA6bJ2g==
"@next/swc-linux-arm64-gnu@15.1.6": "@next/swc-linux-arm64-gnu@15.1.6":
version "15.1.6" version "15.1.6"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.6.tgz#0aaffae519c93d1006419d7b98c34ebfd80ecacd" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.6.tgz#0aaffae519c93d1006419d7b98c34ebfd80ecacd"
integrity sha512-jar9sFw0XewXsBzPf9runGzoivajeWJUc/JkfbLTC4it9EhU8v7tCRLH7l5Y1ReTMN6zKJO0kKAGqDk8YSO2bg== integrity sha512-jar9sFw0XewXsBzPf9runGzoivajeWJUc/JkfbLTC4it9EhU8v7tCRLH7l5Y1ReTMN6zKJO0kKAGqDk8YSO2bg==
"@next/swc-linux-arm64-gnu@15.2.0": "@next/swc-linux-arm64-gnu@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.0.tgz#f10a26cdbacf2e3de2a02a926c72857b3cb613e1" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.1.tgz#d1c4e24b2b27c36a7ebc21ae0573e9e98f794143"
integrity sha512-VnpoMaGukiNWVxeqKHwi8MN47yKGyki5q+7ql/7p/3ifuU2341i/gDwGK1rivk0pVYbdv5D8z63uu9yMw0QhpQ== integrity sha512-wBQ+jGUI3N0QZyWmmvRHjXjTWFy8o+zPFLSOyAyGFI94oJi+kK/LIZFJXeykvgXUk1NLDAEFDZw/NVINhdk9FQ==
"@next/swc-linux-arm64-musl@15.1.6": "@next/swc-linux-arm64-musl@15.1.6":
version "15.1.6" version "15.1.6"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.6.tgz#e7398d3d31ca60033f708a718cd6c31edcee2e9a" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.6.tgz#e7398d3d31ca60033f708a718cd6c31edcee2e9a"
integrity sha512-+n3u//bfsrIaZch4cgOJ3tXCTbSxz0s6brJtU3SzLOvkJlPQMJ+eHVRi6qM2kKKKLuMY+tcau8XD9CJ1OjeSQQ== integrity sha512-+n3u//bfsrIaZch4cgOJ3tXCTbSxz0s6brJtU3SzLOvkJlPQMJ+eHVRi6qM2kKKKLuMY+tcau8XD9CJ1OjeSQQ==
"@next/swc-linux-arm64-musl@15.2.0": "@next/swc-linux-arm64-musl@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.0.tgz#1821c9a1dd17c441d8182f5cefd586f7902fcdb5" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.1.tgz#bce27533f9f046800f850a9c20832e8c15b10955"
integrity sha512-ka97/ssYE5nPH4Qs+8bd8RlYeNeUVBhcnsNUmFM6VWEob4jfN9FTr0NBhXVi1XEJpj3cMfgSRW+LdE3SUZbPrw== integrity sha512-IIxXEXRti/AulO9lWRHiCpUUR8AR/ZYLPALgiIg/9ENzMzLn3l0NSxVdva7R/VDcuSEBo0eGVCe3evSIHNz0Hg==
"@next/swc-linux-x64-gnu@15.1.6": "@next/swc-linux-x64-gnu@15.1.6":
version "15.1.6" version "15.1.6"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.6.tgz#d76c72508f4d79d6016cab0c52640b93e590cffb" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.6.tgz#d76c72508f4d79d6016cab0c52640b93e590cffb"
integrity sha512-SpuDEXixM3PycniL4iVCLyUyvcl6Lt0mtv3am08sucskpG0tYkW1KlRhTgj4LI5ehyxriVVcfdoxuuP8csi3kQ== integrity sha512-SpuDEXixM3PycniL4iVCLyUyvcl6Lt0mtv3am08sucskpG0tYkW1KlRhTgj4LI5ehyxriVVcfdoxuuP8csi3kQ==
"@next/swc-linux-x64-gnu@15.2.0": "@next/swc-linux-x64-gnu@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.0.tgz#522f55c7672346bab43bce0bcb35c4cb668ad20f" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.1.tgz#f90558d93bc25e01b0b271725e291863286753c4"
integrity sha512-zY1JduE4B3q0k2ZCE+DAF/1efjTXUsKP+VXRtrt/rJCTgDlUyyryx7aOgYXNc1d8gobys/Lof9P9ze8IyRDn7Q== integrity sha512-bfI4AMhySJbyXQIKH5rmLJ5/BP7bPwuxauTvVEiJ/ADoddaA9fgyNNCcsbu9SlqfHDoZmfI6g2EjzLwbsVTr5A==
"@next/swc-linux-x64-musl@15.1.6": "@next/swc-linux-x64-musl@15.1.6":
version "15.1.6" version "15.1.6"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.6.tgz#0b8ba80a53e65bf8970ed11ea923001e2512c7cb" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.6.tgz#0b8ba80a53e65bf8970ed11ea923001e2512c7cb"
integrity sha512-L4druWmdFSZIIRhF+G60API5sFB7suTbDRhYWSjiw0RbE+15igQvE2g2+S973pMGvwN3guw7cJUjA/TmbPWTHQ== integrity sha512-L4druWmdFSZIIRhF+G60API5sFB7suTbDRhYWSjiw0RbE+15igQvE2g2+S973pMGvwN3guw7cJUjA/TmbPWTHQ==
"@next/swc-linux-x64-musl@15.2.0": "@next/swc-linux-x64-musl@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.0.tgz#e23be1d046c9a630a0315588f9d692d9705ac355" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.1.tgz#639f143bd0f3fd6e1bde4b383dc6cd8a8ff12628"
integrity sha512-QqvLZpurBD46RhaVaVBepkVQzh8xtlUN00RlG4Iq1sBheNugamUNPuZEH1r9X1YGQo1KqAe1iiShF0acva3jHQ== integrity sha512-FeAbR7FYMWR+Z+M5iSGytVryKHiAsc0x3Nc3J+FD5NVbD5Mqz7fTSy8CYliXinn7T26nDMbpExRUI/4ekTvoiA==
"@next/swc-win32-arm64-msvc@15.1.6": "@next/swc-win32-arm64-msvc@15.1.6":
version "15.1.6" version "15.1.6"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.6.tgz#81b5dbbfdada2c05deef688e799af4a24097b65f" resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.6.tgz#81b5dbbfdada2c05deef688e799af4a24097b65f"
integrity sha512-s8w6EeqNmi6gdvM19tqKKWbCyOBvXFbndkGHl+c9YrzsLARRdCHsD9S1fMj8gsXm9v8vhC8s3N8rjuC/XrtkEg== integrity sha512-s8w6EeqNmi6gdvM19tqKKWbCyOBvXFbndkGHl+c9YrzsLARRdCHsD9S1fMj8gsXm9v8vhC8s3N8rjuC/XrtkEg==
"@next/swc-win32-arm64-msvc@15.2.0": "@next/swc-win32-arm64-msvc@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.0.tgz#9e2cb008b82c676dad7d632a43549f969cb2194f" resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.1.tgz#52ee1e63b192fec8f0230caf839cfc308d0d44d1"
integrity sha512-ODZ0r9WMyylTHAN6pLtvUtQlGXBL9voljv6ujSlcsjOxhtXPI1Ag6AhZK0SE8hEpR1374WZZ5w33ChpJd5fsjw== integrity sha512-yP7FueWjphQEPpJQ2oKmshk/ppOt+0/bB8JC8svPUZNy0Pi3KbPx2Llkzv1p8CoQa+D2wknINlJpHf3vtChVBw==
"@next/swc-win32-x64-msvc@15.1.6": "@next/swc-win32-x64-msvc@15.1.6":
version "15.1.6" version "15.1.6"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.6.tgz#131993c45ffd124fb4b15258e2f3f9669c143e3c" resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.6.tgz#131993c45ffd124fb4b15258e2f3f9669c143e3c"
integrity sha512-6xomMuu54FAFxttYr5PJbEfu96godcxBTRk1OhAvJq0/EnmFU/Ybiax30Snis4vdWZ9LGpf7Roy5fSs7v/5ROQ== integrity sha512-6xomMuu54FAFxttYr5PJbEfu96godcxBTRk1OhAvJq0/EnmFU/Ybiax30Snis4vdWZ9LGpf7Roy5fSs7v/5ROQ==
"@next/swc-win32-x64-msvc@15.2.0": "@next/swc-win32-x64-msvc@15.3.1":
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.0.tgz#d280f450a5b6dbb7437c3265f81ea62febf4bf3c" resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.1.tgz#df5ceb9c3b97bf0d61cb6e84f79bbf9e91a89d29"
integrity sha512-8+4Z3Z7xa13NdUuUAcpVNA6o76lNPniBd9Xbo02bwXQXnZgFvEopwY2at5+z7yHl47X9qbZpvwatZ2BRo3EdZw== integrity sha512-3PMvF2zRJAifcRNni9uMk/gulWfWS+qVI/pagd+4yLF5bcXPZPPH2xlYRYOsUjmCJOXSTAC2PjRzbhsRzR2fDQ==
"@nodelib/fs.scandir@2.1.5": "@nodelib/fs.scandir@2.1.5":
version "2.1.5" version "2.1.5"
@ -3915,10 +4033,10 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
"@types/react-dom@^19", "@types/react-dom@^19.0.3": "@types/react-dom@19.0.4", "@types/react-dom@^19":
version "19.1.2" version "19.0.4"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.2.tgz#bd1fe3b8c28a3a2e942f85314dcfb71f531a242f" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.4.tgz#bedba97f9346bd4c0fe5d39e689713804ec9ac89"
integrity sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw== integrity sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==
"@types/react-twemoji@^0.4.3": "@types/react-twemoji@^0.4.3":
version "0.4.3" version "0.4.3"
@ -3927,10 +4045,10 @@
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
"@types/react@*", "@types/react@^19", "@types/react@^19.0.8": "@types/react@*", "@types/react@19.0.10", "@types/react@^19":
version "19.1.2" version "19.0.10"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.2.tgz#11df86f66f188f212c90ecb537327ec68bfd593f" resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.10.tgz#d0c66dafd862474190fe95ce11a68de69ed2b0eb"
integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw== integrity sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==
dependencies: dependencies:
csstype "^3.0.2" csstype "^3.0.2"
@ -10221,12 +10339,12 @@ next@15.1.6:
"@next/swc-win32-x64-msvc" "15.1.6" "@next/swc-win32-x64-msvc" "15.1.6"
sharp "^0.33.5" sharp "^0.33.5"
next@15.2.0: next@^15.3.1:
version "15.2.0" version "15.3.1"
resolved "https://registry.yarnpkg.com/next/-/next-15.2.0.tgz#00f4619ae4322102b08c1a8bf315f7b757525508" resolved "https://registry.yarnpkg.com/next/-/next-15.3.1.tgz#69cf2c124e504db64e14fc75eb29bd64c0c787a7"
integrity sha512-VaiM7sZYX8KIAHBrRGSFytKknkrexNfGb8GlG6e93JqueCspuGte8i4ybn8z4ww1x3f2uzY4YpTaBEW4/hvsoQ== integrity sha512-8+dDV0xNLOgHlyBxP1GwHGVaNXsmp+2NhZEYrXr24GWLHtt27YrBPbPuHvzlhi7kZNYjeJNR93IF5zfFu5UL0g==
dependencies: dependencies:
"@next/env" "15.2.0" "@next/env" "15.3.1"
"@swc/counter" "0.1.3" "@swc/counter" "0.1.3"
"@swc/helpers" "0.5.15" "@swc/helpers" "0.5.15"
busboy "1.6.0" busboy "1.6.0"
@ -10234,15 +10352,15 @@ next@15.2.0:
postcss "8.4.31" postcss "8.4.31"
styled-jsx "5.1.6" styled-jsx "5.1.6"
optionalDependencies: optionalDependencies:
"@next/swc-darwin-arm64" "15.2.0" "@next/swc-darwin-arm64" "15.3.1"
"@next/swc-darwin-x64" "15.2.0" "@next/swc-darwin-x64" "15.3.1"
"@next/swc-linux-arm64-gnu" "15.2.0" "@next/swc-linux-arm64-gnu" "15.3.1"
"@next/swc-linux-arm64-musl" "15.2.0" "@next/swc-linux-arm64-musl" "15.3.1"
"@next/swc-linux-x64-gnu" "15.2.0" "@next/swc-linux-x64-gnu" "15.3.1"
"@next/swc-linux-x64-musl" "15.2.0" "@next/swc-linux-x64-musl" "15.3.1"
"@next/swc-win32-arm64-msvc" "15.2.0" "@next/swc-win32-arm64-msvc" "15.3.1"
"@next/swc-win32-x64-msvc" "15.2.0" "@next/swc-win32-x64-msvc" "15.3.1"
sharp "^0.33.5" sharp "^0.34.1"
nextjs-toploader@^1.6.12: nextjs-toploader@^1.6.12:
version "1.6.12" version "1.6.12"
@ -11042,14 +11160,7 @@ react-day-picker@8.10.1:
resolved "https://registry.yarnpkg.com/react-day-picker/-/react-day-picker-8.10.1.tgz#4762ec298865919b93ec09ba69621580835b8e80" resolved "https://registry.yarnpkg.com/react-day-picker/-/react-day-picker-8.10.1.tgz#4762ec298865919b93ec09ba69621580835b8e80"
integrity sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA== integrity sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==
react-dom@19.0.0: react-dom@^19.0.0, react-dom@^19.1.0:
version "19.0.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
dependencies:
scheduler "^0.25.0"
react-dom@^19.0.0:
version "19.1.0" version "19.1.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623"
integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==
@ -11222,12 +11333,7 @@ react-transition-group@^4.4.5:
loose-envify "^1.4.0" loose-envify "^1.4.0"
prop-types "^15.6.2" prop-types "^15.6.2"
react@19.0.0: react@^19.0.0, react@^19.1.0:
version "19.0.0"
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
react@^19.0.0:
version "19.1.0" version "19.1.0"
resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75"
integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==
@ -11808,11 +11914,6 @@ sax@>=0.6.0:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
scheduler@^0.25.0:
version "0.25.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
scheduler@^0.26.0: scheduler@^0.26.0:
version "0.26.0" version "0.26.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337"
@ -11947,6 +12048,36 @@ sharp@^0.33.1, sharp@^0.33.5:
"@img/sharp-win32-ia32" "0.33.5" "@img/sharp-win32-ia32" "0.33.5"
"@img/sharp-win32-x64" "0.33.5" "@img/sharp-win32-x64" "0.33.5"
sharp@^0.34.1:
version "0.34.1"
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.1.tgz#e5922894b0cc7ddf159eeabc6d5668e4e8b11d61"
integrity sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==
dependencies:
color "^4.2.3"
detect-libc "^2.0.3"
semver "^7.7.1"
optionalDependencies:
"@img/sharp-darwin-arm64" "0.34.1"
"@img/sharp-darwin-x64" "0.34.1"
"@img/sharp-libvips-darwin-arm64" "1.1.0"
"@img/sharp-libvips-darwin-x64" "1.1.0"
"@img/sharp-libvips-linux-arm" "1.1.0"
"@img/sharp-libvips-linux-arm64" "1.1.0"
"@img/sharp-libvips-linux-ppc64" "1.1.0"
"@img/sharp-libvips-linux-s390x" "1.1.0"
"@img/sharp-libvips-linux-x64" "1.1.0"
"@img/sharp-libvips-linuxmusl-arm64" "1.1.0"
"@img/sharp-libvips-linuxmusl-x64" "1.1.0"
"@img/sharp-linux-arm" "0.34.1"
"@img/sharp-linux-arm64" "0.34.1"
"@img/sharp-linux-s390x" "0.34.1"
"@img/sharp-linux-x64" "0.34.1"
"@img/sharp-linuxmusl-arm64" "0.34.1"
"@img/sharp-linuxmusl-x64" "0.34.1"
"@img/sharp-wasm32" "0.34.1"
"@img/sharp-win32-ia32" "0.34.1"
"@img/sharp-win32-x64" "0.34.1"
shebang-command@^2.0.0: shebang-command@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"