From 29acf06f75bd8a33c5ca2b830bde32de4f787ea6 Mon Sep 17 00:00:00 2001
From: fuomag9 <1580624+fuomag9@users.noreply.github.com>
Date: Fri, 31 Oct 2025 21:03:02 +0100
Subject: [PATCH] =?UTF-8?q?Swapped=20the=20entire=20UI=20to=20Material?=
=?UTF-8?q?=E2=80=AFUI,=20applied=20a=20global=20dark=20theme,=20and=20rem?=
=?UTF-8?q?oved=20all=20of=20the=20old=20styled-jsx/CSS-module=20styling?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/(auth)/login/LoginClient.tsx | 38 +
app/(auth)/login/page.tsx | 69 +-
app/(dashboard)/DashboardLayoutClient.tsx | 86 +
app/(dashboard)/OverviewClient.tsx | 85 +
.../access-lists/AccessListsClient.tsx | 140 ++
app/(dashboard)/access-lists/actions.ts | 10 +-
app/(dashboard)/access-lists/page.tsx | 204 +-
app/(dashboard)/audit-log/AuditLogClient.tsx | 41 +
app/(dashboard)/audit-log/page.tsx | 74 +-
.../certificates/CertificatesClient.tsx | 169 ++
app/(dashboard)/certificates/actions.ts | 6 +-
app/(dashboard)/certificates/page.tsx | 217 +-
.../dead-hosts/DeadHostsClient.tsx | 155 ++
app/(dashboard)/dead-hosts/actions.ts | 6 +-
app/(dashboard)/dead-hosts/page.tsx | 198 +-
app/(dashboard)/layout.tsx | 65 +-
app/(dashboard)/nav-links.tsx | 50 -
app/(dashboard)/page.tsx | 162 +-
.../proxy-hosts/ProxyHostsClient.tsx | 217 ++
app/(dashboard)/proxy-hosts/actions.ts | 6 +-
app/(dashboard)/proxy-hosts/page.tsx | 282 +--
app/(dashboard)/redirects/RedirectsClient.tsx | 157 ++
app/(dashboard)/redirects/actions.ts | 6 +-
app/(dashboard)/redirects/page.tsx | 214 +-
app/(dashboard)/settings/SettingsClient.tsx | 108 +
app/(dashboard)/settings/actions.ts | 6 +-
app/(dashboard)/settings/page.tsx | 180 +-
app/(dashboard)/streams/StreamsClient.tsx | 134 ++
app/(dashboard)/streams/actions.ts | 6 +-
app/(dashboard)/streams/page.tsx | 206 +-
app/api/auth/callback/route.ts | 2 +-
app/api/auth/logout/route.ts | 2 +-
app/layout.tsx | 9 +-
app/providers.tsx | 52 +
app/setup/oauth/SetupClient.tsx | 62 +
app/setup/oauth/page.tsx | 119 +-
next-env.d.ts | 3 +-
package-lock.json | 1887 +++++++++++++----
package.json | 26 +-
src/lib/auth/session.ts | 68 +-
tsconfig.json | 40 +-
41 files changed, 3122 insertions(+), 2445 deletions(-)
create mode 100644 app/(auth)/login/LoginClient.tsx
create mode 100644 app/(dashboard)/DashboardLayoutClient.tsx
create mode 100644 app/(dashboard)/OverviewClient.tsx
create mode 100644 app/(dashboard)/access-lists/AccessListsClient.tsx
create mode 100644 app/(dashboard)/audit-log/AuditLogClient.tsx
create mode 100644 app/(dashboard)/certificates/CertificatesClient.tsx
create mode 100644 app/(dashboard)/dead-hosts/DeadHostsClient.tsx
delete mode 100644 app/(dashboard)/nav-links.tsx
create mode 100644 app/(dashboard)/proxy-hosts/ProxyHostsClient.tsx
create mode 100644 app/(dashboard)/redirects/RedirectsClient.tsx
create mode 100644 app/(dashboard)/settings/SettingsClient.tsx
create mode 100644 app/(dashboard)/streams/StreamsClient.tsx
create mode 100644 app/providers.tsx
create mode 100644 app/setup/oauth/SetupClient.tsx
diff --git a/app/(auth)/login/LoginClient.tsx b/app/(auth)/login/LoginClient.tsx
new file mode 100644
index 00000000..9bbfaace
--- /dev/null
+++ b/app/(auth)/login/LoginClient.tsx
@@ -0,0 +1,38 @@
+"use client";
+
+import Link from "next/link";
+import { Alert, Box, Button, Card, CardContent, Stack, Typography } from "@mui/material";
+
+export default function LoginClient({ oauthConfigured, startOAuth }: { oauthConfigured: boolean; startOAuth: (formData: FormData) => void }) {
+ return (
+
+
+
+
+
+
+ Caddy Proxy Manager
+
+
+ Sign in with your organization's OAuth2 provider to continue.
+
+
+
+ {oauthConfigured ? (
+
+
+ Sign in with OAuth2
+
+
+ ) : (
+
+ The system administrator needs to configure OAuth2 settings before logins are allowed. If this is a fresh installation,
+ start with the OAuth setup wizard.
+
+ )}
+
+
+
+
+ );
+}
diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx
index 81b0045c..3b37162c 100644
--- a/app/(auth)/login/page.tsx
+++ b/app/(auth)/login/page.tsx
@@ -2,9 +2,10 @@ import { redirect } from "next/navigation";
import { getSession } from "@/src/lib/auth/session";
import { buildAuthorizationUrl } from "@/src/lib/auth/oauth";
import { getOAuthSettings } from "@/src/lib/settings";
+import LoginClient from "./LoginClient";
export default async function LoginPage() {
- const session = getSession();
+ const session = await getSession();
if (session) {
redirect("/");
}
@@ -17,69 +18,5 @@ export default async function LoginPage() {
redirect(target);
}
- return (
-
-
Caddy Proxy Manager
-
Sign in with your organization's OAuth2 provider to continue.
- {oauthConfigured ? (
-
- ) : (
-
-
- The system administrator needs to configure OAuth2 settings before logins are allowed. If this is a fresh installation, start
- with the{" "}
-
- OAuth setup wizard
-
- .
-
-
- )}
-
-
- );
+ return ;
}
diff --git a/app/(dashboard)/DashboardLayoutClient.tsx b/app/(dashboard)/DashboardLayoutClient.tsx
new file mode 100644
index 00000000..bb6cd139
--- /dev/null
+++ b/app/(dashboard)/DashboardLayoutClient.tsx
@@ -0,0 +1,86 @@
+"use client";
+
+import { ReactNode } from "react";
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import { Box, Button, Divider, List, ListItemButton, ListItemText, Stack, Typography } from "@mui/material";
+import type { UserRecord } from "@/src/lib/auth/session";
+
+const NAV_ITEMS = [
+ { href: "/", label: "Overview" },
+ { href: "/proxy-hosts", label: "Proxy Hosts" },
+ { href: "/redirects", label: "Redirects" },
+ { href: "/dead-hosts", label: "Dead Hosts" },
+ { href: "/streams", label: "Streams" },
+ { href: "/access-lists", label: "Access Lists" },
+ { href: "/certificates", label: "Certificates" },
+ { href: "/settings", label: "Settings" },
+ { href: "/audit-log", label: "Audit Log" }
+] as const;
+
+export default function DashboardLayoutClient({ user, children }: { user: UserRecord; children: ReactNode }) {
+ const pathname = usePathname();
+
+ return (
+
+
+
+
+ Caddy Proxy Manager
+
+
+ {user.name ?? user.email}
+
+
+
+
+
+
+ {NAV_ITEMS.map((item) => {
+ const selected = pathname === item.href;
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+
+ {children}
+
+
+ );
+}
diff --git a/app/(dashboard)/OverviewClient.tsx b/app/(dashboard)/OverviewClient.tsx
new file mode 100644
index 00000000..9f0587f3
--- /dev/null
+++ b/app/(dashboard)/OverviewClient.tsx
@@ -0,0 +1,85 @@
+"use client";
+
+import Link from "next/link";
+import { Card, CardActionArea, CardContent, Grid, Paper, Stack, Typography } from "@mui/material";
+
+type StatCard = {
+ label: string;
+ icon: string;
+ count: number;
+ href: string;
+};
+
+type RecentEvent = {
+ summary: string;
+ created_at: string;
+};
+
+export default function OverviewClient({
+ userName,
+ stats,
+ recentEvents
+}: {
+ userName: string;
+ stats: StatCard[];
+ recentEvents: RecentEvent[];
+}) {
+ return (
+
+
+
+ Welcome back, {userName}
+
+
+ Manage your Caddy reverse proxies, TLS certificates, and services with confidence.
+
+
+
+
+ {stats.map((stat) => (
+
+
+
+
+
+ {stat.icon}
+
+
+ {stat.count}
+
+ {stat.label}
+
+
+
+
+ ))}
+
+
+
+
+ Recent Activity
+
+ {recentEvents.length === 0 ? (
+
+ No activity recorded yet.
+
+ ) : (
+
+ {recentEvents.map((event, index) => (
+
+ {event.summary}
+
+ {new Date(event.created_at).toLocaleString()}
+
+
+ ))}
+
+ )}
+
+
+ );
+}
diff --git a/app/(dashboard)/access-lists/AccessListsClient.tsx b/app/(dashboard)/access-lists/AccessListsClient.tsx
new file mode 100644
index 00000000..5bf7cf21
--- /dev/null
+++ b/app/(dashboard)/access-lists/AccessListsClient.tsx
@@ -0,0 +1,140 @@
+"use client";
+
+import {
+ Box,
+ Button,
+ Card,
+ CardContent,
+ Divider,
+ IconButton,
+ List,
+ ListItem,
+ ListItemSecondaryAction,
+ ListItemText,
+ Stack,
+ TextField,
+ Typography
+} from "@mui/material";
+import DeleteIcon from "@mui/icons-material/Delete";
+import type { AccessList } from "@/src/lib/models/access-lists";
+import {
+ addAccessEntryAction,
+ createAccessListAction,
+ deleteAccessEntryAction,
+ deleteAccessListAction,
+ updateAccessListAction
+} from "./actions";
+
+type Props = {
+ lists: AccessList[];
+};
+
+export default function AccessListsClient({ lists }: Props) {
+ return (
+
+
+
+ Access Lists
+
+ Protect proxy hosts with HTTP basic authentication credentials.
+
+
+
+ {lists.map((list) => (
+
+
+ updateAccessListAction(list.id, formData)} spacing={2}>
+
+ Access List
+
+
+
+
+
+ Save
+
+
+ Delete list
+
+
+
+
+
+
+
+ Accounts
+ {list.entries.length === 0 ? (
+ No credentials configured.
+ ) : (
+
+ {list.entries.map((entry) => (
+
+
+
+
+
+
+ ))}
+
+ )}
+
+
+
+
+ addAccessEntryAction(list.id, formData)} spacing={1.5} direction={{ xs: "column", sm: "row" }}>
+
+
+
+ Add
+
+
+
+
+ ))}
+
+
+
+
+ Create access list
+
+
+
+
+
+
+
+
+
+ Create Access List
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/access-lists/actions.ts b/app/(dashboard)/access-lists/actions.ts
index 57ab8219..3bbf6122 100644
--- a/app/(dashboard)/access-lists/actions.ts
+++ b/app/(dashboard)/access-lists/actions.ts
@@ -11,7 +11,7 @@ import {
} from "@/src/lib/models/access-lists";
export async function createAccessListAction(formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
const rawUsers = String(formData.get("users") ?? "");
const accounts = rawUsers
.split("\n")
@@ -35,7 +35,7 @@ export async function createAccessListAction(formData: FormData) {
}
export async function updateAccessListAction(id: number, formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await updateAccessList(
id,
{
@@ -48,13 +48,13 @@ export async function updateAccessListAction(id: number, formData: FormData) {
}
export async function deleteAccessListAction(id: number) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await deleteAccessList(id, user.id);
revalidatePath("/access-lists");
}
export async function addAccessEntryAction(id: number, formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await addAccessListEntry(
id,
{
@@ -67,7 +67,7 @@ export async function addAccessEntryAction(id: number, formData: FormData) {
}
export async function deleteAccessEntryAction(accessListId: number, entryId: number) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await removeAccessListEntry(accessListId, entryId, user.id);
revalidatePath("/access-lists");
}
diff --git a/app/(dashboard)/access-lists/page.tsx b/app/(dashboard)/access-lists/page.tsx
index c8e84054..5af14275 100644
--- a/app/(dashboard)/access-lists/page.tsx
+++ b/app/(dashboard)/access-lists/page.tsx
@@ -1,207 +1,7 @@
+import AccessListsClient from "./AccessListsClient";
import { listAccessLists } from "@/src/lib/models/access-lists";
-import { addAccessEntryAction, createAccessListAction, deleteAccessEntryAction, deleteAccessListAction, updateAccessListAction } from "./actions";
export default function AccessListsPage() {
const lists = listAccessLists();
-
- return (
-
-
-
-
- {lists.map((list) => (
-
-
-
-
Accounts
- {list.entries.length === 0 ? (
-
No credentials configured.
- ) : (
-
- {list.entries.map((entry) => (
-
- {entry.username}
- deleteAccessEntryAction(list.id, entry.id)}>
-
- Remove
-
-
-
- ))}
-
- )}
-
-
addAccessEntryAction(list.id, formData)} className="add-entry">
-
-
-
- Add
-
-
-
deleteAccessListAction(list.id)}>
-
- Delete list
-
-
-
- ))}
-
-
-
-
-
-
- );
+ return ;
}
diff --git a/app/(dashboard)/audit-log/AuditLogClient.tsx b/app/(dashboard)/audit-log/AuditLogClient.tsx
new file mode 100644
index 00000000..681e77ae
--- /dev/null
+++ b/app/(dashboard)/audit-log/AuditLogClient.tsx
@@ -0,0 +1,41 @@
+"use client";
+
+import { Paper, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography } from "@mui/material";
+
+type EventRow = {
+ id: number;
+ created_at: string;
+ user: string;
+ summary: string;
+};
+
+export default function AuditLogClient({ events }: { events: EventRow[] }) {
+ return (
+
+
+ Audit Log
+
+ Review configuration changes and user activity.
+
+
+
+
+ When
+ User
+ Summary
+
+
+
+ {events.map((event) => (
+
+ {new Date(event.created_at).toLocaleString()}
+ {event.user}
+ {event.summary}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/audit-log/page.tsx b/app/(dashboard)/audit-log/page.tsx
index 1bcd7903..2ad56c42 100644
--- a/app/(dashboard)/audit-log/page.tsx
+++ b/app/(dashboard)/audit-log/page.tsx
@@ -1,72 +1,20 @@
+import AuditLogClient from "./AuditLogClient";
import { listAuditEvents } from "@/src/lib/models/audit";
import { listUsers } from "@/src/lib/models/user";
export default function AuditLogPage() {
const events = listAuditEvents(200);
- const users = new Map(listUsers().map((user) => [user.id, user]));
+ const users = listUsers();
+ const userMap = new Map(users.map((user) => [user.id, user]));
return (
-
-
-
-
-
- When
- User
- Action
- Entity
- Summary
-
-
-
- {events.map((event) => {
- const user = event.user_id ? users.get(event.user_id) : null;
- return (
-
- {new Date(event.created_at).toLocaleString()}
- {user ? user.name ?? user.email : "System"}
- {event.action}
- {event.entity_type}
- {event.summary ?? "—"}
-
- );
- })}
-
-
-
-
+ ({
+ id: event.id,
+ created_at: event.created_at,
+ summary: event.summary ?? `${event.action} on ${event.entity_type}`,
+ user: event.user_id ? userMap.get(event.user_id)?.name ?? userMap.get(event.user_id)?.email ?? "System" : "System"
+ }))}
+ />
);
}
diff --git a/app/(dashboard)/certificates/CertificatesClient.tsx b/app/(dashboard)/certificates/CertificatesClient.tsx
new file mode 100644
index 00000000..c46bcfd2
--- /dev/null
+++ b/app/(dashboard)/certificates/CertificatesClient.tsx
@@ -0,0 +1,169 @@
+"use client";
+
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+ Box,
+ Button,
+ Card,
+ CardContent,
+ Chip,
+ FormControlLabel,
+ MenuItem,
+ Stack,
+ TextField,
+ Typography,
+ Checkbox
+} from "@mui/material";
+import type { Certificate } from "@/src/lib/models/certificates";
+import { createCertificateAction, deleteCertificateAction, updateCertificateAction } from "./actions";
+
+type Props = {
+ certificates: Certificate[];
+};
+
+export default function CertificatesClient({ certificates }: Props) {
+ return (
+
+
+
+ Certificates
+
+
+ Manage ACME-managed certificates or import your own PEM files for custom deployments.
+
+
+
+
+ {certificates.map((cert) => (
+
+
+
+
+
+ {cert.name}
+
+
+ {cert.domain_names.join(", ")}
+
+
+
+
+
+
+ } sx={{ px: 0 }}>
+ Edit
+
+
+ updateCertificateAction(cert.id, formData)} spacing={2}>
+
+
+
+ Managed (ACME)
+ Imported
+
+ {cert.type === "managed" ? (
+
+
+ } label="Auto renew" />
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+ Save certificate
+
+
+ Delete
+
+
+
+
+
+
+
+ ))}
+
+
+
+
+ Create certificate
+
+
+
+
+
+
+
+ Managed (ACME)
+ Imported
+
+ } label="Auto renew (managed only)" />
+
+
+
+
+ Create certificate
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/certificates/actions.ts b/app/(dashboard)/certificates/actions.ts
index b7da1d3d..1d729cc0 100644
--- a/app/(dashboard)/certificates/actions.ts
+++ b/app/(dashboard)/certificates/actions.ts
@@ -16,7 +16,7 @@ function parseDomains(value: FormDataEntryValue | null): string[] {
}
export async function createCertificateAction(formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
const type = String(formData.get("type") ?? "managed") as "managed" | "imported";
await createCertificate(
{
@@ -33,7 +33,7 @@ export async function createCertificateAction(formData: FormData) {
}
export async function updateCertificateAction(id: number, formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
const type = formData.get("type") ? (String(formData.get("type")) as "managed" | "imported") : undefined;
await updateCertificate(
id,
@@ -51,7 +51,7 @@ export async function updateCertificateAction(id: number, formData: FormData) {
}
export async function deleteCertificateAction(id: number) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await deleteCertificate(id, user.id);
revalidatePath("/certificates");
}
diff --git a/app/(dashboard)/certificates/page.tsx b/app/(dashboard)/certificates/page.tsx
index f7ceb344..41b82e99 100644
--- a/app/(dashboard)/certificates/page.tsx
+++ b/app/(dashboard)/certificates/page.tsx
@@ -1,220 +1,7 @@
+import CertificatesClient from "./CertificatesClient";
import { listCertificates } from "@/src/lib/models/certificates";
-import { createCertificateAction, deleteCertificateAction, updateCertificateAction } from "./actions";
export default function CertificatesPage() {
const certificates = listCertificates();
-
- return (
-
-
-
-
- {certificates.map((cert) => (
-
-
-
-
-
-
{cert.name}
-
{cert.domain_names.join(", ")}
-
-
{cert.type === "managed" ? "Managed" : "Imported"}
-
-
- updateCertificateAction(cert.id, formData)} className="form">
-
- Name
-
-
-
- Domains
-
-
-
- Type
-
- Managed (ACME)
- Imported
-
-
- {cert.type === "managed" ? (
-
-
- Auto renew
-
- ) : (
- <>
-
- Certificate PEM
-
-
-
- Private key PEM
-
-
- >
- )}
-
-
- Save certificate
-
-
-
-
-
deleteCertificateAction(cert.id)}>
-
- Delete
-
-
-
- ))}
-
-
-
-
-
-
- );
+ return ;
}
diff --git a/app/(dashboard)/dead-hosts/DeadHostsClient.tsx b/app/(dashboard)/dead-hosts/DeadHostsClient.tsx
new file mode 100644
index 00000000..485d6b78
--- /dev/null
+++ b/app/(dashboard)/dead-hosts/DeadHostsClient.tsx
@@ -0,0 +1,155 @@
+"use client";
+
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+ Box,
+ Button,
+ Card,
+ CardContent,
+ Chip,
+ FormControlLabel,
+ Stack,
+ TextField,
+ Typography,
+ Checkbox
+} from "@mui/material";
+import type { DeadHost } from "@/src/lib/models/dead-hosts";
+import { createDeadHostAction, deleteDeadHostAction, updateDeadHostAction } from "./actions";
+
+type Props = {
+ hosts: DeadHost[];
+};
+
+export default function DeadHostsClient({ hosts }: Props) {
+ return (
+
+
+
+ Dead Hosts
+
+ Serve friendly status pages for domains without upstreams.
+
+
+
+ {hosts.map((host) => (
+
+
+
+
+
+ {host.name}
+
+
+ {host.domains.join(", ")}
+
+
+
+
+
+
+ } sx={{ px: 0 }}>
+ Edit
+
+
+ updateDeadHostAction(host.id, formData)} spacing={2}>
+
+
+
+
+
+
+ } label="Enabled" />
+
+
+
+ Save
+
+
+
+
+
+
+
+
+ Delete
+
+
+
+
+ ))}
+
+
+
+
+ Create dead host
+
+
+
+
+
+
+
+
+ } label="Enabled" />
+
+
+ Create Dead Host
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/dead-hosts/actions.ts b/app/(dashboard)/dead-hosts/actions.ts
index b713b49a..0078dc60 100644
--- a/app/(dashboard)/dead-hosts/actions.ts
+++ b/app/(dashboard)/dead-hosts/actions.ts
@@ -16,7 +16,7 @@ function parseDomains(value: FormDataEntryValue | null): string[] {
}
export async function createDeadHostAction(formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await createDeadHost(
{
name: String(formData.get("name") ?? "Dead host"),
@@ -31,7 +31,7 @@ export async function createDeadHostAction(formData: FormData) {
}
export async function updateDeadHostAction(id: number, formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await updateDeadHost(
id,
{
@@ -47,7 +47,7 @@ export async function updateDeadHostAction(id: number, formData: FormData) {
}
export async function deleteDeadHostAction(id: number) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await deleteDeadHost(id, user.id);
revalidatePath("/dead-hosts");
}
diff --git a/app/(dashboard)/dead-hosts/page.tsx b/app/(dashboard)/dead-hosts/page.tsx
index dc6c4610..8771e419 100644
--- a/app/(dashboard)/dead-hosts/page.tsx
+++ b/app/(dashboard)/dead-hosts/page.tsx
@@ -1,201 +1,7 @@
+import DeadHostsClient from "./DeadHostsClient";
import { listDeadHosts } from "@/src/lib/models/dead-hosts";
-import { createDeadHostAction, deleteDeadHostAction, updateDeadHostAction } from "./actions";
export default function DeadHostsPage() {
const hosts = listDeadHosts();
-
- return (
-
-
-
-
- {hosts.map((host) => (
-
-
-
-
{host.name}
-
{host.domains.join(", ")}
-
-
{host.enabled ? "Enabled" : "Disabled"}
-
-
- Edit
- updateDeadHostAction(host.id, formData)} className="form">
-
- Name
-
-
-
- Domains
-
-
-
- Status code
-
-
-
- Response body (optional)
-
-
-
-
- Enabled
-
-
-
- Save
-
-
-
-
-
deleteDeadHostAction(host.id)}>
-
- Delete
-
-
-
- ))}
-
-
-
-
-
-
- );
+ return ;
}
diff --git a/app/(dashboard)/layout.tsx b/app/(dashboard)/layout.tsx
index c76959a2..30508d00 100644
--- a/app/(dashboard)/layout.tsx
+++ b/app/(dashboard)/layout.tsx
@@ -1,63 +1,8 @@
-import { ReactNode } from "react";
+import type { ReactNode } from "react";
import { requireUser } from "@/src/lib/auth/session";
-import { NavLinks } from "./nav-links";
+import DashboardLayoutClient from "./DashboardLayoutClient";
-export default function DashboardLayout({ children }: { children: ReactNode }) {
- const { user } = requireUser();
-
- return (
-
- );
+export default async function DashboardLayout({ children }: { children: ReactNode }) {
+ const { user } = await requireUser();
+ return {children} ;
}
diff --git a/app/(dashboard)/nav-links.tsx b/app/(dashboard)/nav-links.tsx
deleted file mode 100644
index b173a5e0..00000000
--- a/app/(dashboard)/nav-links.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-"use client";
-
-import Link from "next/link";
-import { usePathname } from "next/navigation";
-
-const NAV_LINKS = [
- { href: "/", label: "Overview" },
- { href: "/proxy-hosts", label: "Proxy Hosts" },
- { href: "/redirects", label: "Redirects" },
- { href: "/dead-hosts", label: "Dead Hosts" },
- { href: "/streams", label: "Streams" },
- { href: "/access-lists", label: "Access Lists" },
- { href: "/certificates", label: "Certificates" },
- { href: "/settings", label: "Settings" },
- { href: "/audit-log", label: "Audit Log" }
-];
-
-export function NavLinks() {
- const pathname = usePathname();
- return (
-
- {NAV_LINKS.map((link) => {
- const isActive = pathname === link.href;
- return (
-
- {link.label}
-
- );
- })}
-
-
- );
-}
diff --git a/app/(dashboard)/page.tsx b/app/(dashboard)/page.tsx
index a9a5e9cb..63e1d671 100644
--- a/app/(dashboard)/page.tsx
+++ b/app/(dashboard)/page.tsx
@@ -1,6 +1,6 @@
-import Link from "next/link";
import db from "@/src/lib/db";
import { requireUser } from "@/src/lib/auth/session";
+import OverviewClient from "./OverviewClient";
type StatCard = {
label: string;
@@ -11,42 +11,12 @@ type StatCard = {
function loadStats(): StatCard[] {
const metrics = [
- {
- label: "Proxy Hosts",
- table: "proxy_hosts",
- href: "/proxy-hosts",
- icon: "⇄"
- },
- {
- label: "Redirects",
- table: "redirect_hosts",
- href: "/redirects",
- icon: "↪"
- },
- {
- label: "Dead Hosts",
- table: "dead_hosts",
- href: "/dead-hosts",
- icon: "☠"
- },
- {
- label: "Streams",
- table: "stream_hosts",
- href: "/streams",
- icon: "≋"
- },
- {
- label: "Certificates",
- table: "certificates",
- href: "/certificates",
- icon: "🔐"
- },
- {
- label: "Access Lists",
- table: "access_lists",
- href: "/access-lists",
- icon: "🔒"
- }
+ { label: "Proxy Hosts", table: "proxy_hosts", href: "/proxy-hosts", icon: "⇄" },
+ { label: "Redirects", table: "redirect_hosts", href: "/redirects", icon: "↪" },
+ { label: "Dead Hosts", table: "dead_hosts", href: "/dead-hosts", icon: "☠" },
+ { label: "Streams", table: "stream_hosts", href: "/streams", icon: "≋" },
+ { label: "Certificates", table: "certificates", href: "/certificates", icon: "🔐" },
+ { label: "Access Lists", table: "access_lists", href: "/access-lists", icon: "🔒" }
] as const;
return metrics.map((metric) => {
@@ -60,10 +30,9 @@ function loadStats(): StatCard[] {
});
}
-export default function OverviewPage() {
- const { user } = requireUser();
+export default async function OverviewPage() {
+ const { user } = await requireUser();
const stats = loadStats();
-
const recentEvents = db
.prepare(
`SELECT action, entity_type, summary, created_at
@@ -74,110 +43,13 @@ export default function OverviewPage() {
.all() as { action: string; entity_type: string; summary: string | null; created_at: string }[];
return (
-
-
-
- {stats.map((stat) => (
-
- {stat.icon}
- {stat.count}
- {stat.label}
-
- ))}
-
-
- Recent Activity
- {recentEvents.length === 0 ? (
- No activity recorded yet.
- ) : (
-
- {recentEvents.map((event, index) => (
-
- {event.summary ?? `${event.action} on ${event.entity_type}`}
- {new Date(event.created_at).toLocaleString()}
-
- ))}
-
- )}
-
-
-
+ ({
+ summary: event.summary ?? `${event.action} on ${event.entity_type}`,
+ created_at: event.created_at
+ }))}
+ />
);
}
diff --git a/app/(dashboard)/proxy-hosts/ProxyHostsClient.tsx b/app/(dashboard)/proxy-hosts/ProxyHostsClient.tsx
new file mode 100644
index 00000000..a6442266
--- /dev/null
+++ b/app/(dashboard)/proxy-hosts/ProxyHostsClient.tsx
@@ -0,0 +1,217 @@
+"use client";
+
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+ Box,
+ Button,
+ Card,
+ CardContent,
+ Chip,
+ FormControlLabel,
+ Grid,
+ MenuItem,
+ Stack,
+ TextField,
+ Typography,
+ Checkbox
+} from "@mui/material";
+import type { AccessList } from "@/src/lib/models/access-lists";
+import type { Certificate } from "@/src/lib/models/certificates";
+import type { ProxyHost } from "@/src/lib/models/proxy-hosts";
+import { createProxyHostAction, deleteProxyHostAction, updateProxyHostAction } from "./actions";
+
+type Props = {
+ hosts: ProxyHost[];
+ certificates: Certificate[];
+ accessLists: AccessList[];
+};
+
+export default function ProxyHostsClient({ hosts, certificates, accessLists }: Props) {
+ return (
+
+
+
+ Proxy Hosts
+
+
+ Define HTTP(S) reverse proxies managed by Caddy with built-in TLS orchestration.
+
+
+
+
+ {hosts.map((host) => (
+
+
+
+
+
+
+ {host.name}
+
+
+ {host.domains.join(", ")}
+
+
+
+
+
+
+ } sx={{ px: 0 }}>
+ Edit configuration
+
+
+ updateProxyHostAction(host.id, formData)} spacing={2}>
+
+
+
+
+ Managed by Caddy
+ {certificates.map((cert) => (
+
+ {cert.name}
+
+ ))}
+
+
+ None
+ {accessLists.map((list) => (
+
+ {list.name}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save Changes
+
+
+
+
+
+
+
+
+ Delete
+
+
+
+
+
+ ))}
+
+
+
+
+ Create proxy host
+
+
+
+
+
+
+
+
+ Managed by Caddy
+ {certificates.map((cert) => (
+
+ {cert.name}
+
+ ))}
+
+
+ None
+ {accessLists.map((list) => (
+
+ {list.name}
+
+ ))}
+
+
+ } label="Force HTTPS" />
+ } label="HSTS" />
+ } label="Allow WebSocket" />
+ } label="Preserve host header" />
+ } label="Enabled" />
+
+
+
+ Create Host
+
+
+
+
+
+
+
+ );
+}
+
+function HiddenCheckboxField({ name, defaultChecked, label }: { name: string; defaultChecked: boolean; label: string }) {
+ return (
+
+
+ } label={label} />
+
+ );
+}
diff --git a/app/(dashboard)/proxy-hosts/actions.ts b/app/(dashboard)/proxy-hosts/actions.ts
index 6cc7e749..63083c12 100644
--- a/app/(dashboard)/proxy-hosts/actions.ts
+++ b/app/(dashboard)/proxy-hosts/actions.ts
@@ -20,7 +20,7 @@ function parseCheckbox(value: FormDataEntryValue | null): boolean {
}
export async function createProxyHostAction(formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await createProxyHost(
{
name: String(formData.get("name") ?? "Untitled"),
@@ -41,7 +41,7 @@ export async function createProxyHostAction(formData: FormData) {
}
export async function updateProxyHostAction(id: number, formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
const boolField = (key: string) => (formData.has(`${key}_present`) ? parseCheckbox(formData.get(key)) : undefined);
await updateProxyHost(
id,
@@ -64,7 +64,7 @@ export async function updateProxyHostAction(id: number, formData: FormData) {
}
export async function deleteProxyHostAction(id: number) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await deleteProxyHost(id, user.id);
revalidatePath("/proxy-hosts");
}
diff --git a/app/(dashboard)/proxy-hosts/page.tsx b/app/(dashboard)/proxy-hosts/page.tsx
index b7084cba..cbe41f98 100644
--- a/app/(dashboard)/proxy-hosts/page.tsx
+++ b/app/(dashboard)/proxy-hosts/page.tsx
@@ -1,4 +1,4 @@
-import { createProxyHostAction, deleteProxyHostAction, updateProxyHostAction } from "./actions";
+import ProxyHostsClient from "./ProxyHostsClient";
import { listProxyHosts } from "@/src/lib/models/proxy-hosts";
import { listCertificates } from "@/src/lib/models/certificates";
import { listAccessLists } from "@/src/lib/models/access-lists";
@@ -8,283 +8,5 @@ export default function ProxyHostsPage() {
const certificates = listCertificates();
const accessLists = listAccessLists();
- return (
-
-
-
-
- {hosts.map((host) => (
-
- ))}
-
-
-
-
-
-
- );
+ return ;
}
diff --git a/app/(dashboard)/redirects/RedirectsClient.tsx b/app/(dashboard)/redirects/RedirectsClient.tsx
new file mode 100644
index 00000000..0b631243
--- /dev/null
+++ b/app/(dashboard)/redirects/RedirectsClient.tsx
@@ -0,0 +1,157 @@
+"use client";
+
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+ Box,
+ Button,
+ Card,
+ CardContent,
+ Chip,
+ FormControlLabel,
+ Stack,
+ TextField,
+ Typography,
+ Checkbox
+} from "@mui/material";
+import type { RedirectHost } from "@/src/lib/models/redirect-hosts";
+import { createRedirectAction, deleteRedirectAction, updateRedirectAction } from "./actions";
+
+type Props = {
+ redirects: RedirectHost[];
+};
+
+export default function RedirectsClient({ redirects }: Props) {
+ return (
+
+
+
+ Redirects
+
+ Return HTTP 301/302 responses to guide clients toward canonical hosts.
+
+
+
+ {redirects.map((redirect) => (
+
+
+
+
+
+ {redirect.name}
+
+
+ {redirect.domains.join(", ")}
+
+
+
+
+
+
+ } sx={{ px: 0 }}>
+ Edit
+
+
+ updateRedirectAction(redirect.id, formData)} spacing={2}>
+
+
+
+
+
+
+
+
+
+
+ Save
+
+
+
+
+
+
+
+
+ Delete
+
+
+
+
+ ))}
+
+
+
+
+ Create redirect
+
+
+
+
+
+
+
+
+
+ } label="Preserve path/query" />
+ } label="Enabled" />
+
+
+
+ Create Redirect
+
+
+
+
+
+
+
+ );
+}
+
+function HiddenCheckboxField({ name, defaultChecked, label }: { name: string; defaultChecked: boolean; label: string }) {
+ return (
+
+
+ } label={label} />
+
+ );
+}
diff --git a/app/(dashboard)/redirects/actions.ts b/app/(dashboard)/redirects/actions.ts
index 6f492983..68178fb4 100644
--- a/app/(dashboard)/redirects/actions.ts
+++ b/app/(dashboard)/redirects/actions.ts
@@ -16,7 +16,7 @@ function parseList(value: FormDataEntryValue | null): string[] {
}
export async function createRedirectAction(formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await createRedirectHost(
{
name: String(formData.get("name") ?? "Redirect"),
@@ -32,7 +32,7 @@ export async function createRedirectAction(formData: FormData) {
}
export async function updateRedirectAction(id: number, formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await updateRedirectHost(
id,
{
@@ -49,7 +49,7 @@ export async function updateRedirectAction(id: number, formData: FormData) {
}
export async function deleteRedirectAction(id: number) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await deleteRedirectHost(id, user.id);
revalidatePath("/redirects");
}
diff --git a/app/(dashboard)/redirects/page.tsx b/app/(dashboard)/redirects/page.tsx
index f7b23275..48f03aeb 100644
--- a/app/(dashboard)/redirects/page.tsx
+++ b/app/(dashboard)/redirects/page.tsx
@@ -1,217 +1,7 @@
+import RedirectsClient from "./RedirectsClient";
import { listRedirectHosts } from "@/src/lib/models/redirect-hosts";
-import { createRedirectAction, deleteRedirectAction, updateRedirectAction } from "./actions";
export default function RedirectsPage() {
const redirects = listRedirectHosts();
-
- return (
-
-
-
-
- {redirects.map((redirect) => (
-
- ))}
-
-
-
-
-
-
- );
+ return ;
}
diff --git a/app/(dashboard)/settings/SettingsClient.tsx b/app/(dashboard)/settings/SettingsClient.tsx
new file mode 100644
index 00000000..f8382055
--- /dev/null
+++ b/app/(dashboard)/settings/SettingsClient.tsx
@@ -0,0 +1,108 @@
+"use client";
+
+import { Box, Button, Card, CardContent, Stack, TextField, Typography } from "@mui/material";
+import type { CloudflareSettings, GeneralSettings, OAuthSettings } from "@/src/lib/settings";
+import {
+ updateCloudflareSettingsAction,
+ updateGeneralSettingsAction,
+ updateOAuthSettingsAction
+} from "./actions";
+
+type Props = {
+ general: GeneralSettings | null;
+ oauth: OAuthSettings | null;
+ cloudflare: CloudflareSettings | null;
+};
+
+export default function SettingsClient({ general, oauth, cloudflare }: Props) {
+ return (
+
+
+
+ Settings
+
+ Configure organization-wide defaults, authentication, and DNS automation.
+
+
+
+
+
+ General
+
+
+
+
+
+
+ Save general settings
+
+
+
+
+
+
+
+
+
+ OAuth2 Authentication
+
+
+ Provide the OAuth 2.0 endpoints and client credentials issued by your identity provider. Scopes should include profile and
+ email data.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save OAuth settings
+
+
+
+
+
+
+
+
+
+ Cloudflare DNS
+
+
+ Configure a Cloudflare API token with Zone.DNS Edit permissions to enable DNS-01 challenges for wildcard certificates.
+
+
+
+
+
+
+
+ Save Cloudflare settings
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/settings/actions.ts b/app/(dashboard)/settings/actions.ts
index a69eb4d1..4db6371d 100644
--- a/app/(dashboard)/settings/actions.ts
+++ b/app/(dashboard)/settings/actions.ts
@@ -6,7 +6,7 @@ import { applyCaddyConfig } from "@/src/lib/caddy";
import { saveCloudflareSettings, saveGeneralSettings, saveOAuthSettings } from "@/src/lib/settings";
export async function updateGeneralSettingsAction(formData: FormData) {
- requireUser(); // ensure authenticated
+ await requireUser(); // ensure authenticated
saveGeneralSettings({
primaryDomain: String(formData.get("primaryDomain") ?? ""),
acmeEmail: formData.get("acmeEmail") ? String(formData.get("acmeEmail")) : undefined
@@ -15,7 +15,7 @@ export async function updateGeneralSettingsAction(formData: FormData) {
}
export async function updateOAuthSettingsAction(formData: FormData) {
- requireUser();
+ await requireUser();
saveOAuthSettings({
authorizationUrl: String(formData.get("authorizationUrl") ?? ""),
tokenUrl: String(formData.get("tokenUrl") ?? ""),
@@ -31,7 +31,7 @@ export async function updateOAuthSettingsAction(formData: FormData) {
}
export async function updateCloudflareSettingsAction(formData: FormData) {
- requireUser();
+ await requireUser();
const apiToken = String(formData.get("apiToken") ?? "");
if (!apiToken) {
saveCloudflareSettings({ apiToken: "", zoneId: undefined, accountId: undefined });
diff --git a/app/(dashboard)/settings/page.tsx b/app/(dashboard)/settings/page.tsx
index b2636c7a..25994d49 100644
--- a/app/(dashboard)/settings/page.tsx
+++ b/app/(dashboard)/settings/page.tsx
@@ -1,180 +1,12 @@
+import SettingsClient from "./SettingsClient";
import { getCloudflareSettings, getGeneralSettings, getOAuthSettings } from "@/src/lib/settings";
-import { updateCloudflareSettingsAction, updateGeneralSettingsAction, updateOAuthSettingsAction } from "./actions";
export default function SettingsPage() {
- const general = getGeneralSettings();
- const oauth = getOAuthSettings();
- const cloudflare = getCloudflareSettings();
-
return (
-
+
);
}
diff --git a/app/(dashboard)/streams/StreamsClient.tsx b/app/(dashboard)/streams/StreamsClient.tsx
new file mode 100644
index 00000000..9cf1838e
--- /dev/null
+++ b/app/(dashboard)/streams/StreamsClient.tsx
@@ -0,0 +1,134 @@
+"use client";
+
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+import {
+ Accordion,
+ AccordionDetails,
+ AccordionSummary,
+ Box,
+ Button,
+ Card,
+ CardContent,
+ Chip,
+ FormControlLabel,
+ MenuItem,
+ Stack,
+ TextField,
+ Typography,
+ Checkbox
+} from "@mui/material";
+import type { StreamHost } from "@/src/lib/models/stream-hosts";
+import { createStreamAction, deleteStreamAction, updateStreamAction } from "./actions";
+
+type Props = {
+ streams: StreamHost[];
+};
+
+export default function StreamsClient({ streams }: Props) {
+ return (
+
+
+
+ Streams
+
+ Forward raw TCP/UDP connections through Caddy's layer4 module.
+
+
+
+ {streams.map((stream) => (
+
+
+
+
+
+ {stream.name}
+
+
+ Listens on :{stream.listen_port} ({stream.protocol.toUpperCase()}) → {stream.upstream}
+
+
+
+
+
+
+ } sx={{ px: 0 }}>
+ Edit
+
+
+ updateStreamAction(stream.id, formData)} spacing={2}>
+
+
+
+ TCP
+ UDP
+
+
+
+
+ } label="Enabled" />
+
+
+
+ Save
+
+
+
+
+
+
+
+
+ Delete
+
+
+
+
+ ))}
+
+
+
+
+ Create stream
+
+
+
+
+
+
+
+ TCP
+ UDP
+
+
+ } label="Enabled" />
+
+
+ Create Stream
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/streams/actions.ts b/app/(dashboard)/streams/actions.ts
index 17dee01b..fd6190b2 100644
--- a/app/(dashboard)/streams/actions.ts
+++ b/app/(dashboard)/streams/actions.ts
@@ -5,7 +5,7 @@ import { requireUser } from "@/src/lib/auth/session";
import { createStreamHost, deleteStreamHost, updateStreamHost } from "@/src/lib/models/stream-hosts";
export async function createStreamAction(formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await createStreamHost(
{
name: String(formData.get("name") ?? "Stream"),
@@ -20,7 +20,7 @@ export async function createStreamAction(formData: FormData) {
}
export async function updateStreamAction(id: number, formData: FormData) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await updateStreamHost(
id,
{
@@ -36,7 +36,7 @@ export async function updateStreamAction(id: number, formData: FormData) {
}
export async function deleteStreamAction(id: number) {
- const { user } = requireUser();
+ const { user } = await requireUser();
await deleteStreamHost(id, user.id);
revalidatePath("/streams");
}
diff --git a/app/(dashboard)/streams/page.tsx b/app/(dashboard)/streams/page.tsx
index c78361da..b759400e 100644
--- a/app/(dashboard)/streams/page.tsx
+++ b/app/(dashboard)/streams/page.tsx
@@ -1,209 +1,7 @@
+import StreamsClient from "./StreamsClient";
import { listStreamHosts } from "@/src/lib/models/stream-hosts";
-import { createStreamAction, deleteStreamAction, updateStreamAction } from "./actions";
export default function StreamsPage() {
const streams = listStreamHosts();
-
- return (
-
-
-
-
- {streams.map((stream) => (
-
-
-
-
{stream.name}
-
- Listens on :{stream.listen_port} ({stream.protocol.toUpperCase()}) ➜ {stream.upstream}
-
-
-
{stream.enabled ? "Enabled" : "Disabled"}
-
-
- Edit
- updateStreamAction(stream.id, formData)} className="form">
-
- Name
-
-
-
- Listen port
-
-
-
- Protocol
-
- TCP
- UDP
-
-
-
- Upstream
-
-
-
-
- Enabled
-
-
-
- Save
-
-
-
-
-
deleteStreamAction(stream.id)}>
-
- Delete
-
-
-
- ))}
-
-
-
-
-
-
- );
+ return ;
}
diff --git a/app/api/auth/callback/route.ts b/app/api/auth/callback/route.ts
index ce436b44..3ba72bef 100644
--- a/app/api/auth/callback/route.ts
+++ b/app/api/auth/callback/route.ts
@@ -14,7 +14,7 @@ export async function GET(request: NextRequest) {
try {
const { user, redirectTo } = await finalizeOAuthLogin(code, state);
- createSession(user.id);
+ await createSession(user.id);
const destination = redirectTo && redirectTo.startsWith("/") ? redirectTo : "/";
return NextResponse.redirect(new URL(destination, config.baseUrl));
} catch (error) {
diff --git a/app/api/auth/logout/route.ts b/app/api/auth/logout/route.ts
index 29869d2e..7cd509b3 100644
--- a/app/api/auth/logout/route.ts
+++ b/app/api/auth/logout/route.ts
@@ -3,6 +3,6 @@ import { destroySession } from "@/src/lib/auth/session";
import { config } from "@/src/lib/config";
export async function POST() {
- destroySession();
+ await destroySession();
return NextResponse.redirect(new URL("/login", config.baseUrl));
}
diff --git a/app/layout.tsx b/app/layout.tsx
index 8bbd8c17..5ec467b5 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,12 +1,13 @@
-"use client";
-
+import type { ReactNode } from "react";
import "./globals.css";
-import { ReactNode } from "react";
+import Providers from "./providers";
export default function RootLayout({ children }: { children: ReactNode }) {
return (
- {children}
+
+ {children}
+
);
}
diff --git a/app/providers.tsx b/app/providers.tsx
new file mode 100644
index 00000000..9578cc44
--- /dev/null
+++ b/app/providers.tsx
@@ -0,0 +1,52 @@
+"use client";
+
+import { ReactNode, useMemo } from "react";
+import { CssBaseline, ThemeProvider, createTheme, responsiveFontSizes } from "@mui/material";
+
+export default function Providers({ children }: { children: ReactNode }) {
+ const theme = useMemo(
+ () =>
+ responsiveFontSizes(
+ createTheme({
+ palette: {
+ mode: "dark",
+ background: {
+ default: "#05070c",
+ paper: "#0c111d"
+ },
+ primary: {
+ main: "#00bcd4"
+ }
+ },
+ shape: {
+ borderRadius: 12
+ },
+ components: {
+ MuiButton: {
+ styleOverrides: {
+ root: {
+ textTransform: "none",
+ borderRadius: 999
+ }
+ }
+ },
+ MuiCard: {
+ styleOverrides: {
+ root: {
+ backgroundImage: "none"
+ }
+ }
+ }
+ }
+ })
+ ),
+ []
+ );
+
+ return (
+
+
+ {children}
+
+ );
+}
diff --git a/app/setup/oauth/SetupClient.tsx b/app/setup/oauth/SetupClient.tsx
new file mode 100644
index 00000000..bf5abc19
--- /dev/null
+++ b/app/setup/oauth/SetupClient.tsx
@@ -0,0 +1,62 @@
+"use client";
+
+import { Box, Button, Card, CardContent, Grid, Stack, TextField, Typography } from "@mui/material";
+
+export default function OAuthSetupClient({ startSetup }: { startSetup: (formData: FormData) => void }) {
+ return (
+
+
+
+
+
+
+ Configure OAuth2
+
+
+ Provide the OAuth configuration for your identity provider to finish setting up Caddy Proxy Manager. The first user who
+ signs in becomes the administrator.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Save OAuth configuration
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/setup/oauth/page.tsx b/app/setup/oauth/page.tsx
index e164cbfa..97131e70 100644
--- a/app/setup/oauth/page.tsx
+++ b/app/setup/oauth/page.tsx
@@ -2,127 +2,12 @@ import { redirect } from "next/navigation";
import { getOAuthSettings } from "@/src/lib/settings";
import { getUserCount } from "@/src/lib/models/user";
import { initialOAuthSetupAction } from "./actions";
+import OAuthSetupClient from "./SetupClient";
export default function OAuthSetupPage() {
if (getUserCount() > 0 && getOAuthSettings()) {
redirect("/login");
}
- return (
-
- );
+ return ;
}
diff --git a/next-env.d.ts b/next-env.d.ts
index 4f11a03d..c4b7818f 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -1,5 +1,6 @@
///
///
+import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
-// see https://nextjs.org/docs/basic-features/typescript for more information.
+// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/package-lock.json b/package-lock.json
index adb043a7..f1f2e1d9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,19 +8,302 @@
"name": "caddy-proxy-manager",
"version": "1.0.0",
"dependencies": {
- "bcryptjs": "^2.4.3",
- "better-sqlite3": "^11.6.0",
- "next": "^15.0.0",
- "react": "^18.3.1",
- "react-dom": "^18.3.1"
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "@mui/icons-material": "^7.3.4",
+ "@mui/material": "^7.3.4",
+ "bcryptjs": "^3.0.2",
+ "better-sqlite3": "^12.4.1",
+ "next": "^16.0.1",
+ "react": "^19.2.0",
+ "react-dom": "^19.2.0"
},
"devDependencies": {
- "@types/node": "^20.12.12",
- "@types/react": "^18.2.37",
- "@types/react-dom": "^18.2.15",
- "eslint": "^8.57.0",
- "eslint-config-next": "^15.0.0",
- "typescript": "^5.4.5"
+ "@types/node": "^24.9.2",
+ "@types/react": "^19.2.2",
+ "@types/react-dom": "^19.2.2",
+ "eslint": "^9.38.0",
+ "eslint-config-next": "^16.0.1",
+ "typescript": "^5.9.3"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
+ "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
+ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.5",
+ "@babel/helper-compilation-targets": "^7.27.2",
+ "@babel/helper-module-transforms": "^7.28.3",
+ "@babel/helpers": "^7.28.4",
+ "@babel/parser": "^7.28.5",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.5",
+ "@babel/types": "^7.28.5",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@babel/core/node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@babel/core/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
+ "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.5",
+ "@babel/types": "^7.28.5",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+ "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.27.2",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+ "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
+ "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/traverse": "^7.28.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
+ "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
+ "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.5"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
+ "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.2",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
+ "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.5",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.5",
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.5",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
+ "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
"node_modules/@emnapi/core": {
@@ -56,6 +339,152 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@emotion/babel-plugin": {
+ "version": "11.13.5",
+ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
+ "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.16.7",
+ "@babel/runtime": "^7.18.3",
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/serialize": "^1.3.3",
+ "babel-plugin-macros": "^3.1.0",
+ "convert-source-map": "^1.5.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-root": "^1.1.0",
+ "source-map": "^0.5.7",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/cache": {
+ "version": "11.14.0",
+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
+ "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/sheet": "^1.4.0",
+ "@emotion/utils": "^1.4.2",
+ "@emotion/weak-memoize": "^0.4.0",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/hash": {
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
+ "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz",
+ "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
+ "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/react": {
+ "version": "11.14.0",
+ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
+ "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/cache": "^11.14.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
+ "@emotion/utils": "^1.4.2",
+ "@emotion/weak-memoize": "^0.4.0",
+ "hoist-non-react-statics": "^3.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/serialize": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
+ "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/unitless": "^0.10.0",
+ "@emotion/utils": "^1.4.2",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@emotion/sheet": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
+ "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/styled": {
+ "version": "11.14.1",
+ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
+ "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/is-prop-valid": "^1.3.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
+ "@emotion/utils": "^1.4.2"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.0.0-rc.0",
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
+ "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
+ "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@emotion/utils": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
+ "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/weak-memoize": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
+ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
+ "license": "MIT"
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
@@ -85,17 +514,71 @@
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
+ "node_modules/@eslint/config-array": {
+ "version": "0.21.1",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
+ "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.7",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers/node_modules/@eslint/core": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.16.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz",
+ "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
+ "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
@@ -103,36 +586,84 @@
"strip-json-comments": "^3.1.1"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/js": {
- "version": "8.57.1",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
- "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+ "version": "9.38.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz",
+ "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==",
"dev": true,
"license": "MIT",
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
}
},
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
- "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
- "deprecated": "Use @eslint/config-array instead",
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+ "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+ "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@humanwhocodes/object-schema": "^2.0.3",
- "debug": "^4.3.1",
- "minimatch": "^3.0.5"
+ "@eslint/core": "^0.17.0",
+ "levn": "^0.4.1"
},
"engines": {
- "node": ">=10.10.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.7",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+ "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.1",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
}
},
"node_modules/@humanwhocodes/module-importer": {
@@ -149,13 +680,19 @@
"url": "https://github.com/sponsors/nzakas"
}
},
- "node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
- "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
- "deprecated": "Use @eslint/object-schema instead",
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
"dev": true,
- "license": "BSD-3-Clause"
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
},
"node_modules/@img/colour": {
"version": "1.0.0",
@@ -585,6 +1122,297 @@
"url": "https://opencollective.com/libvips"
}
},
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@mui/core-downloads-tracker": {
+ "version": "7.3.4",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.4.tgz",
+ "integrity": "sha512-BIktMapG3r4iXwIhYNpvk97ZfYWTreBBQTWjQKbNbzI64+ULHfYavQEX2w99aSWHS58DvXESWIgbD9adKcUOBw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ }
+ },
+ "node_modules/@mui/icons-material": {
+ "version": "7.3.4",
+ "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.4.tgz",
+ "integrity": "sha512-9n6Xcq7molXWYb680N2Qx+FRW8oT6j/LXF5PZFH3ph9X/Rct0B/BlLAsFI7iL9ySI6LVLuQIVtrLiPT82R7OZw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@mui/material": "^7.3.4",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/material": {
+ "version": "7.3.4",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.4.tgz",
+ "integrity": "sha512-gEQL9pbJZZHT7lYJBKQCS723v1MGys2IFc94COXbUIyCTWa+qC77a7hUax4Yjd5ggEm35dk4AyYABpKKWC4MLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@mui/core-downloads-tracker": "^7.3.4",
+ "@mui/system": "^7.3.3",
+ "@mui/types": "^7.4.7",
+ "@mui/utils": "^7.3.3",
+ "@popperjs/core": "^2.11.8",
+ "@types/react-transition-group": "^4.4.12",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1",
+ "react-is": "^19.1.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@mui/material-pigment-css": "^7.3.3",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@mui/material-pigment-css": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/material/node_modules/react-is": {
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
+ "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
+ "license": "MIT"
+ },
+ "node_modules/@mui/private-theming": {
+ "version": "7.3.3",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.3.tgz",
+ "integrity": "sha512-OJM+9nj5JIyPUvsZ5ZjaeC9PfktmK+W5YaVLToLR8L0lB/DGmv1gcKE43ssNLSvpoW71Hct0necfade6+kW3zQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@mui/utils": "^7.3.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/styled-engine": {
+ "version": "7.3.3",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.3.tgz",
+ "integrity": "sha512-CmFxvRJIBCEaWdilhXMw/5wFJ1+FT9f3xt+m2pPXhHPeVIbBg9MnMvNSJjdALvnQJMPw8jLhrUtXmN7QAZV2fw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@emotion/cache": "^11.14.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/sheet": "^1.4.0",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.4.1",
+ "@emotion/styled": "^11.3.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/system": {
+ "version": "7.3.3",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.3.tgz",
+ "integrity": "sha512-Lqq3emZr5IzRLKaHPuMaLBDVaGvxoh6z7HMWd1RPKawBM5uMRaQ4ImsmmgXWtwJdfZux5eugfDhXJUo2mliS8Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@mui/private-theming": "^7.3.3",
+ "@mui/styled-engine": "^7.3.3",
+ "@mui/types": "^7.4.7",
+ "@mui/utils": "^7.3.3",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/types": {
+ "version": "7.4.7",
+ "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.7.tgz",
+ "integrity": "sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/utils": {
+ "version": "7.3.3",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.3.tgz",
+ "integrity": "sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "@mui/types": "^7.4.7",
+ "@types/prop-types": "^15.7.15",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^19.1.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/utils/node_modules/react-is": {
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
+ "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
+ "license": "MIT"
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
@@ -599,55 +1427,25 @@
}
},
"node_modules/@next/env": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.6.tgz",
- "integrity": "sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.1.tgz",
+ "integrity": "sha512-LFvlK0TG2L3fEOX77OC35KowL8D7DlFF45C0OvKMC4hy8c/md1RC4UMNDlUGJqfCoCS2VWrZ4dSE6OjaX5+8mw==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.6.tgz",
- "integrity": "sha512-YxDvsT2fwy1j5gMqk3ppXlsgDopHnkM4BoxSVASbvvgh5zgsK8lvWerDzPip8k3WVzsTZ1O7A7si1KNfN4OZfQ==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.1.tgz",
+ "integrity": "sha512-g4Cqmv/gyFEXNeVB2HkqDlYKfy+YrlM2k8AVIO/YQVEPfhVruH1VA99uT1zELLnPLIeOnx8IZ6Ddso0asfTIdw==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-glob": "3.3.1"
}
},
- "node_modules/@next/eslint-plugin-next/node_modules/fast-glob": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
- "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/@next/eslint-plugin-next/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/@next/swc-darwin-arm64": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.6.tgz",
- "integrity": "sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.1.tgz",
+ "integrity": "sha512-R0YxRp6/4W7yG1nKbfu41bp3d96a0EalonQXiMe+1H9GTHfKxGNCGFNWUho18avRBPsO8T3RmdWuzmfurlQPbg==",
"cpu": [
"arm64"
],
@@ -661,9 +1459,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.6.tgz",
- "integrity": "sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.1.tgz",
+ "integrity": "sha512-kETZBocRux3xITiZtOtVoVvXyQLB7VBxN7L6EPqgI5paZiUlnsgYv4q8diTNYeHmF9EiehydOBo20lTttCbHAg==",
"cpu": [
"x64"
],
@@ -677,9 +1475,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.6.tgz",
- "integrity": "sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.1.tgz",
+ "integrity": "sha512-hWg3BtsxQuSKhfe0LunJoqxjO4NEpBmKkE+P2Sroos7yB//OOX3jD5ISP2wv8QdUwtRehMdwYz6VB50mY6hqAg==",
"cpu": [
"arm64"
],
@@ -693,9 +1491,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.6.tgz",
- "integrity": "sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.1.tgz",
+ "integrity": "sha512-UPnOvYg+fjAhP3b1iQStcYPWeBFRLrugEyK/lDKGk7kLNua8t5/DvDbAEFotfV1YfcOY6bru76qN9qnjLoyHCQ==",
"cpu": [
"arm64"
],
@@ -709,9 +1507,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.6.tgz",
- "integrity": "sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.1.tgz",
+ "integrity": "sha512-Et81SdWkcRqAJziIgFtsFyJizHoWne4fzJkvjd6V4wEkWTB4MX6J0uByUb0peiJQ4WeAt6GGmMszE5KrXK6WKg==",
"cpu": [
"x64"
],
@@ -725,9 +1523,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.6.tgz",
- "integrity": "sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.1.tgz",
+ "integrity": "sha512-qBbgYEBRrC1egcG03FZaVfVxrJm8wBl7vr8UFKplnxNRprctdP26xEv9nJ07Ggq4y1adwa0nz2mz83CELY7N6Q==",
"cpu": [
"x64"
],
@@ -741,9 +1539,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.6.tgz",
- "integrity": "sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.1.tgz",
+ "integrity": "sha512-cPuBjYP6I699/RdbHJonb3BiRNEDm5CKEBuJ6SD8k3oLam2fDRMKAvmrli4QMDgT2ixyRJ0+DTkiODbIQhRkeQ==",
"cpu": [
"arm64"
],
@@ -757,9 +1555,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.6.tgz",
- "integrity": "sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.1.tgz",
+ "integrity": "sha512-XeEUJsE4JYtfrXe/LaJn3z1pD19fK0Q6Er8Qoufi+HqvdO4LEPyCxLUt4rxA+4RfYo6S9gMlmzCMU2F+AatFqQ==",
"cpu": [
"x64"
],
@@ -820,6 +1618,16 @@
"node": ">=12.4.0"
}
},
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -827,13 +1635,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@rushstack/eslint-patch": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.14.1.tgz",
- "integrity": "sha512-jGTk8UD/RdjsNZW8qq10r0RBvxL8OWtoT+kImlzPDFilmozzM+9QmIJsmze9UiSBrFU45ZxhTYBypn9q9z/VfQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -854,6 +1655,20 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -862,41 +1677,53 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "20.19.24",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz",
- "integrity": "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==",
+ "version": "24.9.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz",
+ "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~6.21.0"
+ "undici-types": "~7.16.0"
}
},
+ "node_modules/@types/parse-json": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
+ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
+ "license": "MIT"
+ },
"node_modules/@types/prop-types": {
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/react": {
- "version": "18.3.26",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
- "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
- "dev": true,
+ "version": "19.2.2",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
+ "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
"license": "MIT",
"dependencies": {
- "@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
- "version": "18.3.7",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
- "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
+ "version": "19.2.2",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz",
+ "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
"dev": true,
"license": "MIT",
"peerDependencies": {
- "@types/react": "^18.0.0"
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@types/react-transition-group": {
+ "version": "4.4.12",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
+ "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*"
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
@@ -1099,6 +1926,36 @@
"balanced-match": "^1.0.0"
}
},
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
@@ -1170,13 +2027,6 @@
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/@ungap/structured-clone": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
- "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/@unrs/resolver-binding-android-arm-eabi": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
@@ -1486,16 +2336,6 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -1742,6 +2582,21 @@
"node": ">= 0.4"
}
},
+ "node_modules/babel-plugin-macros": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
+ "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "cosmiconfig": "^7.0.0",
+ "resolve": "^1.19.0"
+ },
+ "engines": {
+ "node": ">=10",
+ "npm": ">=6"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1769,21 +2624,37 @@
],
"license": "MIT"
},
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.8.22",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.22.tgz",
+ "integrity": "sha512-/tk9kky/d8T8CTXIQYASLyhAxR5VwL3zct1oAoVTaOUHwrmsGnfbRwNdEq+vOl2BN8i3PcDdP0o4Q+jjKQoFbQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
"node_modules/bcryptjs": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
- "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==",
- "license": "MIT"
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz",
+ "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==",
+ "license": "BSD-3-Clause",
+ "bin": {
+ "bcrypt": "bin/bcrypt"
+ }
},
"node_modules/better-sqlite3": {
- "version": "11.10.0",
- "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz",
- "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==",
+ "version": "12.4.1",
+ "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.4.1.tgz",
+ "integrity": "sha512-3yVdyZhklTiNrtg+4WqHpJpFDd+WHTg2oM7UcR80GqL05AOV0xEJzc6qNvFYoEtE+hRp1n9MpN6/+4yhlGkDXQ==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
+ },
+ "engines": {
+ "node": "20.x || 22.x || 23.x || 24.x"
}
},
"node_modules/bindings": {
@@ -1830,6 +2701,40 @@
"node": ">=8"
}
},
+ "node_modules/browserslist": {
+ "version": "4.27.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz",
+ "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.8.19",
+ "caniuse-lite": "^1.0.30001751",
+ "electron-to-chromium": "^1.5.238",
+ "node-releases": "^2.0.26",
+ "update-browserslist-db": "^1.1.4"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
"node_modules/buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -1908,7 +2813,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -1963,6 +2867,15 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -1990,6 +2903,28 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "license": "MIT"
+ },
+ "node_modules/cosmiconfig": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+ "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2009,7 +2944,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true,
"license": "MIT"
},
"node_modules/damerau-levenshtein": {
@@ -2077,7 +3011,6 @@
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -2167,17 +3100,14 @@
"node": ">=8"
}
},
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "license": "Apache-2.0",
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "license": "MIT",
"dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
}
},
"node_modules/dunder-proto": {
@@ -2195,6 +3125,13 @@
"node": ">= 0.4"
}
},
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.244",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.244.tgz",
+ "integrity": "sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
@@ -2211,6 +3148,15 @@
"once": "^1.4.0"
}
},
+ "node_modules/error-ex": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
"node_modules/es-abstract": {
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
@@ -2388,11 +3334,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -2402,82 +3357,84 @@
}
},
"node_modules/eslint": {
- "version": "8.57.1",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
- "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
- "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+ "version": "9.38.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz",
+ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.1",
- "@humanwhocodes/config-array": "^0.13.0",
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.1",
+ "@eslint/config-helpers": "^0.4.1",
+ "@eslint/core": "^0.16.0",
+ "@eslint/eslintrc": "^3.3.1",
+ "@eslint/js": "9.38.0",
+ "@eslint/plugin-kit": "^0.4.0",
+ "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
+ "cross-spawn": "^7.0.6",
"debug": "^4.3.2",
- "doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "esquery": "^1.4.2",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
+ "file-entry-cache": "^8.0.0",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
+ "optionator": "^0.9.3"
},
"bin": {
"eslint": "bin/eslint.js"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
}
},
"node_modules/eslint-config-next": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.6.tgz",
- "integrity": "sha512-cGr3VQlPsZBEv8rtYp4BpG1KNXDqGvPo9VC1iaCgIA11OfziC/vczng+TnAS3WpRIR3Q5ye/6yl+CRUuZ1fPGg==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.1.tgz",
+ "integrity": "sha512-wNuHw5gNOxwLUvpg0cu6IL0crrVC9hAwdS/7UwleNkwyaMiWIOAwf8yzXVqBBzL3c9A7jVRngJxjoSpPP1aEhg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@next/eslint-plugin-next": "15.5.6",
- "@rushstack/eslint-patch": "^1.10.3",
- "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
- "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+ "@next/eslint-plugin-next": "16.0.1",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^3.5.2",
- "eslint-plugin-import": "^2.31.0",
+ "eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.0",
"eslint-plugin-react": "^7.37.0",
- "eslint-plugin-react-hooks": "^5.0.0"
+ "eslint-plugin-react-hooks": "^7.0.0",
+ "globals": "16.4.0",
+ "typescript-eslint": "^8.46.0"
},
"peerDependencies": {
- "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0",
+ "eslint": ">=9.0.0",
"typescript": ">=3.3.1"
},
"peerDependenciesMeta": {
@@ -2486,6 +3443,19 @@
}
}
},
+ "node_modules/eslint-config-next/node_modules/globals": {
+ "version": "16.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz",
+ "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/eslint-import-resolver-node": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
@@ -2702,13 +3672,20 @@
}
},
"node_modules/eslint-plugin-react-hooks": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz",
- "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz",
+ "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.24.4",
+ "@babel/parser": "^7.24.4",
+ "hermes-parser": "^0.25.1",
+ "zod": "^3.25.0 || ^4.0.0",
+ "zod-validation-error": "^3.5.0 || ^4.0.0"
+ },
"engines": {
- "node": ">=10"
+ "node": ">=18"
},
"peerDependencies": {
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
@@ -2756,9 +3733,9 @@
}
},
"node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
@@ -2766,7 +3743,7 @@
"estraverse": "^5.2.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
@@ -2785,19 +3762,45 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/eslint/node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
- "acorn": "^8.9.0",
+ "acorn": "^8.15.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "eslint-visitor-keys": "^4.2.1"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree/node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
@@ -2866,9 +3869,9 @@
"license": "MIT"
},
"node_modules/fast-glob": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
- "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+ "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2876,7 +3879,7 @@
"@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.2",
"merge2": "^1.3.0",
- "micromatch": "^4.0.8"
+ "micromatch": "^4.0.4"
},
"engines": {
"node": ">=8.6.0"
@@ -2920,16 +3923,16 @@
}
},
"node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "flat-cache": "^3.0.4"
+ "flat-cache": "^4.0.0"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16.0.0"
}
},
"node_modules/file-uri-to-path": {
@@ -2951,6 +3954,12 @@
"node": ">=8"
}
},
+ "node_modules/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "license": "MIT"
+ },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -2969,18 +3978,17 @@
}
},
"node_modules/flat-cache": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
"dev": true,
"license": "MIT",
"dependencies": {
"flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
+ "keyv": "^4.5.4"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16"
}
},
"node_modules/flatted": {
@@ -3012,18 +4020,10 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"license": "MIT"
},
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -3070,6 +4070,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -3160,16 +4170,13 @@
}
},
"node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "type-fest": "^0.20.2"
- },
"engines": {
- "node": ">=8"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -3297,7 +4304,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@@ -3306,6 +4312,32 @@
"node": ">= 0.4"
}
},
+ "node_modules/hermes-estree": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
+ "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.25.1"
+ }
+ },
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -3340,7 +4372,6 @@
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
@@ -3363,18 +4394,6 @@
"node": ">=0.8.19"
}
},
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -3420,6 +4439,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "license": "MIT"
+ },
"node_modules/is-async-function": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
@@ -3500,7 +4525,6 @@
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
@@ -3659,16 +4683,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -3865,6 +4879,18 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -3872,6 +4898,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "license": "MIT"
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -3959,6 +4991,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -3994,6 +5032,16 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -4072,7 +5120,6 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -4123,12 +5170,12 @@
"license": "MIT"
},
"node_modules/next": {
- "version": "15.5.6",
- "resolved": "https://registry.npmjs.org/next/-/next-15.5.6.tgz",
- "integrity": "sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/next/-/next-16.0.1.tgz",
+ "integrity": "sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==",
"license": "MIT",
"dependencies": {
- "@next/env": "15.5.6",
+ "@next/env": "16.0.1",
"@swc/helpers": "0.5.15",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
@@ -4138,18 +5185,18 @@
"next": "dist/bin/next"
},
"engines": {
- "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
+ "node": ">=20.9.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "15.5.6",
- "@next/swc-darwin-x64": "15.5.6",
- "@next/swc-linux-arm64-gnu": "15.5.6",
- "@next/swc-linux-arm64-musl": "15.5.6",
- "@next/swc-linux-x64-gnu": "15.5.6",
- "@next/swc-linux-x64-musl": "15.5.6",
- "@next/swc-win32-arm64-msvc": "15.5.6",
- "@next/swc-win32-x64-msvc": "15.5.6",
- "sharp": "^0.34.3"
+ "@next/swc-darwin-arm64": "16.0.1",
+ "@next/swc-darwin-x64": "16.0.1",
+ "@next/swc-linux-arm64-gnu": "16.0.1",
+ "@next/swc-linux-arm64-musl": "16.0.1",
+ "@next/swc-linux-x64-gnu": "16.0.1",
+ "@next/swc-linux-x64-musl": "16.0.1",
+ "@next/swc-win32-arm64-msvc": "16.0.1",
+ "@next/swc-win32-x64-msvc": "16.0.1",
+ "sharp": "^0.34.4"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@@ -4186,11 +5233,17 @@
"node": ">=10"
}
},
+ "node_modules/node-releases": {
+ "version": "2.0.27",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
+ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -4390,7 +5443,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
@@ -4399,6 +5451,24 @@
"node": ">=6"
}
},
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -4409,16 +5479,6 @@
"node": ">=8"
}
},
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -4433,9 +5493,17 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -4533,7 +5601,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
@@ -4607,37 +5674,48 @@
}
},
"node_modules/react": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
- "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
+ "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
- "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "version": "19.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
+ "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT",
"dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.2"
+ "scheduler": "^0.27.0"
},
"peerDependencies": {
- "react": "^18.3.1"
+ "react": "^19.2.0"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -4700,7 +5778,6 @@
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.1",
@@ -4721,7 +5798,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -4748,45 +5824,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "deprecated": "Rimraf versions prior to v4 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/rimraf/node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "deprecated": "Glob versions prior to v9 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -4887,13 +5924,10 @@
}
},
"node_modules/scheduler": {
- "version": "0.23.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
- "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
},
"node_modules/semver": {
"version": "7.7.3",
@@ -5143,6 +6177,15 @@
"simple-concat": "^1.0.0"
}
},
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -5295,19 +6338,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
@@ -5354,6 +6384,12 @@
}
}
},
+ "node_modules/stylis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
+ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
+ "license": "MIT"
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -5371,7 +6407,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -5408,13 +6443,6 @@
"node": ">=6"
}
},
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -5533,19 +6561,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
@@ -5638,6 +6653,30 @@
"node": ">=14.17"
}
},
+ "node_modules/typescript-eslint": {
+ "version": "8.46.2",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.2.tgz",
+ "integrity": "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.46.2",
+ "@typescript-eslint/parser": "8.46.2",
+ "@typescript-eslint/typescript-estree": "8.46.2",
+ "@typescript-eslint/utils": "8.46.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
"node_modules/unbox-primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
@@ -5658,9 +6697,9 @@
}
},
"node_modules/undici-types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
- "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
@@ -5699,6 +6738,37 @@
"@unrs/resolver-binding-win32-x64-msvc": "1.11.1"
}
},
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz",
+ "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -5836,6 +6906,22 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"license": "ISC"
},
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -5848,6 +6934,29 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zod": {
+ "version": "4.1.12",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
+ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-validation-error": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
+ "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.25.0 || ^4.0.0"
+ }
}
}
}
diff --git a/package.json b/package.json
index 8b3f8801..261641c9 100644
--- a/package.json
+++ b/package.json
@@ -11,18 +11,22 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
- "bcryptjs": "^2.4.3",
- "better-sqlite3": "^11.6.0",
- "next": "^15.0.0",
- "react": "^18.3.1",
- "react-dom": "^18.3.1"
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "@mui/icons-material": "^7.3.4",
+ "@mui/material": "^7.3.4",
+ "bcryptjs": "^3.0.2",
+ "better-sqlite3": "^12.4.1",
+ "next": "^16.0.1",
+ "react": "^19.2.0",
+ "react-dom": "^19.2.0"
},
"devDependencies": {
- "@types/node": "^20.12.12",
- "@types/react": "^18.2.37",
- "@types/react-dom": "^18.2.15",
- "eslint": "^8.57.0",
- "eslint-config-next": "^15.0.0",
- "typescript": "^5.4.5"
+ "@types/node": "^24.9.2",
+ "@types/react": "^19.2.2",
+ "@types/react-dom": "^19.2.2",
+ "eslint": "^9.38.0",
+ "eslint-config-next": "^16.0.1",
+ "typescript": "^5.9.3"
}
}
diff --git a/src/lib/auth/session.ts b/src/lib/auth/session.ts
index ba064649..94fd4c4a 100644
--- a/src/lib/auth/session.ts
+++ b/src/lib/auth/session.ts
@@ -7,6 +7,16 @@ import { config } from "../config";
const SESSION_COOKIE = "cpm_session";
const SESSION_TTL_MS = 1000 * 60 * 60 * 24 * 7; // 7 days
+type CookiesHandle = Awaited>;
+
+async function getCookieStore(): Promise {
+ const store = cookies();
+ if (typeof (store as any)?.then === "function") {
+ return (await store) as CookiesHandle;
+ }
+ return store as CookiesHandle;
+}
+
function hashToken(token: string): string {
return crypto.createHmac("sha256", config.sessionSecret).update(token).digest("hex");
}
@@ -37,7 +47,7 @@ export type SessionContext = {
user: UserRecord;
};
-export function createSession(userId: number): SessionRecord {
+export async function createSession(userId: number): Promise {
const token = crypto.randomBytes(48).toString("base64url");
const hashed = hashToken(token);
const expiresAt = new Date(Date.now() + SESSION_TTL_MS).toISOString();
@@ -56,24 +66,30 @@ export function createSession(userId: number): SessionRecord {
created_at: nowIso()
};
- const cookieStore = cookies();
- cookieStore.set({
- name: SESSION_COOKIE,
- value: token,
- httpOnly: true,
- secure: process.env.NODE_ENV === "production",
- sameSite: "lax",
- path: "/",
- expires: new Date(expiresAt)
- });
+ const cookieStore = await getCookieStore();
+ if (typeof (cookieStore as any).set === "function") {
+ (cookieStore as any).set({
+ name: SESSION_COOKIE,
+ value: token,
+ httpOnly: true,
+ secure: process.env.NODE_ENV === "production",
+ sameSite: "lax",
+ path: "/",
+ expires: new Date(expiresAt)
+ });
+ } else {
+ console.warn("Unable to set session cookie in this context.");
+ }
return session;
}
-export function destroySession() {
- const cookieStore = cookies();
- const token = cookieStore.get(SESSION_COOKIE);
- cookieStore.delete(SESSION_COOKIE);
+export async function destroySession() {
+ const cookieStore = await getCookieStore();
+ const token = typeof (cookieStore as any).get === "function" ? cookieStore.get(SESSION_COOKIE) : undefined;
+ if (typeof (cookieStore as any).delete === "function") {
+ (cookieStore as any).delete(SESSION_COOKIE);
+ }
if (!token) {
return;
@@ -83,9 +99,9 @@ export function destroySession() {
db.prepare("DELETE FROM sessions WHERE token = ?").run(hashed);
}
-export function getSession(): SessionContext | null {
- const cookieStore = cookies();
- const token = cookieStore.get(SESSION_COOKIE);
+export async function getSession(): Promise {
+ const cookieStore = await getCookieStore();
+ const token = typeof (cookieStore as any).get === "function" ? cookieStore.get(SESSION_COOKIE) : undefined;
if (!token) {
return null;
}
@@ -100,13 +116,17 @@ export function getSession(): SessionContext | null {
.get(hashed) as SessionRecord | undefined;
if (!session) {
- cookieStore.delete(SESSION_COOKIE);
+ if (typeof (cookieStore as any).delete === "function") {
+ (cookieStore as any).delete(SESSION_COOKIE);
+ }
return null;
}
if (new Date(session.expires_at).getTime() < Date.now()) {
db.prepare("DELETE FROM sessions WHERE id = ?").run(session.id);
- cookieStore.delete(SESSION_COOKIE);
+ if (typeof (cookieStore as any).delete === "function") {
+ (cookieStore as any).delete(SESSION_COOKIE);
+ }
return null;
}
@@ -118,15 +138,17 @@ export function getSession(): SessionContext | null {
.get(session.user_id) as UserRecord | undefined;
if (!user || user.status !== "active") {
- cookieStore.delete(SESSION_COOKIE);
+ if (typeof (cookieStore as any).delete === "function") {
+ (cookieStore as any).delete(SESSION_COOKIE);
+ }
return null;
}
return { session, user };
}
-export function requireUser(): SessionContext {
- const context = getSession();
+export async function requireUser(): Promise {
+ const context = await getSession();
if (!context) {
redirect("/login");
}
diff --git a/tsconfig.json b/tsconfig.json
index 0fa117cd..94911638 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES2020",
- "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "lib": [
+ "DOM",
+ "DOM.Iterable",
+ "ES2022"
+ ],
"allowJs": false,
"skipLibCheck": true,
"strict": true,
@@ -11,14 +15,34 @@
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
- "jsx": "preserve",
+ "jsx": "react-jsx",
"incremental": true,
- "types": ["node"],
+ "types": [
+ "node"
+ ],
"paths": {
- "@/*": ["./*"],
- "@/src/*": ["src/*"]
- }
+ "@/*": [
+ "./*"
+ ],
+ "@/src/*": [
+ "src/*"
+ ]
+ },
+ "esModuleInterop": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ]
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
- "exclude": ["node_modules"]
+ "include": [
+ "**/*.ts",
+ "**/*.tsx",
+ "next-env.d.ts",
+ ".next/types/**/*.ts",
+ ".next/dev/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}