From cfd05e24fb51890a9f722bf0e01fc8a17e527227 Mon Sep 17 00:00:00 2001 From: Vatsal Ojha Date: Wed, 12 Nov 2025 21:35:40 +0530 Subject: [PATCH] Feat: implement QA Gate --- app/api/qa-gate/route.ts | 162 +++++++++++++++++++++++++++++++++++++ app/api/qa-logout/route.ts | 43 ++++++++++ app/qa-gate/page.tsx | 138 +++++++++++++++++++++++++++++++ lib/constants.ts | 9 +++ middleware.ts | 77 +++++++++++++----- package-lock.json | 132 ++++++++++++++---------------- package.json | 1 + 7 files changed, 473 insertions(+), 89 deletions(-) create mode 100644 app/api/qa-gate/route.ts create mode 100644 app/api/qa-logout/route.ts create mode 100644 app/qa-gate/page.tsx create mode 100644 lib/constants.ts diff --git a/app/api/qa-gate/route.ts b/app/api/qa-gate/route.ts new file mode 100644 index 0000000..c44fedf --- /dev/null +++ b/app/api/qa-gate/route.ts @@ -0,0 +1,162 @@ +// app/api/qa-gate/route.ts +import { NextResponse } from "next/server"; +import { serialize } from "cookie"; +import crypto from "crypto"; +import { ENV } from "@/lib/constants"; +import { SECRETKEY } from "@/lib/constants"; +import { GHTOKEN } from "@/lib/constants"; +import { TEAMNAMES } from "@/lib/constants"; +import { ORG } from "@/lib/constants"; +// import { DOMAIN } from "@/lib/constants"; + +export async function POST(req: Request) { + console.log("QA Gate API called, ENV:", ENV); + + if (ENV !== "QA") { + return NextResponse.json({ error: "Not found" }, { status: 404 }); + } + + try { + const body = await req.json().catch(() => null); + if (!body) { + return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); + } + + const { username, password } = body; + + if (!username || !password) { + return NextResponse.json({ error: "Username and password required" }, { status: 400 }); + } + + if (!SECRETKEY || !GHTOKEN || !TEAMNAMES) { + console.error("Missing required env vars:", { + hasSecretKey: !!SECRETKEY, + hasGhToken: !!GHTOKEN, + hasTeamNames: !!TEAMNAMES, + }); + return NextResponse.json({ error: "Server configuration error" }, { status: 500 }); + } + + const expectedPassword = `${username}-${SECRETKEY}`; + const isValid = + password.length === expectedPassword.length && + crypto.timingSafeEqual(Buffer.from(password), Buffer.from(expectedPassword)); + + if (!isValid) { + console.log("Invalid password for user:", username); + return NextResponse.json({ error: "Invalid password" }, { status: 401 }); + } + + console.log("Checking GitHub org membership for:", username); + + // Check if user is in org + const orgRes = await fetch(`https://api.github.com/orgs/${ORG}/members/${username}`, { + headers: { + Authorization: `Bearer ${GHTOKEN}`, + Accept: "application/vnd.github+json", + "User-Agent": "QA-Gate-App", + }, + }); + + console.log("Org check response:", orgRes.status); + + if (orgRes.status === 404) { + return NextResponse.json({ + error: "Not a member of Dijkstra-Edu organization" + }, { status: 403 }); + } else if (orgRes.status === 401) { + return NextResponse.json({ error: "GitHub token invalid" }, { status: 500 }); + } else if (!orgRes.ok) { + return NextResponse.json({ error: "Organization check failed" }, { status: 403 }); + } + + console.log("Checking team membership for:", username, "in teams:", TEAMNAMES); + + // Split team names and check membership in any of them + const allowedTeams = TEAMNAMES.split(',').map(team => team.trim()); + let userInTeam = false; + let memberOfTeams: string[] = []; + + for (const teamName of allowedTeams) { + console.log("Checking membership in team:", teamName); + + const teamRes = await fetch( + `https://api.github.com/orgs/${ORG}/teams/team-${teamName}/members/${username}`, + { + headers: { + Authorization: `Bearer ${GHTOKEN}`, + Accept: "application/vnd.github+json", + "User-Agent": "QA-Gate-App", + }, + } + ); + + console.log(`Team '${teamName}' check response:`, teamRes.status); + + if (teamRes.status === 200 || teamRes.status === 204) { + userInTeam = true; + memberOfTeams.push(teamName); + console.log(`User is a member of team: ${teamName}`); + break; + } else if (teamRes.status === 404) { + console.log(`User is not a member of team: ${teamName} (or team doesn't exist)`); + } else if (teamRes.status === 401) { + return NextResponse.json({ error: "Insufficient permissions to check team membership" }, { status: 500 }); + } else { + console.error(`Team '${teamName}' membership check failed:`, teamRes.status); + } + } + + if (!userInTeam) { + return NextResponse.json({ + error: `Not a member of any required development teams` + }, { status: 403 }); + } + + // All checks passed - issue cookie + console.log("All checks passed, issuing cookie. User is member of teams:", memberOfTeams); + return issueSuccessResponse(`Access granted for team member of: ${memberOfTeams.join(', ')}`, req); + + } catch (err) { + console.error("QA verify error:", err); + return NextResponse.json({ + error: "Internal server error", + details: ENV === "QA" ? String(err) : undefined + }, { status: 500 }); + } +} + +function issueSuccessResponse(note: string, req: Request) { + const res = NextResponse.json({ + success: true, + message: "Access granted", + note, + timestamp: new Date().toISOString(), + }); + + // Get the request URL + const url = new URL(req.url); + const isSecure = url.protocol === 'https:'; + const hostname = url.hostname; + + // More robust cookie settings + const cookieOptions: any = { + path: "/", + httpOnly: true, + secure: isSecure, + sameSite: "lax" as const, + maxAge: 60 * 60 * 8, // 8 hours + }; + + // Additional debug logging + console.log("Setting cookie with options:", { + ...cookieOptions, + url: url.origin, + protocol: url.protocol, + hostname, + }); + + res.headers.set("Set-Cookie", serialize("qa_verified", "true", cookieOptions)); + + return res; +} \ No newline at end of file diff --git a/app/api/qa-logout/route.ts b/app/api/qa-logout/route.ts new file mode 100644 index 0000000..4fb7b30 --- /dev/null +++ b/app/api/qa-logout/route.ts @@ -0,0 +1,43 @@ +// app/api/qa-logout/route.ts +import { NextResponse } from "next/server"; +import { serialize } from "cookie"; +import { ENV } from "@/lib/constants"; + +export async function POST(req: Request) { + console.log("QA logout API called"); + + // Allow this in any environment for cleanup purposes + try { + const url = new URL(req.url); + const isSecure = url.protocol === "https:"; + + const cookieOptions = { + path: "/", + httpOnly: true, + secure: ENV === "QA" ? true : isSecure, + sameSite: "lax" as const, + maxAge: 0, + expires: new Date(0), + }; + + const cookieHeader = serialize("qa_verified", "", cookieOptions); + console.log("Setting cookie header:", cookieHeader); + + const res = NextResponse.json({ + success: true, + message: "QA access cleared", + timestamp: new Date().toISOString(), + cookieCleared: true, + environment: ENV + }); + + // Set multiple cookie clearing headers to be sure + res.headers.set("Set-Cookie", cookieHeader); + + console.log("QA cookie cleared successfully"); + return res; + } catch (err) { + console.error("QA logout error:", err); + return NextResponse.json({ error: "Internal server error" }, { status: 500 }); + } +} \ No newline at end of file diff --git a/app/qa-gate/page.tsx b/app/qa-gate/page.tsx new file mode 100644 index 0000000..1bb7ee6 --- /dev/null +++ b/app/qa-gate/page.tsx @@ -0,0 +1,138 @@ +"use client"; +import { useState } from "react"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Eye, EyeOff } from "lucide-react"; +import { JOIN_PAGE } from "@/lib/constants"; + +export default function QAGatePage() { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [showPassword, setShowPassword] = useState(false); + const [error, setError] = useState(""); + const [loading, setLoading] = useState(false); + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + setError(""); + setLoading(true); + + try { + console.log("Submitting QA gate request..."); + const res = await fetch("/api/qa-gate", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ username, password }), + credentials: "include", + }); + + console.log("Response status:", res.status); + console.log("Response ok:", res.ok); + + if (res.ok) { + const data = await res.json(); + console.log("QA gate passed:", data); + // Redirect to login or home page + window.location.href = "/"; + } else { + let errorMessage = "Access denied"; + try { + const data = await res.json(); + errorMessage = data.error || errorMessage; + } catch (parseError) { + console.error("Error parsing response:", parseError); + errorMessage = `Server error (${res.status})`; + } + setError(errorMessage); + } + } catch (err: unknown) { + if (err instanceof Error) { + console.error("QA gate error:", err); + setError(`Network error: ${err.message}`); + } else { + console.error("Unknown error:", err); + setError("An unknown error occurred. Please try again."); + } + } finally { + setLoading(false); + } + } + + return ( +
+ + +
+ Dijkstra Logo +
+ Dijkstra QA Environment Access +

+ Enter your GitHub credentials to access the QA environment +

+
+ +
+ setUsername(e.target.value)} + disabled={loading} + required + /> +
+ setPassword(e.target.value)} + disabled={loading} + required + className="pr-10" + /> + +
+ {error && ( +
+

{error}

+
+ )} + +
+

+ • Must be a member of Dijkstra-Edu organization.

Not a member?{" "} + + Join here + +

+

• Must be part of the development team

+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/lib/constants.ts b/lib/constants.ts new file mode 100644 index 0000000..f05bddb --- /dev/null +++ b/lib/constants.ts @@ -0,0 +1,9 @@ +export const ENV = process.env.ENVIRONMENT || "DEV"; +export const SECRETKEY = process.env.SECRET_KEY; +export const GHTOKEN = process.env.GITHUB_TOKEN; +export const TEAMNAMES = process.env.TEAM_NAMES; +export const ORG = process.env.ORG; +export const JOIN_PAGE = process.env.NEXT_PUBLIC_JOINING_PAGE_URL || "https://github.com/Dijkstra-Edu"; +export const DOMAIN = process.env.DOMAIN; + + diff --git a/middleware.ts b/middleware.ts index f21df20..01c5fdb 100644 --- a/middleware.ts +++ b/middleware.ts @@ -45,40 +45,79 @@ // middleware.ts import { withAuth } from "next-auth/middleware"; import { NextResponse } from "next/server"; +import { ENV } from "./lib/constants" export default withAuth( - function middleware(req) { - //console.log("Middleware running for:", req.nextUrl.pathname); - - // You can add additional logic here if needed - // For now, just continue + async function middleware(req) { + const { pathname, origin} = req.nextUrl; + + // QA lockdown - block EVERYTHING except QA gate routes + if (ENV === "QA") { + const token = req.nextauth.token; + const bypassCookie = req.cookies.get("qa_verified")?.value; + + // ONLY allow QA gate routes and essential API routes + const isQAGateRoute = + pathname.startsWith("/qa-gate") || + pathname.startsWith("/api/qa-gate") || + pathname.startsWith("/api/qa-logout") || + pathname.startsWith("/api/auth"); // NextAuth API routes + + // If QA gate route, allow through + if (isQAGateRoute) { + return NextResponse.next(); + } + + // For ALL other routes (including /login), check QA bypass first + if (!bypassCookie) { + return NextResponse.redirect(new URL("/qa-gate", origin)); + } + + // After QA bypass is confirmed, check NextAuth requirements + // Allow /login page since user has passed QA gate + if (pathname === "/" || pathname === "/login" || pathname.startsWith("/onboarding")) { + return NextResponse.next(); + } + + // For all other protected routes, also require NextAuth token + if (!token) { + return NextResponse.redirect(new URL("/", origin)); + } + } + return NextResponse.next(); }, { callbacks: { authorized: ({ token, req }) => { - //console.log("Token in authorized:", token); const { pathname } = req.nextUrl; - - - //const publicRoutes = ["/","/login"]; - //const isPublicRoute = publicRoutes.some(route => pathname.startsWith(route)); - - // Public routes that don't require authentication - if (pathname === '/' || pathname === "/login" || pathname.startsWith("/onboarding")){ + + // For QA environment, let the main middleware handle all authorization + if (ENV === "QA") { return true; } - - // All other routes require authentication - return !!(token); + + // Always allow these public routes in non-QA environments + if ( + pathname === "/" || + pathname === "/login" || + pathname.startsWith("/onboarding") || + pathname.startsWith("/api/auth") + ) { + return true; + } + + // For non-QA environments, require token for protected routes + return !!token; }, }, - pages: { - signIn: "/login", - }, + //pages: { + // signIn: "/login", + //}, } ); + export const config = { matcher: [ /* diff --git a/package-lock.json b/package-lock.json index 9d16c1c..81b2e75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "@uiw/react-md-editor": "^3.6.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "cookie": "^1.0.2", "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", "framer-motion": "^12.19.2", @@ -136,6 +137,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -409,6 +411,7 @@ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", "license": "MIT", + "peer": true, "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", @@ -1198,7 +1201,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -3262,6 +3264,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.24.2.tgz", "integrity": "sha512-RZ0+RdU9i88WqJF3ca1MWWDC08Ad2y9F2pytCfgohKHswNzhz0qeacoWZU/44yI15D+r320Peu6ucsy0uV+u4w==", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -3696,6 +3699,7 @@ "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.24.2.tgz", "integrity": "sha512-g9UGZRVtJJsGNtaQUlIwQQVX5akPJRZSMGvxyp02tj32mFTS8Q+ldD/4J7jCwevCJWZmb/fIbVrANzIFEiHsLw==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-changeset": "^2.3.0", "prosemirror-collab": "^1.3.1", @@ -3871,7 +3875,6 @@ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -3882,7 +3885,6 @@ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -3973,6 +3975,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -3983,6 +3986,7 @@ "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.0.0" } @@ -4081,6 +4085,7 @@ "integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.35.0", "@typescript-eslint/types": "8.35.0", @@ -4646,7 +4651,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" @@ -4656,29 +4660,25 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", @@ -4689,15 +4689,13 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -4710,7 +4708,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "license": "MIT", - "peer": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } @@ -4720,7 +4717,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@xtuc/long": "4.2.2" } @@ -4729,15 +4725,13 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -4754,7 +4748,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", @@ -4768,7 +4761,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", @@ -4781,7 +4773,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", @@ -4796,7 +4787,6 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "license": "MIT", - "peer": true, "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" @@ -4812,21 +4802,20 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5263,6 +5252,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", @@ -5304,8 +5294,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/busboy": { "version": "1.6.0", @@ -5496,7 +5485,6 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.0" } @@ -5587,8 +5575,7 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/common-path-prefix": { "version": "3.0.0", @@ -5610,12 +5597,12 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" } }, "node_modules/crelt": { @@ -5998,7 +5985,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/embla-carousel-react": { "version": "8.6.0", @@ -6175,8 +6163,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.1", @@ -6275,6 +6262,7 @@ "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -6449,6 +6437,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -6704,7 +6693,6 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.8.x" } @@ -7072,8 +7060,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause", - "peer": true + "license": "BSD-2-Clause" }, "node_modules/globals": { "version": "14.0.0", @@ -7520,6 +7507,7 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -8125,7 +8113,6 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -8140,7 +8127,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -8212,8 +8198,7 @@ "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", - "peer": true + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -8570,7 +8555,6 @@ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.11.5" } @@ -8972,8 +8956,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", @@ -9552,7 +9535,6 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -9562,7 +9544,6 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", - "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -9733,8 +9714,7 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/next": { "version": "15.3.4", @@ -9822,6 +9802,15 @@ } } }, + "node_modules/next-auth/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next-remove-imports": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/next-remove-imports/-/next-remove-imports-1.0.12.tgz", @@ -10344,6 +10333,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.9.tgz", "integrity": "sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -10519,6 +10509,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.1.tgz", "integrity": "sha512-AUvbm7qqmpZa5d9fPKMvH1Q5bqYQvAZWOGRvxsB6iFLyycvC9MwNemNVjHVrWgjaoxAfY8XVg7DbvQ/qxvI9Eg==", "license": "MIT", + "peer": true, "dependencies": { "orderedmap": "^2.0.0" } @@ -10548,6 +10539,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz", "integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-transform": "^1.0.0", @@ -10596,6 +10588,7 @@ "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.40.0.tgz", "integrity": "sha512-2G3svX0Cr1sJjkD/DYWSe3cfV5VPVTBOxI9XQEGWJDFEpsZb/gh4MV29ctv+OJx2RFX4BLt09i+6zaGM/ldkCw==", "license": "MIT", + "peer": true, "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", @@ -10647,7 +10640,6 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "^5.1.0" } @@ -10657,6 +10649,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -10666,6 +10659,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -10677,7 +10671,8 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/react-markdown": { "version": "7.0.1", @@ -10755,6 +10750,7 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", + "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -10902,7 +10898,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -11415,8 +11412,7 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/safe-push-apply": { "version": "1.0.0", @@ -11459,6 +11455,7 @@ "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -11504,6 +11501,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -11551,7 +11549,6 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "randombytes": "^2.1.0" } @@ -11771,7 +11768,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -11790,7 +11786,6 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "license": "MIT", - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -12082,7 +12077,8 @@ "version": "4.1.10", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.10.tgz", "integrity": "sha512-P3nr6WkvKV/ONsTzj6Gb57sWPMX29EPNPopo7+FcpkQaNsrNpZ1pv8QmrYI2RqEKD7mlGqLnGovlcYnBK0IqUA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -12125,7 +12121,6 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", @@ -12144,7 +12139,6 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", @@ -12178,7 +12172,8 @@ "version": "0.177.0", "resolved": "https://registry.npmjs.org/three/-/three-0.177.0.tgz", "integrity": "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tiny-invariant": { "version": "1.3.3", @@ -12224,6 +12219,7 @@ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -12415,6 +12411,7 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12832,7 +12829,6 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "license": "MIT", - "peer": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -12856,7 +12852,6 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", @@ -12904,7 +12899,6 @@ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.13.0" } @@ -12914,7 +12908,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -12928,7 +12921,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=4.0" } diff --git a/package.json b/package.json index b13800e..aade6dc 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@uiw/react-md-editor": "^3.6.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "cookie": "^1.0.2", "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", "framer-motion": "^12.19.2",