diff --git a/backend/prisma/migrations/20251224191233_add_release_notes_acceptances/migration.sql b/backend/prisma/migrations/20251224191233_add_release_notes_acceptances/migration.sql new file mode 100644 index 0000000..34f618f --- /dev/null +++ b/backend/prisma/migrations/20251224191233_add_release_notes_acceptances/migration.sql @@ -0,0 +1,22 @@ +-- CreateTable +CREATE TABLE "release_notes_acceptances" ( + "id" TEXT NOT NULL, + "user_id" TEXT NOT NULL, + "version" TEXT NOT NULL, + "accepted_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "release_notes_acceptances_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "release_notes_acceptances_user_id_version_key" ON "release_notes_acceptances"("user_id", "version"); + +-- CreateIndex +CREATE INDEX "release_notes_acceptances_user_id_idx" ON "release_notes_acceptances"("user_id"); + +-- CreateIndex +CREATE INDEX "release_notes_acceptances_version_idx" ON "release_notes_acceptances"("version"); + +-- AddForeignKey +ALTER TABLE "release_notes_acceptances" ADD CONSTRAINT "release_notes_acceptances_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; + diff --git a/backend/prisma/migrations/20251225000000_add_show_github_version_on_login/migration.sql b/backend/prisma/migrations/20251225000000_add_show_github_version_on_login/migration.sql new file mode 100644 index 0000000..530f881 --- /dev/null +++ b/backend/prisma/migrations/20251225000000_add_show_github_version_on_login/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "settings" ADD COLUMN "show_github_version_on_login" BOOLEAN NOT NULL DEFAULT true; + diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index a06bcb4..14ef554 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -202,6 +202,7 @@ model settings { metrics_enabled Boolean @default(true) metrics_anonymous_id String? metrics_last_sent DateTime? + show_github_version_on_login Boolean @default(true) } model update_history { @@ -250,6 +251,7 @@ model users { dashboard_preferences dashboard_preferences[] user_sessions user_sessions[] auto_enrollment_tokens auto_enrollment_tokens[] + release_notes_acceptances release_notes_acceptances[] } model user_sessions { @@ -437,3 +439,15 @@ model job_history { @@index([status]) @@index([created_at]) } + +model release_notes_acceptances { + id String @id @default(uuid()) + user_id String + version String + accepted_at DateTime @default(now()) + users users @relation(fields: [user_id], references: [id], onDelete: Cascade) + + @@unique([user_id, version]) + @@index([user_id]) + @@index([version]) +} diff --git a/backend/release-notes/RELEASE_NOTES_1.3.7.md b/backend/release-notes/RELEASE_NOTES_1.3.7.md new file mode 100644 index 0000000..4f78fa5 --- /dev/null +++ b/backend/release-notes/RELEASE_NOTES_1.3.7.md @@ -0,0 +1,34 @@ +## 📝 ALERT : Auto-update of Agent issue + +Versions <1.3.6 have an issue where the service does not restart after auto-update. OpenRC systems are unaffected and work correctly. +This means you will unfortunately have to use `systemctl start patchmon-agent` on your systems to load up 1.3.7 agent when it auto-updates shortly. + +Very sorry for this, future versions are fixed - I built this release notes notification feature specifically to notify you of this. + +--- + +## 🎉 New Features & Improvements : + +**Mobile UI**: Mobile user interface improvements are mostly complete, providing a better experience on mobile devices. + +**Systemctl Helper Script**: In future versions (1.3.7+), a systemctl helper script will be available to assist with auto-update service restarts. + +**Staggered Agent Intervals**: Agents now report at staggered times to prevent overwhelming the PatchMon server. If the agent report interval is set to 60 minutes, different hosts will report at different times. This is in the `config.yml` as "report_offset: nxyz" + +**Reboot Detection Information**: Reboot detection information is now stored in the database. When the "Reboot Required" flag is displayed, hovering over it will show the specific reason why a reboot is needed (Reboot feature still needs work and it will be much better in 1.3.8) + +**JSON Report Output**: The `patchmon-agent report --json` command now outputs the complete report payload to the console in JSON format instead of sending it to the PatchMon server. This is very useful for integrating PatchMon agent data with other tools and for diagnostic purposes. + +**Persistent Docker Toggle**: Docker integration toggle state is now persisted in the database, eliminating in-memory configuration issues. No more losing Docker settings on container restarts (thanks to the community for initiating this feature). + +**Config.yml Synchronization**: The agent now writes and compares the `config.yml` file with the server configuration upon startup, ensuring better synchronization of settings between the agent and server. + +**Network Information Page**: Enhanced network information page to display IPv6 addresses and support multiple network interfaces, providing more comprehensive network details. + +**Auto-Update Logic Fix**: Fixed an issue where agents would auto-update even when per-host auto-update was disabled. The logic now properly honors both server-wide auto-update settings and per-host auto-update settings. + +**Prisma Version Fix**: Fixed Prisma version issues affecting Kubernetes deployments by statically setting the Prisma version in package.json files. + +**Hiding Github Version**: Added a toggle in Server Version settings to disable showing the github release notes on the login screen + +--- diff --git a/backend/src/routes/authRoutes.js b/backend/src/routes/authRoutes.js index 915fc15..9ca0a03 100644 --- a/backend/src/routes/authRoutes.js +++ b/backend/src/routes/authRoutes.js @@ -844,6 +844,24 @@ router.post( req, ); + // Get accepted release notes versions + let acceptedVersions = []; + try { + if (prisma.release_notes_acceptances) { + acceptedVersions = await prisma.release_notes_acceptances.findMany({ + where: { user_id: user.id }, + select: { version: true }, + }); + } + } catch (error) { + // If table doesn't exist yet or Prisma client not regenerated, use empty array + console.warn( + "Could not fetch release notes acceptances:", + error.message, + ); + acceptedVersions = []; + } + res.json({ message: "Login successful", token: session.access_token, @@ -863,6 +881,9 @@ router.post( // Include user preferences so they're available immediately after login theme_preference: user.theme_preference, color_theme: user.color_theme, + accepted_release_notes_versions: acceptedVersions.map( + (a) => a.version, + ), }, }); } catch (error) { @@ -986,13 +1007,36 @@ router.post( req, ); + // Get accepted release notes versions + let acceptedVersions = []; + try { + if (prisma.release_notes_acceptances) { + acceptedVersions = await prisma.release_notes_acceptances.findMany({ + where: { user_id: user.id }, + select: { version: true }, + }); + } + } catch (error) { + // If table doesn't exist yet or Prisma client not regenerated, use empty array + console.warn( + "Could not fetch release notes acceptances:", + error.message, + ); + acceptedVersions = []; + } + res.json({ message: "Login successful", token: session.access_token, refresh_token: session.refresh_token, expires_at: session.expires_at, tfa_bypass_until: session.tfa_bypass_until, - user: updatedUser, + user: { + ...updatedUser, + accepted_release_notes_versions: acceptedVersions.map( + (a) => a.version, + ), + }, }); } catch (error) { console.error("TFA verification error:", error); diff --git a/backend/src/routes/buyMeACoffeeRoutes.js b/backend/src/routes/buyMeACoffeeRoutes.js new file mode 100644 index 0000000..8c681ac --- /dev/null +++ b/backend/src/routes/buyMeACoffeeRoutes.js @@ -0,0 +1,206 @@ +const express = require("express"); +const axios = require("axios"); +const { authenticateToken } = require("../middleware/auth"); + +const router = express.Router(); + +// Cache for supporter count (5 minute cache) +const supporterCountCache = { + count: null, + timestamp: null, + cacheDuration: 5 * 60 * 1000, // 5 minutes +}; + +// Get supporter count from Buy Me a Coffee page +router.get("/supporter-count", authenticateToken, async (_req, res) => { + try { + // Check cache first + const now = Date.now(); + if ( + supporterCountCache.count !== null && + supporterCountCache.timestamp !== null && + now - supporterCountCache.timestamp < supporterCountCache.cacheDuration + ) { + return res.json({ count: supporterCountCache.count, cached: true }); + } + + // Fetch the Buy Me a Coffee page + const response = await axios.get("https://buymeacoffee.com/iby___", { + headers: { + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", + }, + timeout: 10000, // 10 second timeout + }); + + const html = response.data; + + // Try multiple patterns to find the supporter count + let supporterCount = null; + + // Pattern 1: Look for "X supporters" or "X supporter" text (most common) + // Try various formats: "25 supporters", "1 supporter", "25 people", etc. + const textPatterns = [ + /(\d+)\s+supporters?/i, + /(\d+)\s+people\s+(have\s+)?(bought|supported)/i, + /supporter[^>]*>.*?(\d+)/i, + /(\d+)[^<]*supporter/i, + />(\d+)<[^>]*supporter/i, + /supporter[^<]*<[^>]*>(\d+)/i, + ]; + + for (const pattern of textPatterns) { + const match = html.match(pattern); + if (match?.[1]) { + const count = parseInt(match[1], 10); + if (count > 0 && count < 1000000) { + // Reasonable upper limit + supporterCount = count; + break; + } + } + } + + // Pattern 2: Look for data attributes or specific class names + // Buy Me a Coffee might use data attributes like data-count, data-supporters, etc. + if (!supporterCount) { + const dataPatterns = [ + /data-supporters?=["'](\d+)["']/i, + /data-count=["'](\d+)["']/i, + /supporter[^>]*data-[^=]*=["'](\d+)["']/i, + ]; + + for (const pattern of dataPatterns) { + const match = html.match(pattern); + if (match?.[1]) { + const count = parseInt(match[1], 10); + if (count > 0 && count < 1000000) { + supporterCount = count; + break; + } + } + } + } + + // Pattern 3: Look for JSON-LD structured data or meta tags + if (!supporterCount) { + const jsonLdMatches = html.matchAll( + /]*type=["']application\/ld\+json["'][^>]*>(.*?)<\/script>/gis, + ); + for (const jsonLdMatch of jsonLdMatches) { + try { + const jsonLd = JSON.parse(jsonLdMatch[1]); + // Look for supporter count in structured data (could be nested) + const findCount = (obj) => { + if (typeof obj !== "object" || obj === null) return null; + if (obj.supporterCount || obj.supporter_count || obj.supporters) { + return parseInt( + obj.supporterCount || obj.supporter_count || obj.supporters, + 10, + ); + } + for (const value of Object.values(obj)) { + if (typeof value === "object") { + const found = findCount(value); + if (found) return found; + } + } + return null; + }; + const count = findCount(jsonLd); + if (count && count > 0 && count < 1000000) { + supporterCount = count; + break; + } + } catch (_e) { + // Ignore JSON parse errors + } + } + } + + // Pattern 4: Look for specific class names or IDs that Buy Me a Coffee uses + if (!supporterCount) { + const classPatterns = [ + /class="[^"]*supporter[^"]*"[^>]*>.*?(\d+)/i, + /id="[^"]*supporter[^"]*"[^>]*>.*?(\d+)/i, + /]*class="[^"]*count[^"]*"[^>]*>(\d+)<\/span>/i, + ]; + + for (const pattern of classPatterns) { + const match = html.match(pattern); + if (match?.[1]) { + const count = parseInt(match[1], 10); + if (count > 0 && count < 1000000) { + supporterCount = count; + break; + } + } + } + } + + // Pattern 5: Look for numbers near common supporter-related text + if (!supporterCount) { + // Find all numbers in the HTML and check context around them + const numberMatches = html.matchAll(/\b(\d{1,6})\b/g); + for (const match of numberMatches) { + const num = parseInt(match[1], 10); + if (num > 0 && num < 1000000) { + // Check context around this number (200 chars before and after) + const start = Math.max(0, match.index - 200); + const end = Math.min( + html.length, + match.index + match[0].length + 200, + ); + const context = html.substring(start, end).toLowerCase(); + if ( + context.includes("supporter") || + context.includes("coffee") || + context.includes("donation") + ) { + supporterCount = num; + break; + } + } + } + } + + // Update cache + if (supporterCount !== null && supporterCount > 0) { + supporterCountCache.count = supporterCount; + supporterCountCache.timestamp = now; + } + + if (supporterCount === null) { + // If we couldn't parse it, return the cached value if available, or 0 + if (supporterCountCache.count !== null) { + return res.json({ + count: supporterCountCache.count, + cached: true, + error: "Could not parse current count, returning cached value", + }); + } + return res.status(500).json({ + error: "Could not retrieve supporter count", + }); + } + + res.json({ count: supporterCount, cached: false }); + } catch (error) { + console.error("Error fetching Buy Me a Coffee supporter count:", error); + + // Return cached value if available + if (supporterCountCache.count !== null) { + return res.json({ + count: supporterCountCache.count, + cached: true, + error: "Failed to fetch, returning cached value", + }); + } + + res.status(500).json({ + error: "Failed to fetch supporter count", + }); + } +}); + +module.exports = router; diff --git a/backend/src/routes/releaseNotesAcceptanceRoutes.js b/backend/src/routes/releaseNotesAcceptanceRoutes.js new file mode 100644 index 0000000..410c6cf --- /dev/null +++ b/backend/src/routes/releaseNotesAcceptanceRoutes.js @@ -0,0 +1,53 @@ +const express = require("express"); +const { authenticateToken } = require("../middleware/auth"); +const { getPrismaClient } = require("../config/prisma"); + +const prisma = getPrismaClient(); +const router = express.Router(); + +// Mark release notes as accepted for current user +router.post("/accept", authenticateToken, async (req, res) => { + try { + const userId = req.user.id; + const { version } = req.body; + + if (!version) { + return res.status(400).json({ error: "Version is required" }); + } + + // Check if the model exists (Prisma client might not be regenerated yet) + if (!prisma.release_notes_acceptances) { + console.warn( + "release_notes_acceptances model not available - Prisma client may need regeneration", + ); + return res.status(503).json({ + error: + "Release notes acceptance feature not available. Please regenerate Prisma client.", + }); + } + + await prisma.release_notes_acceptances.upsert({ + where: { + user_id_version: { + user_id: userId, + version: version, + }, + }, + update: { + accepted_at: new Date(), + }, + create: { + user_id: userId, + version: version, + accepted_at: new Date(), + }, + }); + + res.json({ success: true }); + } catch (error) { + console.error("Error accepting release notes:", error); + res.status(500).json({ error: "Failed to accept release notes" }); + } +}); + +module.exports = router; diff --git a/backend/src/routes/releaseNotesRoutes.js b/backend/src/routes/releaseNotesRoutes.js new file mode 100644 index 0000000..60d6d21 --- /dev/null +++ b/backend/src/routes/releaseNotesRoutes.js @@ -0,0 +1,104 @@ +const express = require("express"); +const fs = require("node:fs").promises; +const path = require("node:path"); +const { authenticateToken } = require("../middleware/auth"); + +const router = express.Router(); + +// Helper to get current version +function getCurrentVersion() { + try { + const packageJson = require("../../package.json"); + return packageJson?.version || "unknown"; + } catch (error) { + console.error("Could not read version from package.json:", error); + return "unknown"; + } +} + +// Get release notes for a specific version +router.get("/:version", authenticateToken, async (req, res) => { + try { + const { version } = req.params; + const releaseNotesPath = path.join( + __dirname, + "../../release-notes", + `RELEASE_NOTES_${version}.md`, + ); + + try { + const content = await fs.readFile(releaseNotesPath, "utf-8"); + res.json({ + version, + content, + exists: true, + }); + } catch (_fileError) { + // File doesn't exist for this version + res.json({ + version, + content: null, + exists: false, + }); + } + } catch (error) { + console.error("Error fetching release notes:", error); + res.status(500).json({ error: "Failed to fetch release notes" }); + } +}); + +// Get release notes for current version +router.get("/current", authenticateToken, async (_req, res) => { + try { + const currentVersion = getCurrentVersion(); + const releaseNotesPath = path.join( + __dirname, + "../../release-notes", + `RELEASE_NOTES_${currentVersion}.md`, + ); + + try { + const content = await fs.readFile(releaseNotesPath, "utf-8"); + res.json({ + version: currentVersion, + content, + exists: true, + }); + } catch (_fileError) { + // No release notes for current version + res.json({ + version: currentVersion, + content: null, + exists: false, + }); + } + } catch (error) { + console.error("Error fetching current release notes:", error); + res.status(500).json({ error: "Failed to fetch release notes" }); + } +}); + +// List all available release notes versions +router.get("/", authenticateToken, async (_req, res) => { + try { + const releaseNotesDir = path.join(__dirname, "../../release-notes"); + const files = await fs.readdir(releaseNotesDir); + + const versions = files + .filter( + (file) => file.startsWith("RELEASE_NOTES_") && file.endsWith(".md"), + ) + .map((file) => file.replace("RELEASE_NOTES_", "").replace(".md", "")) + .sort((a, b) => { + // Simple version comparison (you might want a more robust one) + return b.localeCompare(a, undefined, { numeric: true }); + }); + + res.json({ versions }); + } catch (error) { + console.error("Error listing release notes:", error); + res.status(500).json({ error: "Failed to list release notes" }); + } +}); + +module.exports = router; diff --git a/backend/src/routes/settingsRoutes.js b/backend/src/routes/settingsRoutes.js index a865e0e..d003ab4 100644 --- a/backend/src/routes/settingsRoutes.js +++ b/backend/src/routes/settingsRoutes.js @@ -134,6 +134,10 @@ router.put( .optional() .isLength({ min: 1 }) .withMessage("Favicon path must be a non-empty string"), + body("showGithubVersionOnLogin") + .optional() + .isBoolean() + .withMessage("Show GitHub version on login must be a boolean"), ], async (req, res) => { try { @@ -159,6 +163,7 @@ router.put( logoLight, favicon, colorTheme, + showGithubVersionOnLogin, } = req.body; // Get current settings to check for update interval changes @@ -191,6 +196,8 @@ router.put( if (logoLight !== undefined) updateData.logo_light = logoLight; if (favicon !== undefined) updateData.favicon = favicon; if (colorTheme !== undefined) updateData.color_theme = colorTheme; + if (showGithubVersionOnLogin !== undefined) + updateData.show_github_version_on_login = showGithubVersionOnLogin; const updatedSettings = await updateSettings( currentSettings.id, @@ -254,6 +261,21 @@ router.get("/server-url", async (_req, res) => { } }); +// Get login settings for public use (used by login screen) +router.get("/login-settings", async (_req, res) => { + try { + const settings = await getSettings(); + res.json({ + show_github_version_on_login: + settings.show_github_version_on_login !== false, + signup_enabled: settings.signup_enabled || false, + }); + } catch (error) { + console.error("Failed to fetch login settings:", error); + res.status(500).json({ error: "Failed to fetch login settings" }); + } +}); + // Get update interval policy for agents (requires API authentication) router.get("/update-interval", async (req, res) => { try { diff --git a/backend/src/server.js b/backend/src/server.js index e92cfd9..c839597 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -72,6 +72,9 @@ const agentVersionRoutes = require("./routes/agentVersionRoutes"); const metricsRoutes = require("./routes/metricsRoutes"); const userPreferencesRoutes = require("./routes/userPreferencesRoutes"); const apiHostsRoutes = require("./routes/apiHostsRoutes"); +const releaseNotesRoutes = require("./routes/releaseNotesRoutes"); +const releaseNotesAcceptanceRoutes = require("./routes/releaseNotesAcceptanceRoutes"); +const buyMeACoffeeRoutes = require("./routes/buyMeACoffeeRoutes"); const { initSettings } = require("./services/settingsService"); const { queueManager } = require("./services/automation"); const { authenticateToken, requireAdmin } = require("./middleware/auth"); @@ -482,6 +485,12 @@ app.use(`/api/${apiVersion}/agent`, agentVersionRoutes); app.use(`/api/${apiVersion}/metrics`, metricsRoutes); app.use(`/api/${apiVersion}/user/preferences`, userPreferencesRoutes); app.use(`/api/${apiVersion}/api`, authLimiter, apiHostsRoutes); +app.use(`/api/${apiVersion}/release-notes`, releaseNotesRoutes); +app.use( + `/api/${apiVersion}/release-notes-acceptance`, + releaseNotesAcceptanceRoutes, +); +app.use(`/api/${apiVersion}/buy-me-a-coffee`, buyMeACoffeeRoutes); // Bull Board - will be populated after queue manager initializes let bullBoardRouter = null; diff --git a/backend/src/services/automation/shared/utils.js b/backend/src/services/automation/shared/utils.js index 0b877c0..382e259 100644 --- a/backend/src/services/automation/shared/utils.js +++ b/backend/src/services/automation/shared/utils.js @@ -1,4 +1,6 @@ // Common utilities for automation jobs +const path = require("node:path"); +const fs = require("node:fs"); /** * Compare two semantic versions @@ -36,7 +38,10 @@ async function checkPublicRepo(owner, repo) { // Get current version for User-Agent (or use generic if unavailable) let currentVersion = "unknown"; try { - const packageJson = require("../../../package.json"); + // Use __dirname to construct absolute path to package.json + const packageJsonPath = path.join(__dirname, "../../../package.json"); + const packageJsonContent = fs.readFileSync(packageJsonPath, "utf8"); + const packageJson = JSON.parse(packageJsonContent); if (packageJson?.version) { currentVersion = packageJson.version; } diff --git a/frontend/package.json b/frontend/package.json index bbf182e..94943e3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,6 +27,7 @@ "react-chartjs-2": "^5.2.0", "react-dom": "^18.3.1", "react-icons": "^5.5.0", + "react-markdown": "^9.0.1", "react-router-dom": "^6.30.1" }, "devDependencies": { diff --git a/frontend/src/components/Layout.jsx b/frontend/src/components/Layout.jsx index c6a234e..3e10e5f 100644 --- a/frontend/src/components/Layout.jsx +++ b/frontend/src/components/Layout.jsx @@ -35,6 +35,7 @@ import { dashboardAPI, versionAPI } from "../utils/api"; import DiscordIcon from "./DiscordIcon"; import GlobalSearch from "./GlobalSearch"; import Logo from "./Logo"; +import ReleaseNotesModal from "./ReleaseNotesModal"; import UpgradeNotificationIcon from "./UpgradeNotificationIcon"; const Layout = ({ children }) => { @@ -47,6 +48,7 @@ const Layout = ({ children }) => { const [_userMenuOpen, setUserMenuOpen] = useState(false); const [githubStars, setGithubStars] = useState(null); const [mobileLinksOpen, setMobileLinksOpen] = useState(false); + const [showReleaseNotes, setShowReleaseNotes] = useState(false); const location = useLocation(); const navigate = useNavigate(); const { @@ -86,6 +88,37 @@ const Layout = ({ children }) => { staleTime: 300000, // Consider data stale after 5 minutes }); + // Check for new release notes when user or version changes + useEffect(() => { + if (!user || !versionInfo?.version) return; + + // Get accepted versions from user object (loaded on login) + const acceptedVersions = user.accepted_release_notes_versions || []; + const currentVersion = versionInfo.version; + + // If already accepted, don't show + if (acceptedVersions.includes(currentVersion)) { + return; + } + + // Check if release notes exist for this version + fetch(`/api/v1/release-notes/${currentVersion}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + }) + .then((res) => res.json()) + .then((data) => { + // Only show if release notes exist and version not accepted + if (data.exists && !acceptedVersions.includes(currentVersion)) { + setShowReleaseNotes(true); + } + }) + .catch((error) => { + console.error("Error checking release notes:", error); + }); + }, [user, versionInfo]); + // Build navigation based on permissions const buildNavigation = () => { const nav = []; @@ -1536,6 +1569,12 @@ const Layout = ({ children }) => {
{children}
+ + {/* Release Notes Modal */} + setShowReleaseNotes(false)} + /> ); }; diff --git a/frontend/src/components/ReleaseNotesModal.jsx b/frontend/src/components/ReleaseNotesModal.jsx new file mode 100644 index 0000000..bf5f90c --- /dev/null +++ b/frontend/src/components/ReleaseNotesModal.jsx @@ -0,0 +1,383 @@ +import { useQuery } from "@tanstack/react-query"; +import { ArrowRight, ExternalLink, Heart, Sparkles } from "lucide-react"; +import { useEffect, useState } from "react"; +import ReactMarkdown from "react-markdown"; +import { useAuth } from "../contexts/AuthContext"; +import { versionAPI } from "../utils/api"; + +const ReleaseNotesModal = ({ isOpen, onAccept }) => { + const [currentStep, setCurrentStep] = useState(1); // 1 = release notes, 2 = founder's note + const [isAccepting, setIsAccepting] = useState(false); + const { acceptReleaseNotes } = useAuth(); + + // Get current app version + const { data: versionInfo } = useQuery({ + queryKey: ["versionInfo"], + queryFn: () => versionAPI.getCurrent().then((res) => res.data), + staleTime: 300000, + }); + + // Get release notes for current version + const { data: releaseNotes, isLoading } = useQuery({ + queryKey: ["releaseNotes", versionInfo?.version], + queryFn: async () => { + if (!versionInfo?.version) return null; + const response = await fetch( + `/api/v1/release-notes/${versionInfo.version}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + }, + ); + return response.json(); + }, + enabled: isOpen && !!versionInfo?.version, + }); + + // Fetch supporter count from Buy Me a Coffee + const { data: supporterData, isLoading: isLoadingSupporters } = useQuery({ + queryKey: ["buyMeACoffeeSupporters"], + queryFn: async () => { + const response = await fetch("/api/v1/buy-me-a-coffee/supporter-count", { + headers: { + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + }); + if (!response.ok) return null; + return response.json(); + }, + enabled: isOpen && currentStep === 2, + staleTime: 5 * 60 * 1000, // 5 minutes cache + }); + + // Check if running on PatchMon Cloud + const isCloudVersion = window.location.hostname.endsWith(".patchmon.cloud"); + + const handleNext = () => { + setCurrentStep(2); + }; + + const handleDonateNow = async () => { + // Open donation page in new tab + window.open( + "https://buymeacoffee.com/iby___", + "_blank", + "noopener,noreferrer", + ); + // Update database to mark as accepted + await handleAccept(); + }; + + const handleMembershipNow = async () => { + // Open membership page in new tab + window.open( + "https://buymeacoffee.com/iby___/membership", + "_blank", + "noopener,noreferrer", + ); + // Update database to mark as accepted + await handleAccept(); + }; + + const handleClose = async () => { + // Update database to mark as accepted + await handleAccept(); + }; + + const handleAccept = async () => { + const currentVersion = versionInfo?.version; + if (!currentVersion) { + onAccept(); + return; + } + + setIsAccepting(true); + + try { + // This updates DB, state, and localStorage + const result = await acceptReleaseNotes(currentVersion); + + if (result.success) { + // Success - state is already updated, modal will close + onAccept(); + } else { + console.error("Failed to accept release notes:", result.error); + // Still close modal even if API call fails + onAccept(); + } + } catch (error) { + console.error("Error accepting release notes:", error); + onAccept(); + } finally { + setIsAccepting(false); + } + }; + + // Reset to step 1 when modal opens + useEffect(() => { + if (isOpen) { + setCurrentStep(1); + } + }, [isOpen]); + + if (!isOpen) return null; + + const currentVersion = versionInfo?.version || "unknown"; + const hasReleaseNotes = releaseNotes?.exists && releaseNotes?.content; + + // Buy Me a Coffee SVG + const BuyMeACoffeeIcon = () => ( + + Buy Me a Coffee + + + ); + + return ( +
+
+ {/* Backdrop - lighter and more subtle */} + + )} +
+ + {/* Content - Step 1: Release Notes */} + {currentStep === 1 && ( +
+ {isLoading ? ( +
+
+
+ ) : hasReleaseNotes ? ( +
+ ( +

+ ), + h2: ({ node, ...props }) => ( +

+ ), + h3: ({ node, ...props }) => ( +

+ ), + p: ({ node, ...props }) => ( +

+ ), + ul: ({ node, ...props }) => ( +

    + ), + li: ({ node, ...props }) => ( +
  • + ), + strong: ({ node, ...props }) => ( + + ), + code: ({ node, ...props }) => ( + + ), + hr: ({ node, ...props }) => ( +
    + ), + }} + > + {releaseNotes.content} + +

+ ) : ( +
+

+ No release notes available for this version. +

+
+ )} +
+ )} + + {/* Content - Step 2: Founder's Note */} + {currentStep === 2 && ( +
+
+ {/* Personal note from founder */} +
+

+ A personal note from the founder Iby +

+
+

+ PatchMon wouldn't be what it is today without the + incredible support the community has shown over the last + 3 months. +

+

+ Your feedback and dedication on Discord has been keeping + me going - I love each and every one of you. +

+
+
+ +
+ {/* Support request - different for cloud vs self-hosted */} +
+

+ {isCloudVersion + ? "Upgrade Your PatchMon Cloud Experience" + : "Do you find PatchMon useful?"} +

+

+ {isCloudVersion + ? "Join as a member to unlock premium features like isolated resources, custom domains, priority support, and more. Help support the project while getting enhanced capabilities for your PatchMon Cloud instance." + : "Please consider supporting the project to keep the project OpenSource to help me maintain the infrastructure and develop new features."} +

+
+
+
+
+ )} +
+ + {/* Footer - Step 1: Next button */} + {currentStep === 1 && ( +
+ +
+ )} + + {/* Footer - Step 2: Support buttons (different for cloud vs self-hosted) */} + {currentStep === 2 && ( +
+
+ {/* Supporter/Member count - only show for self-hosted */} + {!isCloudVersion && + !isLoadingSupporters && + supporterData?.count !== undefined && ( +

+ + {supporterData.count} + {" "} + {supporterData.count === 1 ? "person has" : "people have"}{" "} + bought me a coffee so far! +

+ )} + {!isCloudVersion && isLoadingSupporters && ( +

+ Loading supporter count... +

+ )} + {/* Primary button - Membership for cloud, Donation for self-hosted */} + +
+
+ )} + + + + ); +}; + +export default ReleaseNotesModal; diff --git a/frontend/src/components/settings/AgentUpdatesTab.jsx b/frontend/src/components/settings/AgentUpdatesTab.jsx index 627b68d..01351cc 100644 --- a/frontend/src/components/settings/AgentUpdatesTab.jsx +++ b/frontend/src/components/settings/AgentUpdatesTab.jsx @@ -1,19 +1,15 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { AlertCircle, CheckCircle, Save, Shield, X } from "lucide-react"; import { useEffect, useId, useState } from "react"; -import { permissionsAPI, settingsAPI } from "../../utils/api"; +import { settingsAPI } from "../../utils/api"; const AgentUpdatesTab = () => { const updateIntervalId = useId(); const autoUpdateId = useId(); - const signupEnabledId = useId(); - const defaultRoleId = useId(); const ignoreSslId = useId(); const [formData, setFormData] = useState({ updateInterval: 60, autoUpdate: false, - signupEnabled: false, - defaultUserRole: "user", ignoreSslSelfSigned: false, }); const [errors, setErrors] = useState({}); @@ -82,20 +78,12 @@ const AgentUpdatesTab = () => { queryFn: () => settingsAPI.get().then((res) => res.data), }); - // Fetch available roles for default user role dropdown - const { data: roles, isLoading: rolesLoading } = useQuery({ - queryKey: ["rolePermissions"], - queryFn: () => permissionsAPI.getRoles().then((res) => res.data), - }); - // Update form data when settings are loaded useEffect(() => { if (settings) { const newFormData = { updateInterval: settings.update_interval || 60, autoUpdate: settings.auto_update || false, - signupEnabled: settings.signup_enabled === true, - defaultUserRole: settings.default_user_role || "user", ignoreSslSelfSigned: settings.ignore_ssl_self_signed === true, }; setFormData(newFormData); @@ -425,85 +413,6 @@ const AgentUpdatesTab = () => {

- {/* User Signup Setting */} -
- - - {/* Default User Role Dropdown */} - {formData.signupEnabled && ( -
- - -

- New users will be assigned this role when they register. -

-
- )} - -

- When enabled, users can create their own accounts through the signup - page. When disabled, only administrators can create user accounts. -

-
- - {/* Security Notice */} -
-
- -
-

- Security Notice -

-

- When enabling user self-registration, exercise caution on - internal networks. Consider restricting access to trusted - networks only and ensure proper role assignments to prevent - unauthorized access to sensitive systems. -

-
-
-
- {/* Save Button */}
+
+ + {updateSignupSettingsMutation.isSuccess && ( +
+
+ +
+

+ Settings saved successfully! +

+
+
+
+ )} + + ); }; diff --git a/frontend/src/components/settings/VersionUpdateTab.jsx b/frontend/src/components/settings/VersionUpdateTab.jsx index 6ed0ffb..cd8a2b6 100644 --- a/frontend/src/components/settings/VersionUpdateTab.jsx +++ b/frontend/src/components/settings/VersionUpdateTab.jsx @@ -1,3 +1,4 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { AlertCircle, CheckCircle, @@ -8,9 +9,30 @@ import { GitCommit, } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; -import { versionAPI } from "../../utils/api"; +import { settingsAPI, versionAPI } from "../../utils/api"; const VersionUpdateTab = () => { + const queryClient = useQueryClient(); + + // Fetch current settings + const { data: settings, isLoading: settingsLoading } = useQuery({ + queryKey: ["settings"], + queryFn: () => settingsAPI.get().then((res) => res.data), + }); + + // Update settings mutation + const updateSettingsMutation = useMutation({ + mutationFn: (data) => { + return settingsAPI.update(data).then((res) => res.data); + }, + onSuccess: () => { + queryClient.invalidateQueries(["settings"]); + }, + onError: (error) => { + console.error("Failed to update settings:", error); + }, + }); + // Version checking state const [versionInfo, setVersionInfo] = useState({ currentVersion: null, @@ -101,6 +123,50 @@ const VersionUpdateTab = () => { )}

+ {/* Toggle for showing GitHub version on login */} +
+
+
+ +

+ When enabled, the login screen will display the latest GitHub + release version and release notes information. +

+
+ +
+
+
{/* My Version */}
diff --git a/frontend/src/contexts/AuthContext.jsx b/frontend/src/contexts/AuthContext.jsx index 3cb6496..8e9807f 100644 --- a/frontend/src/contexts/AuthContext.jsx +++ b/frontend/src/contexts/AuthContext.jsx @@ -71,7 +71,12 @@ export const AuthProvider = ({ children }) => { if (storedToken && storedUser) { try { setToken(storedToken); - setUser(JSON.parse(storedUser)); + const parsedUser = JSON.parse(storedUser); + setUser({ + ...parsedUser, + accepted_release_notes_versions: + parsedUser.accepted_release_notes_versions || [], + }); // Fetch permissions from backend fetchPermissions(storedToken); // User is authenticated, skip setup check @@ -128,9 +133,20 @@ export const AuthProvider = ({ children }) => { // Regular successful login setToken(data.token); - setUser(data.user); + setUser({ + ...data.user, + accepted_release_notes_versions: + data.user.accepted_release_notes_versions || [], + }); localStorage.setItem("token", data.token); - localStorage.setItem("user", JSON.stringify(data.user)); + localStorage.setItem( + "user", + JSON.stringify({ + ...data.user, + accepted_release_notes_versions: + data.user.accepted_release_notes_versions || [], + }), + ); // Fetch user permissions after successful login const userPermissions = await fetchPermissions(data.token); @@ -237,8 +253,19 @@ export const AuthProvider = ({ children }) => { } // Update both state and localStorage atomically - setUser(data.user); - localStorage.setItem("user", JSON.stringify(data.user)); + setUser({ + ...data.user, + accepted_release_notes_versions: + data.user.accepted_release_notes_versions || [], + }); + localStorage.setItem( + "user", + JSON.stringify({ + ...data.user, + accepted_release_notes_versions: + data.user.accepted_release_notes_versions || [], + }), + ); return { success: true, user: data.user }; } else { @@ -349,6 +376,48 @@ export const AuthProvider = ({ children }) => { } }; + const acceptReleaseNotes = async (version) => { + try { + const response = await fetch("/api/v1/release-notes-acceptance/accept", { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ version }), + }); + + const data = await response.json(); + + if (response.ok) { + // Update user state immediately with new accepted version + const updatedAcceptedVersions = [ + ...(user?.accepted_release_notes_versions || []), + version, + ]; + + const updatedUser = { + ...user, + accepted_release_notes_versions: updatedAcceptedVersions, + }; + + // Update both state and localStorage atomically + setUser(updatedUser); + localStorage.setItem("user", JSON.stringify(updatedUser)); + + return { success: true }; + } else { + return { + success: false, + error: data.error || "Failed to accept release notes", + }; + } + } catch (error) { + console.error("Error accepting release notes:", error); + return { success: false, error: "Network error occurred" }; + } + }; + const isAdmin = () => { return user?.role === "admin"; }; @@ -411,14 +480,25 @@ export const AuthProvider = ({ children }) => { // Use flushSync to ensure all state updates are applied synchronously flushSync(() => { setToken(authToken); - setUser(authUser); + setUser({ + ...authUser, + accepted_release_notes_versions: + authUser.accepted_release_notes_versions || [], + }); setNeedsFirstTimeSetup(false); setAuthPhase(AUTH_PHASES.READY); }); // Store in localStorage after state is updated localStorage.setItem("token", authToken); - localStorage.setItem("user", JSON.stringify(authUser)); + localStorage.setItem( + "user", + JSON.stringify({ + ...authUser, + accepted_release_notes_versions: + authUser.accepted_release_notes_versions || [], + }), + ); // Fetch permissions immediately for the new authenticated user fetchPermissions(authToken); @@ -458,6 +538,7 @@ export const AuthProvider = ({ children }) => { canViewReports, canExportData, canManageSettings, + acceptReleaseNotes, }; return {children}; diff --git a/frontend/src/pages/Login.jsx b/frontend/src/pages/Login.jsx index 5eb00e4..7517382 100644 --- a/frontend/src/pages/Login.jsx +++ b/frontend/src/pages/Login.jsx @@ -49,6 +49,8 @@ const Login = () => { const [requiresTfa, setRequiresTfa] = useState(false); const [tfaUsername, setTfaUsername] = useState(""); const [signupEnabled, setSignupEnabled] = useState(false); + const [showGithubVersionOnLogin, setShowGithubVersionOnLogin] = + useState(true); const [latestRelease, setLatestRelease] = useState(null); const [githubStars, setGithubStars] = useState(null); const canvasRef = useRef(null); @@ -151,26 +153,35 @@ const Login = () => { return () => window.removeEventListener("resize", handleResize); }, [themeConfig]); - // Check if signup is enabled + // Check login settings (signup enabled and show github version) useEffect(() => { - const checkSignupEnabled = async () => { + const checkLoginSettings = async () => { try { - const response = await fetch("/api/v1/auth/signup-enabled"); + const response = await fetch("/api/v1/settings/login-settings"); if (response.ok) { const data = await response.json(); - setSignupEnabled(data.signupEnabled); + setSignupEnabled(data.signup_enabled || false); + setShowGithubVersionOnLogin( + data.show_github_version_on_login !== false, + ); } } catch (error) { - console.error("Failed to check signup status:", error); + console.error("Failed to check login settings:", error); // Default to disabled on error for security setSignupEnabled(false); + setShowGithubVersionOnLogin(true); // Default to showing on error } }; - checkSignupEnabled(); + checkLoginSettings(); }, []); // Fetch latest release and stars from GitHub useEffect(() => { + // Only fetch if the setting allows it + if (!showGithubVersionOnLogin) { + return; + } + const fetchGitHubData = async () => { try { // Try to get cached data first @@ -261,7 +272,7 @@ const Login = () => { }; fetchGitHubData(); - }, []); // Run once on mount + }, [showGithubVersionOnLogin]); // Run once on mount const handleSubmit = async (e) => { e.preventDefault(); @@ -449,209 +460,213 @@ const Login = () => {
- {/* Left side - Info Panel (hidden on mobile) */} -
-
-
-
-
- PatchMon -

- Linux Patch Monitoring -

-
+ {/* Left side - Info Panel (hidden on mobile or when GitHub version is disabled) */} + {showGithubVersionOnLogin && ( +
+
+
+
+
+ PatchMon +

+ Linux Patch Monitoring +

+
- {latestRelease ? ( -
-
-
-
- - Latest Release + {showGithubVersionOnLogin && latestRelease ? ( +
+
+
+
+ + Latest Release + +
+ + {latestRelease.version}
- - {latestRelease.version} - -
- {latestRelease.name && ( -

- {latestRelease.name} -

- )} + {latestRelease.name && ( +

+ {latestRelease.name} +

+ )} -
- + + Release date + + + Released {latestRelease.publishedAt} +
+ + {latestRelease.body && ( +

+ {latestRelease.body} +

+ )} + + - Release date - - - Released {latestRelease.publishedAt} + View Release Notes + + External link + + +
+ ) : showGithubVersionOnLogin ? ( +
+
+
+
+
+
+
+ ) : null} +
+
- {latestRelease.body && ( -

- {latestRelease.body} -

- )} - + {/* Social Links Footer */} +
+
+

Connect with us

+
+ {/* GitHub */} - View Release Notes - - External link - - + + {githubStars !== null && ( +
+ + + {githubStars} + +
+ )} +
+ + {/* Roadmap */} + + + + + {/* Docs */} + + + + + {/* Discord */} + + + + + {/* Email */} + + + + + {/* YouTube */} + + + + + {/* Reddit */} + + + + + {/* Website */} + +
- ) : ( -
-
-
-
-
-
-
- )} -
-
- - {/* Social Links Footer */} -
-
-

Connect with us

-
- {/* GitHub */} - - - {githubStars !== null && ( -
- - - {githubStars} - -
- )} -
- - {/* Roadmap */} - - - - - {/* Docs */} - - - - - {/* Discord */} - - - - - {/* Email */} - - - - - {/* YouTube */} - - - - - {/* Reddit */} - - - - - {/* Website */} - - -
-
+ )} {/* Right side - Login Form */} -
+
diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx index f59180c..654b0e4 100644 --- a/frontend/src/pages/Settings.jsx +++ b/frontend/src/pages/Settings.jsx @@ -18,12 +18,7 @@ import { import { useEffect, useId, useState } from "react"; import UpgradeNotificationIcon from "../components/UpgradeNotificationIcon"; import { useUpdateNotification } from "../contexts/UpdateNotificationContext"; -import { - agentFileAPI, - permissionsAPI, - settingsAPI, - versionAPI, -} from "../utils/api"; +import { agentFileAPI, settingsAPI, versionAPI } from "../utils/api"; const Settings = () => { const repoPublicId = useId(); @@ -33,7 +28,6 @@ const Settings = () => { const hostId = useId(); const portId = useId(); const updateIntervalId = useId(); - const defaultRoleId = useId(); const githubRepoUrlId = useId(); const sshKeyPathId = useId(); const _scriptFileId = useId(); @@ -44,8 +38,6 @@ const Settings = () => { serverPort: 3001, updateInterval: 60, autoUpdate: false, - signupEnabled: false, - defaultUserRole: "user", githubRepoUrl: "git@github.com:9technologygroup/patchmon.net.git", repositoryType: "public", sshKeyPath: "", @@ -175,12 +167,6 @@ const Settings = () => { return settings?.ignore_ssl_self_signed ? "-sk" : "-s"; }; - // Fetch available roles for default user role dropdown - const { data: roles, isLoading: rolesLoading } = useQuery({ - queryKey: ["rolePermissions"], - queryFn: () => permissionsAPI.getRoles().then((res) => res.data), - }); - // Update form data when settings are loaded useEffect(() => { if (settings) { @@ -190,9 +176,6 @@ const Settings = () => { serverPort: settings.server_port || 3001, updateInterval: settings.update_interval || 60, autoUpdate: settings.auto_update || false, - // biome-ignore lint/complexity/noUselessTernary: Seems to be desired given the comment - signupEnabled: settings.signup_enabled === true ? true : false, // Explicit boolean conversion - defaultUserRole: settings.default_user_role || "user", githubRepoUrl: settings.github_repo_url || "https://github.com/PatchMon/PatchMon.git", @@ -997,66 +980,6 @@ const Settings = () => {

- {/* User Signup Setting */} -
- - - {/* Default User Role Dropdown */} - {formData.signupEnabled && ( -
- - -

- New users will be assigned this role when they register. -

-
- )} - -

- When enabled, users can create their own accounts through the - signup page. When disabled, only administrators can create - user accounts. -

-
- {/* Security Notice */}
diff --git a/package-lock.json b/package-lock.json index 09a551d..5661d3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "patchmon", - "version": "1.3.6", + "version": "1.3.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "patchmon", - "version": "1.3.6", + "version": "1.3.7", "license": "AGPL-3.0", "workspaces": [ "backend", @@ -23,7 +23,7 @@ }, "backend": { "name": "patchmon-backend", - "version": "1.3.6", + "version": "1.3.7", "license": "AGPL-3.0", "dependencies": { "@bull-board/api": "^6.13.1", @@ -42,6 +42,7 @@ "ioredis": "^5.8.1", "jsonwebtoken": "^9.0.2", "moment": "^2.30.1", + "prisma": "^6.1.0", "qrcode": "^1.5.4", "speakeasy": "^2.0.0", "uuid": "^11.0.3", @@ -50,8 +51,7 @@ }, "devDependencies": { "@types/bcryptjs": "^2.4.6", - "nodemon": "^3.1.9", - "prisma": "^6.1.0" + "nodemon": "^3.1.9" }, "engines": { "node": ">=18.0.0" @@ -59,7 +59,7 @@ }, "frontend": { "name": "patchmon-frontend", - "version": "1.3.6", + "version": "1.3.7", "license": "AGPL-3.0", "dependencies": { "@dnd-kit/core": "^6.3.1", @@ -78,6 +78,7 @@ "react-chartjs-2": "^5.2.0", "react-dom": "^18.3.1", "react-icons": "^5.5.0", + "react-markdown": "^9.0.1", "react-router-dom": "^6.30.1" }, "devDependencies": { @@ -612,8 +613,282 @@ "react": ">=16.8.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.10", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -627,6 +902,159 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@ioredis/commands": { "version": "1.4.0", "license": "MIT" @@ -838,7 +1266,6 @@ }, "node_modules/@prisma/config": { "version": "6.16.2", - "devOptional": true, "license": "Apache-2.0", "dependencies": { "c12": "3.1.0", @@ -849,12 +1276,10 @@ }, "node_modules/@prisma/debug": { "version": "6.16.2", - "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/engines": { "version": "6.16.2", - "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -866,12 +1291,10 @@ }, "node_modules/@prisma/engines-version": { "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43", - "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { "version": "6.16.2", - "devOptional": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "6.16.2", @@ -881,7 +1304,6 @@ }, "node_modules/@prisma/get-platform": { "version": "6.16.2", - "devOptional": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "6.16.2" @@ -925,7 +1347,6 @@ }, "node_modules/@standard-schema/spec": { "version": "1.0.0", - "devOptional": true, "license": "MIT" }, "node_modules/@tanstack/query-core": { @@ -992,11 +1413,37 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", - "dev": true, "license": "MIT" }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/http-proxy": { "version": "1.17.16", "license": "MIT", @@ -1004,6 +1451,21 @@ "@types/node": "*" } }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "24.6.0", "license": "MIT", @@ -1013,12 +1475,10 @@ }, "node_modules/@types/prop-types": { "version": "15.7.15", - "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.24", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -1037,6 +1497,18 @@ "version": "1.3.5", "license": "MIT" }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "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==", + "license": "ISC" + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "dev": true, @@ -1166,6 +1638,16 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "license": "MIT" @@ -1317,7 +1799,6 @@ }, "node_modules/c12": { "version": "3.1.0", - "devOptional": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.3", @@ -1344,7 +1825,6 @@ }, "node_modules/c12/node_modules/chokidar": { "version": "4.0.3", - "devOptional": true, "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -1358,7 +1838,6 @@ }, "node_modules/c12/node_modules/readdirp": { "version": "4.1.2", - "devOptional": true, "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -1427,6 +1906,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -1453,6 +1942,46 @@ "node": ">=8" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chart.js": { "version": "4.5.0", "license": "MIT", @@ -1488,7 +2017,6 @@ }, "node_modules/citty": { "version": "0.1.6", - "devOptional": true, "license": "MIT", "dependencies": { "consola": "^3.2.3" @@ -1580,6 +2108,16 @@ "node": ">= 0.8" } }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "4.1.1", "dev": true, @@ -1621,12 +2159,10 @@ }, "node_modules/confbox": { "version": "0.2.2", - "devOptional": true, "license": "MIT" }, "node_modules/consola": { "version": "3.4.2", - "devOptional": true, "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" @@ -1730,7 +2266,6 @@ }, "node_modules/csstype": { "version": "3.1.3", - "dev": true, "license": "MIT" }, "node_modules/date-fns": { @@ -1770,9 +2305,21 @@ "node": ">=0.10.0" } }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/deepmerge-ts": { "version": "7.1.5", - "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=16.0.0" @@ -1780,7 +2327,6 @@ }, "node_modules/defu": { "version": "6.1.4", - "devOptional": true, "license": "MIT" }, "node_modules/delayed-stream": { @@ -1804,9 +2350,17 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/destr": { "version": "2.0.5", - "devOptional": true, "license": "MIT" }, "node_modules/destroy": { @@ -1825,6 +2379,19 @@ "node": ">=8" } }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "dev": true, @@ -1879,7 +2446,6 @@ }, "node_modules/effect": { "version": "3.16.12", - "devOptional": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -1910,7 +2476,6 @@ }, "node_modules/empathic": { "version": "2.0.0", - "devOptional": true, "license": "MIT", "engines": { "node": ">=14" @@ -1965,7 +2530,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.10", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1976,32 +2543,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.10", - "@esbuild/android-arm": "0.25.10", - "@esbuild/android-arm64": "0.25.10", - "@esbuild/android-x64": "0.25.10", - "@esbuild/darwin-arm64": "0.25.10", - "@esbuild/darwin-x64": "0.25.10", - "@esbuild/freebsd-arm64": "0.25.10", - "@esbuild/freebsd-x64": "0.25.10", - "@esbuild/linux-arm": "0.25.10", - "@esbuild/linux-arm64": "0.25.10", - "@esbuild/linux-ia32": "0.25.10", - "@esbuild/linux-loong64": "0.25.10", - "@esbuild/linux-mips64el": "0.25.10", - "@esbuild/linux-ppc64": "0.25.10", - "@esbuild/linux-riscv64": "0.25.10", - "@esbuild/linux-s390x": "0.25.10", - "@esbuild/linux-x64": "0.25.10", - "@esbuild/netbsd-arm64": "0.25.10", - "@esbuild/netbsd-x64": "0.25.10", - "@esbuild/openbsd-arm64": "0.25.10", - "@esbuild/openbsd-x64": "0.25.10", - "@esbuild/openharmony-arm64": "0.25.10", - "@esbuild/sunos-x64": "0.25.10", - "@esbuild/win32-arm64": "0.25.10", - "@esbuild/win32-ia32": "0.25.10", - "@esbuild/win32-x64": "0.25.10" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escalade": { @@ -2016,6 +2583,16 @@ "version": "1.0.3", "license": "MIT" }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/etag": { "version": "1.8.1", "license": "MIT", @@ -2108,12 +2685,16 @@ }, "node_modules/exsolve": { "version": "1.0.7", - "devOptional": true, + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, "node_modules/fast-check": { "version": "3.23.2", - "devOptional": true, "funding": [ { "type": "individual", @@ -2308,6 +2889,21 @@ "node": ">= 0.6" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "license": "MIT", @@ -2365,7 +2961,6 @@ }, "node_modules/giget": { "version": "2.0.0", - "devOptional": true, "license": "MIT", "dependencies": { "citty": "^0.1.6", @@ -2380,7 +2975,9 @@ } }, "node_modules/glob": { - "version": "10.4.5", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -2482,6 +3079,46 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/helmet": { "version": "8.1.0", "license": "MIT", @@ -2489,6 +3126,16 @@ "node": ">=18.0.0" } }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/http-errors": { "version": "2.0.0", "license": "MIT", @@ -2549,6 +3196,12 @@ "version": "2.0.4", "license": "ISC" }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, "node_modules/ioredis": { "version": "5.8.1", "license": "MIT", @@ -2578,6 +3231,30 @@ "node": ">= 0.10" } }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-arrayish": { "version": "0.3.4", "license": "MIT" @@ -2607,6 +3284,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "license": "MIT", @@ -2631,6 +3318,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-number": { "version": "7.0.0", "license": "MIT", @@ -2638,6 +3335,18 @@ "node": ">=0.12.0" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-object": { "version": "5.0.0", "license": "MIT", @@ -2691,7 +3400,6 @@ }, "node_modules/jiti": { "version": "2.6.0", - "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -2888,6 +3596,16 @@ "node": ">= 12.0.0" } }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "license": "MIT", @@ -2927,6 +3645,159 @@ "node": ">= 0.4" } }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/media-typer": { "version": "0.3.0", "license": "MIT", @@ -2956,6 +3827,448 @@ "node": ">= 0.6" } }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "license": "MIT", @@ -3091,7 +4404,6 @@ }, "node_modules/node-fetch-native": { "version": "1.6.7", - "devOptional": true, "license": "MIT" }, "node_modules/node-gyp-build-optional-packages": { @@ -3187,7 +4499,6 @@ }, "node_modules/nypm": { "version": "0.6.2", - "devOptional": true, "license": "MIT", "dependencies": { "citty": "^0.1.6", @@ -3230,7 +4541,6 @@ }, "node_modules/ohash": { "version": "2.0.11", - "devOptional": true, "license": "MIT" }, "node_modules/on-finished": { @@ -3285,6 +4595,31 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, "node_modules/parseurl": { "version": "1.3.3", "license": "MIT", @@ -3346,12 +4681,10 @@ }, "node_modules/pathe": { "version": "2.0.3", - "devOptional": true, "license": "MIT" }, "node_modules/perfect-debounce": { "version": "1.0.0", - "devOptional": true, "license": "MIT" }, "node_modules/picocolors": { @@ -3386,7 +4719,6 @@ }, "node_modules/pkg-types": { "version": "2.3.0", - "devOptional": true, "license": "MIT", "dependencies": { "confbox": "^0.2.2", @@ -3545,7 +4877,6 @@ }, "node_modules/prisma": { "version": "6.16.2", - "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -3567,6 +4898,16 @@ } } }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "license": "MIT", @@ -3589,7 +4930,6 @@ }, "node_modules/pure-rand": { "version": "6.1.0", - "devOptional": true, "funding": [ { "type": "individual", @@ -3727,7 +5067,6 @@ }, "node_modules/rc9": { "version": "2.1.2", - "devOptional": true, "license": "MIT", "dependencies": { "defu": "^6.1.4", @@ -3770,6 +5109,33 @@ "react": "*" } }, + "node_modules/react-markdown": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.1.0.tgz", + "integrity": "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, "node_modules/react-refresh": { "version": "0.17.0", "dev": true, @@ -3861,6 +5227,39 @@ "node": ">=4" } }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/require-directory": { "version": "2.1.1", "license": "MIT", @@ -4221,6 +5620,16 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/spawn-command": { "version": "0.0.2", "dev": true @@ -4286,6 +5695,20 @@ "node": ">=8" } }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "license": "MIT", @@ -4308,6 +5731,24 @@ "node": ">=8" } }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, "node_modules/sucrase": { "version": "3.35.0", "dev": true, @@ -4434,7 +5875,6 @@ }, "node_modules/tinyexec": { "version": "1.0.1", - "devOptional": true, "license": "MIT" }, "node_modules/tinyglobby": { @@ -4512,6 +5952,16 @@ "tree-kill": "cli.js" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/triple-beam": { "version": "1.4.1", "license": "MIT", @@ -4519,6 +5969,16 @@ "node": ">= 14.0.0" } }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "dev": true, @@ -4548,6 +6008,93 @@ "version": "7.13.0", "license": "MIT" }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unpipe": { "version": "1.0.0", "license": "MIT", @@ -4620,12 +6167,42 @@ "node": ">= 0.8" } }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { - "version": "7.1.7", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", + "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", + "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", @@ -4870,6 +6447,16 @@ "engines": { "node": ">=12" } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } }