From 61311386feaa906fb7c4465b24ee22ce6291d825 Mon Sep 17 00:00:00 2001
From: Val <44112412+LawfaL@users.noreply.github.com>
Date: Mon, 7 Jul 2025 18:21:02 +0700
Subject: [PATCH] feat: seo checker
---
app/api/seo-check/route.js | 488 +++++++
app/seo-checker/page.js | 28 +
app/services-details/page.js | 2 +-
app/services/ad-campaign-management/page.js | 2 +-
app/services/cloud-computing/page.js | 2 +-
app/services/cyber-security/page.js | 2 +-
app/services/lead-generation/page.js | 2 +-
app/services/performance-monitoring/page.js | 2 +-
.../search-engine-optimization/page.js | 2 +-
app/services/social-media-management/page.js | 2 +-
app/services/web-development/page.js | 2 +-
app/services/website-maintenance/page.js | 2 +-
components/layout/Menu.js | 2 +-
components/seoChecker.js | 719 +++++++++++
package-lock.json | 1125 ++++++++++++++++-
package.json | 6 +-
16 files changed, 2347 insertions(+), 41 deletions(-)
create mode 100644 app/api/seo-check/route.js
create mode 100644 app/seo-checker/page.js
create mode 100644 components/seoChecker.js
diff --git a/app/api/seo-check/route.js b/app/api/seo-check/route.js
new file mode 100644
index 0000000..591209d
--- /dev/null
+++ b/app/api/seo-check/route.js
@@ -0,0 +1,488 @@
+// app/api/seo-check/route.js
+import { NextResponse } from "next/server";
+import * as cheerio from "cheerio";
+
+export async function POST(request) {
+ const startTime = Date.now();
+
+ try {
+ // Validate request
+ let url;
+ try {
+ const body = await request.json();
+ url = body?.url;
+ if (!url) throw new Error("URL is required");
+ } catch (e) {
+ return NextResponse.json(
+ { error: "Invalid request format" },
+ { status: 400 }
+ );
+ }
+
+ // Validate URL format
+ let parsedUrl;
+ try {
+ parsedUrl = new URL(url);
+ if (!["http:", "https:"].includes(parsedUrl.protocol)) {
+ throw new Error("Invalid protocol");
+ }
+ } catch (e) {
+ return NextResponse.json(
+ { error: "Please provide a valid HTTP/HTTPS URL" },
+ { status: 400 }
+ );
+ }
+
+ // Fetch HTML with enhanced configuration
+ const controller = new AbortController();
+ const timeout = setTimeout(() => controller.abort(), 15000);
+
+ let response;
+ try {
+ response = await fetch(url, {
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (compatible; SEO-Analyzer/1.0; +https://github.com)",
+ Accept: "text/html,application/xhtml+xml",
+ },
+ redirect: "follow",
+ signal: controller.signal,
+ });
+ clearTimeout(timeout);
+ } catch (e) {
+ return NextResponse.json(
+ {
+ error:
+ e.name === "AbortError"
+ ? "Request timed out"
+ : `Fetch failed: ${e.message}`,
+ },
+ { status: 400 }
+ );
+ }
+
+ // Verify response
+ if (!response.ok) {
+ return NextResponse.json(
+ {
+ error: `HTTP ${response.status}`,
+ status: response.status,
+ url: response.url,
+ },
+ { status: 400 }
+ );
+ }
+
+ const contentType = response.headers.get("content-type");
+ if (!contentType?.includes("text/html")) {
+ return NextResponse.json(
+ { error: "URL does not return HTML content" },
+ { status: 400 }
+ );
+ }
+
+ // Parse HTML
+ const html = await response.text();
+ const finalUrl = response.url;
+ let $;
+ try {
+ $ = cheerio.load(html);
+ } catch (e) {
+ return NextResponse.json(
+ { error: "Failed to parse HTML content" },
+ { status: 500 }
+ );
+ }
+
+ // Extract security headers
+ const securityHeaders = {
+ https: finalUrl.startsWith("https://"),
+ xFrameOptions: response.headers.get("x-frame-options"),
+ xXSSProtection: response.headers.get("x-xss-protection"),
+ contentTypeOptions: response.headers.get("x-content-type-options"),
+ strictTransportSecurity: response.headers.get(
+ "strict-transport-security"
+ ),
+ };
+
+ // Add this new function to analyze charset
+ function analyzeCharset($) {
+ const charsetMeta = $("meta[charset]");
+ if (charsetMeta.length > 0) {
+ return {
+ exists: true,
+ value: charsetMeta.attr("charset")?.toUpperCase() || "UTF-8",
+ declaredInMeta: true,
+ };
+ }
+
+ const httpEquiv = $('meta[http-equiv="Content-Type"]');
+ if (httpEquiv.length > 0) {
+ const content = httpEquiv.attr("content") || "";
+ const charsetMatch = content.match(/charset=([^;]+)/i);
+ if (charsetMatch) {
+ return {
+ exists: true,
+ value: charsetMatch[1].toUpperCase(),
+ declaredInMeta: true,
+ };
+ }
+ }
+
+ return {
+ exists: false,
+ value: null,
+ declaredInMeta: false,
+ };
+ }
+
+ // Title Tag Analysis
+ function analyzeTitle($) {
+ const title = $("title").first().text().trim();
+ return {
+ exists: title.length > 0,
+ text: title,
+ length: title.length,
+ status:
+ title.length >= 30 && title.length <= 60
+ ? "optimal"
+ : title.length < 30
+ ? "too_short"
+ : "too_long",
+ };
+ }
+
+ // Meta Description Analysis
+ function analyzeMetaDescription($) {
+ const desc = $('meta[name="description"]').attr("content") || "";
+ return {
+ exists: desc.length > 0,
+ text: desc,
+ length: desc.length,
+ status:
+ desc.length >= 50 && desc.length <= 160
+ ? "optimal"
+ : desc.length < 50
+ ? "too_short"
+ : "too_long",
+ };
+ }
+
+ // Meta Robots Analysis
+ function analyzeMetaRobots($) {
+ const content = $('meta[name="robots"]').attr("content") || "";
+ return {
+ exists: content.length > 0,
+ content,
+ noindex: content.includes("noindex"),
+ nofollow: content.includes("nofollow"),
+ };
+ }
+
+ // Viewport Analysis
+ function analyzeViewport($) {
+ const viewport = $('meta[name="viewport"]').attr("content") || "";
+ return {
+ exists: viewport.length > 0,
+ content: viewport,
+ mobileFriendly: viewport.includes("width=device-width"),
+ };
+ }
+
+ // Text Analysis Functions
+ function calculateReadabilityScore(text) {
+ // Simple readability score calculation (Flesch-Kincaid approximation)
+ const words = text
+ .trim()
+ .split(/\s+/)
+ .filter((word) => word.length > 0);
+ const sentences = text.split(/[.!?]+/).filter((s) => s.trim().length > 0);
+ const syllables = words.reduce(
+ (count, word) => count + countSyllables(word),
+ 0
+ );
+
+ if (words.length === 0 || sentences.length === 0) return 0;
+
+ const wordsPerSentence = words.length / sentences.length;
+ const syllablesPerWord = syllables / words.length;
+
+ // Flesch Reading Ease Score
+ const score =
+ 206.835 - 1.015 * wordsPerSentence - 84.6 * syllablesPerWord;
+
+ // Normalize to 0-100 scale
+ return Math.max(0, Math.min(100, Math.round(score)));
+ }
+
+ function countSyllables(word) {
+ // Simple syllable counting approximation
+ word = word.toLowerCase().replace(/[^a-z]/g, "");
+ if (word.length <= 3) return 1;
+
+ let syllables = word.replace(/[^aeiouy]/g, "").length;
+ syllables -= word.match(/e$/) ? 1 : 0; // Silent e
+ syllables -= word.match(/[aeiouy]{2,}/g)?.length || 0; // Diphthongs
+ return Math.max(1, syllables);
+ }
+
+ // Content Analysis
+ function analyzeContent($) {
+ const bodyText = $("body").text();
+ const words = bodyText
+ .trim()
+ .split(/\s+/)
+ .filter((word) => word.length > 0);
+
+ return {
+ wordCount: words.length,
+ textLength: bodyText.length,
+ readability: calculateReadabilityScore(bodyText),
+ paragraphCount: $("p").length,
+ listCount: $("ul, ol").length,
+ };
+ }
+
+ // Perform comprehensive analysis
+ const analysis = {
+ url: finalUrl,
+ pageLoadTime: (Date.now() - startTime) / 1000,
+ title: analyzeTitle($),
+ meta: {
+ description: analyzeMetaDescription($),
+ robots: analyzeMetaRobots($),
+ viewport: analyzeViewport($),
+ charset: analyzeCharset($),
+ keywords: $('meta[name="keywords"]').attr("content") || null,
+ },
+ headings: analyzeHeadings($),
+ images: analyzeImages($),
+ links: analyzeLinks($, finalUrl),
+ content: analyzeContent($),
+ technical: {
+ canonical: analyzeCanonical($),
+ language: analyzeLanguage($),
+ schemaMarkup: analyzeSchemaMarkup($),
+ doctype: analyzeDoctype($),
+ },
+ social: {
+ openGraph: analyzeOpenGraph($),
+ twitterCard: analyzeTwitterCards($),
+ },
+ security: securityHeaders,
+ analyzedAt: new Date().toISOString(),
+ };
+
+ return NextResponse.json(analysis);
+ } catch (error) {
+ console.error("SEO analysis error:", error);
+ return NextResponse.json(
+ {
+ error: "Internal server error during analysis",
+ details:
+ process.env.NODE_ENV === "development" ? error.stack : undefined,
+ },
+ { status: 500 }
+ );
+ }
+}
+
+// Analysis Functions
+function analyzeTitle($) {
+ const title = $("title").first().text().trim();
+ return {
+ exists: title.length > 0,
+ text: title,
+ length: title.length,
+ status:
+ title.length >= 30 && title.length <= 60
+ ? "optimal"
+ : title.length < 30
+ ? "too_short"
+ : "too_long",
+ };
+}
+
+function analyzeMetaDescription($) {
+ const desc = $('meta[name="description"]').attr("content") || "";
+ return {
+ exists: desc.length > 0,
+ text: desc,
+ length: desc.length,
+ status:
+ desc.length >= 50 && desc.length <= 160
+ ? "optimal"
+ : desc.length < 50
+ ? "too_short"
+ : "too_long",
+ };
+}
+
+function analyzeMetaRobots($) {
+ const content = $('meta[name="robots"]').attr("content") || "";
+ return {
+ exists: content.length > 0,
+ content,
+ noindex: content.includes("noindex"),
+ nofollow: content.includes("nofollow"),
+ };
+}
+
+function analyzeViewport($) {
+ const viewport = $('meta[name="viewport"]').attr("content") || "";
+ return {
+ exists: viewport.length > 0,
+ content: viewport,
+ mobileFriendly: viewport.includes("width=device-width"),
+ };
+}
+
+function analyzeHeadings($) {
+ return {
+ h1: {
+ count: $("h1").length,
+ texts: $("h1")
+ .map((i, el) => $(el).text().trim())
+ .get(),
+ },
+ h2: {
+ count: $("h2").length,
+ texts: $("h2")
+ .map((i, el) => $(el).text().trim())
+ .get(),
+ },
+ h3: {
+ count: $("h3").length,
+ texts: $("h3")
+ .map((i, el) => $(el).text().trim())
+ .get(),
+ },
+ };
+}
+
+function analyzeImages($) {
+ const images = $("img");
+ const withAlt = images.filter((i, el) => {
+ const alt = $(el).attr("alt");
+ return alt && alt.trim() !== "";
+ }).length;
+
+ return {
+ total: images.length,
+ withAlt,
+ withoutAlt: images.length - withAlt,
+ percentageWithAlt:
+ images.length > 0 ? Math.round((withAlt / images.length) * 100) : 100,
+ };
+}
+
+function analyzeLinks($, baseUrl) {
+ const links = $("a[href]");
+ let internal = 0;
+ let external = 0;
+ let nofollow = 0;
+
+ try {
+ const baseDomain = new URL(baseUrl).hostname.replace("www.", "");
+
+ links.each((i, el) => {
+ const href = $(el).attr("href");
+ const rel = $(el).attr("rel") || "";
+
+ if (rel.includes("nofollow")) nofollow++;
+
+ try {
+ const url = new URL(href, baseUrl);
+ if (url.hostname.replace("www.", "") === baseDomain) {
+ internal++;
+ } else {
+ external++;
+ }
+ } catch {
+ internal++; // Relative links
+ }
+ });
+ } catch (e) {
+ console.error("Link analysis error:", e);
+ }
+
+ return {
+ total: links.length,
+ internal,
+ external,
+ nofollow,
+ nofollowPercentage:
+ links.length > 0 ? Math.round((nofollow / links.length) * 100) : 0,
+ };
+}
+
+function analyzeContent($) {
+ const bodyText = $("body").text();
+ const words = bodyText
+ .trim()
+ .split(/\s+/)
+ .filter((word) => word.length > 0);
+
+ return {
+ wordCount: words.length,
+ textLength: bodyText.length,
+ readability: calculateReadabilityScore(words), // Implement your own formula
+ };
+}
+
+function analyzeCanonical($) {
+ const canonical = $('link[rel="canonical"]').attr("href") || "";
+ return {
+ exists: canonical.length > 0,
+ url: canonical,
+ isSelf: canonical === $('meta[property="og:url"]').attr("content"),
+ };
+}
+
+function analyzeSchemaMarkup($) {
+ const schemas = $('script[type="application/ld+json"]');
+ const types = [];
+
+ schemas.each((i, el) => {
+ try {
+ const json = JSON.parse($(el).text());
+ if (json["@type"]) types.push(json["@type"]);
+ } catch (e) {
+ console.error("Schema parsing error:", e);
+ }
+ });
+
+ return {
+ count: schemas.length,
+ types: [...new Set(types)], // Unique types only
+ };
+}
+
+function analyzeOpenGraph($) {
+ return {
+ title: $('meta[property="og:title"]').attr("content") || "",
+ description: $('meta[property="og:description"]').attr("content") || "",
+ image: $('meta[property="og:image"]').attr("content") || "",
+ url: $('meta[property="og:url"]').attr("content") || "",
+ };
+}
+
+function analyzeTwitterCards($) {
+ return {
+ card: $('meta[name="twitter:card"]').attr("content") || "",
+ title: $('meta[name="twitter:title"]').attr("content") || "",
+ description: $('meta[name="twitter:description"]').attr("content") || "",
+ image: $('meta[name="twitter:image"]').attr("content") || "",
+ };
+}
+
+function analyzeLanguage($) {
+ return $("html").attr("lang") || null;
+}
+
+function analyzeDoctype($) {
+ const doctype = $("html")[0]?.prev?.data;
+ return doctype?.includes("
+
+
+
+ SEO Analyzer
+
+
+ Get a comprehensive SEO report for any webpage
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/services-details/page.js b/app/services-details/page.js
index 55c596f..4cbf16d 100644
--- a/app/services-details/page.js
+++ b/app/services-details/page.js
@@ -200,7 +200,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/ad-campaign-management/page.js b/app/services/ad-campaign-management/page.js
index 9b2d9c6..84f008d 100644
--- a/app/services/ad-campaign-management/page.js
+++ b/app/services/ad-campaign-management/page.js
@@ -229,7 +229,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/cloud-computing/page.js b/app/services/cloud-computing/page.js
index 895d5a6..8355c11 100644
--- a/app/services/cloud-computing/page.js
+++ b/app/services/cloud-computing/page.js
@@ -261,7 +261,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/cyber-security/page.js b/app/services/cyber-security/page.js
index 242f706..aeba9b9 100644
--- a/app/services/cyber-security/page.js
+++ b/app/services/cyber-security/page.js
@@ -230,7 +230,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/lead-generation/page.js b/app/services/lead-generation/page.js
index 525a141..7c34fca 100644
--- a/app/services/lead-generation/page.js
+++ b/app/services/lead-generation/page.js
@@ -228,7 +228,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/performance-monitoring/page.js b/app/services/performance-monitoring/page.js
index c56a3c0..d5890e0 100644
--- a/app/services/performance-monitoring/page.js
+++ b/app/services/performance-monitoring/page.js
@@ -236,7 +236,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/search-engine-optimization/page.js b/app/services/search-engine-optimization/page.js
index be0a96c..952b4cb 100644
--- a/app/services/search-engine-optimization/page.js
+++ b/app/services/search-engine-optimization/page.js
@@ -235,7 +235,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/social-media-management/page.js b/app/services/social-media-management/page.js
index e6098b6..12f98a9 100644
--- a/app/services/social-media-management/page.js
+++ b/app/services/social-media-management/page.js
@@ -230,7 +230,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/web-development/page.js b/app/services/web-development/page.js
index cc75989..fa0516d 100644
--- a/app/services/web-development/page.js
+++ b/app/services/web-development/page.js
@@ -232,7 +232,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/app/services/website-maintenance/page.js b/app/services/website-maintenance/page.js
index 458840b..e889490 100644
--- a/app/services/website-maintenance/page.js
+++ b/app/services/website-maintenance/page.js
@@ -276,7 +276,7 @@ export default function ServicesDetails3() {
SEO Checker
Check your website's SEO performance.
-
SEO Checker
+
SEO Checker
diff --git a/components/layout/Menu.js b/components/layout/Menu.js
index aab6f85..78e76e5 100644
--- a/components/layout/Menu.js
+++ b/components/layout/Menu.js
@@ -55,7 +55,7 @@ export default function Menu() {
*/}
- SEO checker
+ SEO checker
diff --git a/components/seoChecker.js b/components/seoChecker.js
new file mode 100644
index 0000000..b439244
--- /dev/null
+++ b/components/seoChecker.js
@@ -0,0 +1,719 @@
+"use client";
+import { useState } from "react";
+import {
+ FiCheckCircle,
+ FiAlertTriangle,
+ FiInfo,
+ FiDownload,
+ FiExternalLink,
+} from "react-icons/fi";
+
+const SEOChecker = () => {
+ const [url, setUrl] = useState("");
+ const [seoData, setSeoData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const [activeTab, setActiveTab] = useState("summary");
+
+ const checkSEO = async () => {
+ if (!url) {
+ setError("Please enter a URL");
+ return;
+ }
+
+ setLoading(true);
+ setError(null);
+ setSeoData(null);
+
+ try {
+ const response = await fetch("/api/seo-check", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ url }),
+ });
+
+ if (!response.ok) {
+ const errorData = await response.json();
+ throw new Error(errorData.error || "Failed to analyze URL");
+ }
+
+ const data = await response.json();
+ setSeoData(data);
+ setActiveTab("summary");
+ } catch (err) {
+ setError(err.message || "Failed to check SEO");
+ console.error("SEO check error:", err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const calculateScores = (data) => {
+ if (!data) return { score: 0, deductions: [], categoryScores: {} };
+
+ let score = 100;
+ const deductions = [];
+
+ // Title (15 points)
+ if (!data.title.exists) {
+ score -= 15;
+ deductions.push({
+ item: "Title Tag",
+ points: -15,
+ message: "Missing completely",
+ });
+ } else {
+ if (data.title.text.length < 30) {
+ score -= 7;
+ deductions.push({
+ item: "Title Length",
+ points: -7,
+ message: "Too short (under 30 chars)",
+ });
+ } else if (data.title.text.length > 60) {
+ score -= 5;
+ deductions.push({
+ item: "Title Length",
+ points: -5,
+ message: "Too long (over 60 chars)",
+ });
+ }
+ }
+
+ // Meta Description (10 points)
+ if (!data.meta.description.exists) {
+ score -= 10;
+ deductions.push({
+ item: "Meta Description",
+ points: -10,
+ message: "Missing completely",
+ });
+ } else {
+ if (data.meta.description.text.length < 50) {
+ score -= 5;
+ deductions.push({
+ item: "Meta Description",
+ points: -5,
+ message: "Too short (under 50 chars)",
+ });
+ } else if (data.meta.description.text.length > 160) {
+ score -= 3;
+ deductions.push({
+ item: "Meta Description",
+ points: -3,
+ message: "Too long (over 160 chars)",
+ });
+ }
+ }
+
+ // Headings (15 points)
+ if (data.headings.h1.count === 0) {
+ score -= 10;
+ deductions.push({
+ item: "H1 Heading",
+ points: -10,
+ message: "Missing H1 tag",
+ });
+ } else if (data.headings.h1.count > 1) {
+ score -= 7;
+ deductions.push({
+ item: "H1 Heading",
+ points: -7,
+ message: "Multiple H1 tags",
+ });
+ }
+
+ if (data.headings.h2.count < 2) {
+ score -= 3;
+ deductions.push({
+ item: "H2 Headings",
+ points: -3,
+ message: "Not enough H2 tags",
+ });
+ }
+
+ // Images (10 points)
+ if (data.images?.withoutAlt > 0) {
+ const deduction = Math.min(10, data.images.withoutAlt * 2);
+ score -= deduction;
+ deductions.push({
+ item: "Image Alt Tags",
+ points: -deduction,
+ message: `${data.images.withoutAlt} images missing alt text`,
+ });
+ }
+
+ // Links (10 points)
+ if (data.links?.internal < 5) {
+ score -= 5;
+ deductions.push({
+ item: "Internal Links",
+ points: -5,
+ message: "Few internal links",
+ });
+ }
+
+ if (data.links?.external === 0) {
+ score -= 2;
+ deductions.push({
+ item: "External Links",
+ points: -2,
+ message: "No external links",
+ });
+ }
+
+ // Mobile (10 points)
+ if (!data.meta?.viewport?.mobileFriendly) {
+ score -= 10;
+ deductions.push({
+ item: "Mobile Friendly",
+ points: -10,
+ message: "No responsive viewport",
+ });
+ }
+
+ // Performance (10 points)
+ if (data.pageLoadTime > 3) {
+ const deduction = Math.min(10, Math.floor(data.pageLoadTime - 2) * 2);
+ score -= deduction;
+ deductions.push({
+ item: "Page Speed",
+ points: -deduction,
+ message: `Slow load time (${data.pageLoadTime}s)`,
+ });
+ }
+
+ // Technical SEO (20 points)
+ if (!data.technical?.canonical?.exists) {
+ score -= 5;
+ deductions.push({
+ item: "Canonical URL",
+ points: -5,
+ message: "Missing canonical tag",
+ });
+ }
+
+ if (!data.security?.https) {
+ score -= 5;
+ deductions.push({
+ item: "HTTPS",
+ points: -5,
+ message: "Not using HTTPS",
+ });
+ }
+
+ if (data.technical?.schemaMarkup?.count === 0) {
+ score -= 5;
+ deductions.push({
+ item: "Schema Markup",
+ points: -5,
+ message: "Missing structured data",
+ });
+ }
+
+ if (!data.meta?.robots?.content) {
+ score -= 5;
+ deductions.push({
+ item: "Robots Meta",
+ points: -5,
+ message: "Missing robots meta tag",
+ });
+ }
+
+ // Calculate category scores
+ const categoryScores = {
+ onPage: calculateOnPageScore(data),
+ technical: calculateTechnicalScore(data),
+ content: calculateContentScore(data),
+ mobile: calculateMobileScore(data),
+ };
+
+ return {
+ score: Math.max(0, Math.round(score)),
+ deductions,
+ categoryScores,
+ };
+ };
+
+ const calculateOnPageScore = (data) => {
+ let score = 30;
+ if (!data.title.exists) score -= 15;
+ if (!data.meta.description.exists) score -= 10;
+ if (data.headings.h1.count !== 1) score -= 5;
+ return Math.max(0, score);
+ };
+
+ const calculateTechnicalScore = (data) => {
+ let score = 30;
+ if (!data.technical.canonical.exists) score -= 5;
+ if (!data.security.https) score -= 5;
+ if (data.technical.schemaMarkup.count === 0) score -= 5;
+ if (!data.meta.robots.content) score -= 5;
+ return Math.max(0, score);
+ };
+
+ const calculateContentScore = (data) => {
+ let score = 20;
+ if (data.content.wordCount < 300) score -= 5;
+ if (data.content.readability < 60) score -= 5;
+ if (data.images.withoutAlt > 0) score -= 5;
+ return Math.max(0, score);
+ };
+
+ const calculateMobileScore = (data) => {
+ let score = 20;
+ if (!data.meta.viewport.mobileFriendly) score -= 10;
+ if (data.pageLoadTime > 3) score -= 5;
+ return Math.max(0, score);
+ };
+
+ const renderReportSection = () => {
+ if (!seoData) return null;
+
+ const { score, deductions, categoryScores } = calculateScores(seoData);
+
+ switch (activeTab) {
+ case "summary":
+ return (
+
+
+
+
+
+
+
+
+
+
+ Key Recommendations
+
+
+ {deductions
+ .sort((a, b) => a.points - b.points)
+ .map((item, i) => (
+
+ {item.points < -7 ? (
+
+ ) : (
+
+ )}
+
+
+ {item.item}
+
+ {item.points}
+
+
+
{item.message}
+
+
+ Priority:{" "}
+ {item.points < -7
+ ? "High"
+ : item.points < -4
+ ? "Medium"
+ : "Low"}
+
+ {item.item === "HTTPS" && !seoData.security.https && (
+
+ Try HTTPS
+
+ )}
+
+
+
+ ))}
+
+
+
+ );
+
+ case "details":
+ return (
+
+
+
+
+ = 2
+ ? "good"
+ : "bad"
+ }
+ goodText={`1 H1 and ${seoData.headings.h2.count} H2 headings`}
+ badText={
+ seoData.headings.h1.count === 0
+ ? "No H1 heading"
+ : seoData.headings.h1.count > 1
+ ? "Multiple H1 headings"
+ : "Not enough H2 headings"
+ }
+ recommendation="Use one H1 and multiple H2s for proper structure"
+ />
+
+
+
+
+ 0 ? "good" : "bad"
+ }
+ goodText={`${seoData.technical.schemaMarkup.count} schema items found`}
+ badText="Missing"
+ recommendation="Implement structured data for rich snippets"
+ />
+
+
+
+
+ = 300 ? "good" : "bad"}
+ goodText={`${seoData.content.wordCount} words (good length)`}
+ badText={`${seoData.content.wordCount} words (too short)`}
+ recommendation="Aim for at least 300 words of quality content"
+ />
+ = 60 ? "good" : "bad"}
+ goodText={`Score: ${seoData.content.readability}/100 (good)`}
+ badText={`Score: ${seoData.content.readability}/100 (needs improvement)`}
+ recommendation="Simplify complex sentences and reduce jargon"
+ />
+
+
+
+ );
+
+ case "full-report":
+ return (
+
+
+
Comprehensive SEO Report
+
+ Generated for {seoData.url} on{" "}
+ {new Date(seoData.analyzedAt).toLocaleString()}
+
+
+
+
+ Executive Summary
+
+
+ Overall SEO Score: {score}/100 -{" "}
+ {score >= 80
+ ? "Excellent"
+ : score >= 60
+ ? "Good"
+ : score >= 40
+ ? "Needs Improvement"
+ : "Poor"}
+
+
+ {score >= 80
+ ? "Your site has strong SEO fundamentals."
+ : score >= 60
+ ? "Your site has decent SEO but could use some improvements."
+ : score >= 40
+ ? "Your site needs significant SEO improvements."
+ : "Your site requires urgent SEO attention."}
+
+
+
+
+ Detailed Findings
+
+
+
On-Page SEO
+
+
+ Title Tag: {" "}
+ {seoData.title.exists
+ ? `"${seoData.title.text}" (${seoData.title.text.length} characters, ${seoData.title.status})`
+ : "Missing"}
+
+
+ Meta Description: {" "}
+ {seoData.meta.description.exists
+ ? `"${seoData.meta.description.text}" (${seoData.meta.description.text.length} characters, ${seoData.meta.description.status})`
+ : "Missing"}
+
+
+ Headings: {seoData.headings.h1.count} H1,{" "}
+ {seoData.headings.h2.count} H2, {seoData.headings.h3.count} H3
+
+
+
+
Technical SEO
+
+
+ Canonical URL: {" "}
+ {seoData.technical.canonical.exists
+ ? seoData.technical.canonical.url
+ : "Missing"}
+
+
+ Schema Markup: {" "}
+ {seoData.technical.schemaMarkup.count > 0
+ ? `${seoData.technical.schemaMarkup.count} schema items found`
+ : "None detected"}
+
+
+ HTTPS: {" "}
+ {seoData.security.https ? "Enabled" : "Not enabled"}
+
+
+
+
Content Quality
+
+
+ Word Count: {seoData.content.wordCount} words
+
+
+ Readability: Score{" "}
+ {seoData.content.readability}/100
+
+
+ Images: {seoData.images.total} total,{" "}
+ {seoData.images.withoutAlt} missing alt text
+
+
+
+
+
+ window.print()}
+ className="bg-blue-600 text-white px-4 py-2 rounded-md flex items-center"
+ >
+
+ Download PDF Report
+
+
+
+ );
+
+ default:
+ return null;
+ }
+ };
+
+ return (
+
+
+
+
setUrl(e.target.value)}
+ placeholder="Enter URL (e.g., https://example.com)"
+ className="flex-1 p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
+ onKeyDown={(e) => e.key === "Enter" && checkSEO()}
+ />
+
+ {loading ? (
+ <>
+
+
+
+
+ Analyzing...
+ >
+ ) : (
+ "Run Full Analysis"
+ )}
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+ {loading && (
+
+
+
+ Running comprehensive SEO analysis...
+
+
This may take 10-15 seconds
+
+ )}
+
+ {seoData && (
+ <>
+
+
+ {["summary", "details", "full-report"].map((tab) => (
+ setActiveTab(tab)}
+ className={`px-4 py-2 text-sm font-medium whitespace-nowrap ${
+ activeTab === tab
+ ? "border-b-2 border-blue-500 text-blue-600"
+ : "text-gray-500 hover:text-gray-700"
+ }`}
+ >
+ {tab
+ .split("-")
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
+ .join(" ")}
+
+ ))}
+
+
+
+ {renderReportSection()}
+ >
+ )}
+
+ );
+};
+
+// Helper Components
+const ScoreCard = ({ title, score, max, description }) => {
+ const percentage = (score / max) * 100;
+ const getColor = () => {
+ if (percentage >= 80) return "bg-green-500";
+ if (percentage >= 50) return "bg-yellow-500";
+ return "bg-red-500";
+ };
+
+ return (
+
+
{title}
+
+ {score}
+ / {max}
+
+
+
{description}
+
+ );
+};
+
+const Section = ({ title, children }) => (
+
+);
+
+const CheckItem = ({ label, status, goodText, badText, recommendation }) => (
+
+
+ {status === "good" ? (
+
+ ) : (
+
+ )}
+
+
+
{label}
+
+ {status === "good" ? goodText : badText}
+
+ {status !== "good" && recommendation && (
+
+ Recommendation: {recommendation}
+
+ )}
+
+
+);
+
+export default SEOChecker;
diff --git a/package-lock.json b/package-lock.json
index b3cb489..1216ed0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,20 +17,24 @@
"@supabase/auth-ui-react": "^0.4.7",
"@supabase/ssr": "^0.5.1",
"@supabase/supabase-js": "^2.45.2",
+ "@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.1.11",
"aos": "^2.3.4",
- "axios": "^1.7.2",
+ "axios": "^1.10.0",
+ "cheerio": "^1.1.0",
"cookies-next": "^4.2.1",
"lucide-react": "^0.525.0",
"next": "^14.2.5",
"nocodb-sdk": "^0.255.0",
"node-fetch": "^3.3.2",
"postcss": "^8.5.6",
+ "puppeteer": "^24.11.2",
"react": "18.2.0",
"react-curved-text": "^3.0.0",
"react-dom": "18.2.0",
"react-google-recaptcha": "^3.1.0",
"react-hot-toast": "^2.5.2",
+ "react-icons": "^5.5.0",
"react-modal-video": "^2.0.1",
"react-phone-number-input": "^3.4.4",
"resend": "^3.5.0",
@@ -83,6 +87,29 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@babel/code-frame": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/runtime": {
"version": "7.24.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz",
@@ -488,6 +515,27 @@
"node": ">=14"
}
},
+ "node_modules/@puppeteer/browsers": {
+ "version": "2.10.5",
+ "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.5.tgz",
+ "integrity": "sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "debug": "^4.4.1",
+ "extract-zip": "^2.0.1",
+ "progress": "^2.0.3",
+ "proxy-agent": "^6.5.0",
+ "semver": "^7.7.2",
+ "tar-fs": "^3.0.8",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "browsers": "lib/cjs/main-cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@react-email/render": {
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/@react-email/render/-/render-0.0.16.tgz",
@@ -668,6 +716,18 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@tailwindcss/forms": {
+ "version": "0.5.10",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",
+ "integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==",
+ "license": "MIT",
+ "dependencies": {
+ "mini-svg-data-uri": "^1.2.3"
+ },
+ "peerDependencies": {
+ "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1"
+ }
+ },
"node_modules/@tailwindcss/node": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz",
@@ -929,6 +989,12 @@
"tailwindcss": "4.1.11"
}
},
+ "node_modules/@tootallnate/quickjs-emscripten": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+ "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
+ "license": "MIT"
+ },
"node_modules/@types/acorn": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
@@ -1037,6 +1103,16 @@
"@types/node": "*"
}
},
+ "node_modules/@types/yauzl": {
+ "version": "2.10.3",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
+ "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
@@ -1236,6 +1312,15 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/agent-base": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+ "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -1310,6 +1395,24 @@
"lodash.throttle": "^4.0.1"
}
},
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "license": "Python-2.0"
+ },
+ "node_modules/ast-types": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
+ "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/astring": {
"version": "1.8.6",
"resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz",
@@ -1324,15 +1427,22 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz",
- "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
+ "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
+ "license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
+ "node_modules/b4a": {
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
+ "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==",
+ "license": "Apache-2.0"
+ },
"node_modules/bail": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
@@ -1347,6 +1457,87 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
+ "node_modules/bare-events": {
+ "version": "2.5.4",
+ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz",
+ "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==",
+ "license": "Apache-2.0",
+ "optional": true
+ },
+ "node_modules/bare-fs": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.6.tgz",
+ "integrity": "sha512-25RsLF33BqooOEFNdMcEhMpJy8EoR88zSMrnOQOaM3USnOK2VmaJ1uaQEwPA6AQjrv1lXChScosN6CzbwbO9OQ==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "bare-events": "^2.5.4",
+ "bare-path": "^3.0.0",
+ "bare-stream": "^2.6.4"
+ },
+ "engines": {
+ "bare": ">=1.16.0"
+ },
+ "peerDependencies": {
+ "bare-buffer": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-buffer": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-os": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz",
+ "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "bare": ">=1.14.0"
+ }
+ },
+ "node_modules/bare-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
+ "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "bare-os": "^3.0.1"
+ }
+ },
+ "node_modules/bare-stream": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz",
+ "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "streamx": "^2.21.0"
+ },
+ "peerDependencies": {
+ "bare-buffer": "*",
+ "bare-events": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-buffer": {
+ "optional": true
+ },
+ "bare-events": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/basic-ftp": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
+ "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -1358,6 +1549,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "license": "ISC"
+ },
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -1409,6 +1606,15 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -1444,6 +1650,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001643",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz",
@@ -1536,6 +1751,79 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/cheerio": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.0.tgz",
+ "integrity": "sha512-+0hMx9eYhJvWbgpKV9hN7jg0JcwydpopZE4hgi+KvQtByZXPp04NiCWU0LzcAbP63abZckIHkTQaXVF52mX3xQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.2.2",
+ "encoding-sniffer": "^0.2.0",
+ "htmlparser2": "^10.0.0",
+ "parse5": "^7.3.0",
+ "parse5-htmlparser2-tree-adapter": "^7.1.0",
+ "parse5-parser-stream": "^7.1.2",
+ "undici": "^7.10.0",
+ "whatwg-mimetype": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18.17"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+ "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/cheerio/node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/cheerio/node_modules/htmlparser2": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz",
+ "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.2.1",
+ "entities": "^6.0.0"
+ }
+ },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -1577,6 +1865,19 @@
"node": ">=6.0"
}
},
+ "node_modules/chromium-bidi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-5.1.0.tgz",
+ "integrity": "sha512-9MSRhWRVoRPDG0TgzkHrshFSJJNZzfY5UFqUMuksg7zL1yoZIZ3jLB0YAgHclbiAxPI86pBnwDX1tbzoiV8aFw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "mitt": "^3.0.1",
+ "zod": "^3.24.1"
+ },
+ "peerDependencies": {
+ "devtools-protocol": "*"
+ }
+ },
"node_modules/classlist-polyfill": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz",
@@ -1596,7 +1897,6 @@
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
@@ -1720,6 +2020,32 @@
"url": "https://opencollective.com/core-js"
}
},
+ "node_modules/cosmiconfig": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
+ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/country-flag-icons": {
"version": "1.5.13",
"resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.13.tgz",
@@ -1738,6 +2064,34 @@
"node": ">= 8"
}
},
+ "node_modules/css-select": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+ "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -1773,11 +2127,12 @@
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
},
"node_modules/debug": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
- "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "license": "MIT",
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -1824,6 +2179,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/degenerator": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+ "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ast-types": "^0.13.4",
+ "escodegen": "^2.1.0",
+ "esprima": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -1861,6 +2230,12 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/devtools-protocol": {
+ "version": "0.0.1464554",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1464554.tgz",
+ "integrity": "sha512-CAoP3lYfwAGQTaAXYvA6JZR0fjGUb7qec1qf4mToyoH2TZgUFeIqYcjh6f9jNuhHfuZiEdH+PONHYrLhRQX6aw==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
@@ -1915,9 +2290,10 @@
"deprecated": "dommatrix is no longer maintained. Please use @thednp/dommatrix."
},
"node_modules/domutils": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
- "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
@@ -1968,6 +2344,28 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
+ "node_modules/encoding-sniffer": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
+ "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "^0.6.3",
+ "whatwg-encoding": "^3.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.18.2",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
@@ -1992,6 +2390,24 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
@@ -2025,6 +2441,46 @@
"node": ">=6"
}
},
+ "node_modules/escodegen": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+ "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esprima": "^4.0.1",
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2"
+ },
+ "bin": {
+ "escodegen": "bin/escodegen.js",
+ "esgenerate": "bin/esgenerate.js"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/escodegen/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/escodegen/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -2038,6 +2494,19 @@
"node": ">=8.0.0"
}
},
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/esrecurse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -2139,6 +2608,15 @@
"@types/estree": "^1.0.0"
}
},
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
@@ -2153,18 +2631,53 @@
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ },
+ "engines": {
+ "node": ">= 10.17.0"
+ },
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"peer": true
},
+ "node_modules/fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "license": "MIT"
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"peer": true
},
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "license": "MIT",
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
@@ -2281,7 +2794,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@@ -2304,6 +2816,44 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/get-uri": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz",
+ "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "basic-ftp": "^5.0.2",
+ "data-uri-to-buffer": "^6.0.2",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/get-uri/node_modules/data-uri-to-buffer": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
+ "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -2550,11 +3100,65 @@
"entities": "^4.4.0"
}
},
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/immutable": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
"integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw=="
},
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
@@ -2573,6 +3177,19 @@
"prop-types": "^15.8.1"
}
},
+ "node_modules/ip-address": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
+ "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+ "license": "MIT",
+ "dependencies": {
+ "jsbn": "1.1.0",
+ "sprintf-js": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
@@ -2595,6 +3212,12 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "license": "MIT"
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -2761,6 +3384,24 @@
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsbn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
+ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
+ "license": "MIT"
+ },
"node_modules/jsep": {
"version": "1.3.9",
"resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.9.tgz",
@@ -2772,8 +3413,7 @@
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
- "peer": true
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
@@ -3022,6 +3662,12 @@
"url": "https://opencollective.com/parcel"
}
},
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
+ },
"node_modules/loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
@@ -3855,6 +4501,15 @@
"node": ">= 0.6"
}
},
+ "node_modules/mini-svg-data-uri": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
+ "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
+ "license": "MIT",
+ "bin": {
+ "mini-svg-data-uri": "cli.js"
+ }
+ },
"node_modules/minimatch": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
@@ -3889,6 +4544,12 @@
"node": ">= 18"
}
},
+ "node_modules/mitt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
+ "license": "MIT"
+ },
"node_modules/mkdirp": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
@@ -3905,9 +4566,10 @@
}
},
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.11",
@@ -3933,6 +4595,15 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"peer": true
},
+ "node_modules/netmask": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
+ "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
"node_modules/next": {
"version": "14.2.5",
"resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz",
@@ -4087,6 +4758,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -4106,11 +4789,64 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/pac-proxy-agent": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
+ "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
+ "license": "MIT",
+ "dependencies": {
+ "@tootallnate/quickjs-emscripten": "^0.23.0",
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "get-uri": "^6.0.1",
+ "http-proxy-agent": "^7.0.0",
+ "https-proxy-agent": "^7.0.6",
+ "pac-resolver": "^7.0.1",
+ "socks-proxy-agent": "^8.0.5"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/pac-resolver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
+ "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
+ "license": "MIT",
+ "dependencies": {
+ "degenerator": "^5.0.0",
+ "netmask": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/package-json-from-dist": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
"integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw=="
},
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/parse-entities": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz",
@@ -4135,6 +4871,73 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
},
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-htmlparser2-tree-adapter": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
+ "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
+ "license": "MIT",
+ "dependencies": {
+ "domhandler": "^5.0.3",
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-parser-stream": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
+ "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
+ "license": "MIT",
+ "dependencies": {
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5/node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/parseley": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
@@ -4178,6 +4981,12 @@
"url": "https://ko-fi.com/killymxi"
}
},
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "license": "MIT"
+ },
"node_modules/periscopic": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
@@ -4233,6 +5042,15 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -4257,11 +5075,49 @@
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
},
+ "node_modules/proxy-agent": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
+ "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "http-proxy-agent": "^7.0.1",
+ "https-proxy-agent": "^7.0.6",
+ "lru-cache": "^7.14.1",
+ "pac-proxy-agent": "^7.1.0",
+ "proxy-from-env": "^1.1.0",
+ "socks-proxy-agent": "^8.0.5"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/proxy-agent/node_modules/lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
+ "node_modules/pump": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
+ "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -4271,6 +5127,44 @@
"node": ">=6"
}
},
+ "node_modules/puppeteer": {
+ "version": "24.11.2",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.11.2.tgz",
+ "integrity": "sha512-HopdRZWHa5zk0HSwd8hU+GlahQ3fmesTAqMIDHVY9HasCvppcYuHYXyjml0nlm+nbwVCqAQWV+dSmiNCrZGTGQ==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@puppeteer/browsers": "2.10.5",
+ "chromium-bidi": "5.1.0",
+ "cosmiconfig": "^9.0.0",
+ "devtools-protocol": "0.0.1464554",
+ "puppeteer-core": "24.11.2",
+ "typed-query-selector": "^2.12.0"
+ },
+ "bin": {
+ "puppeteer": "lib/cjs/puppeteer/node/cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/puppeteer-core": {
+ "version": "24.11.2",
+ "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.11.2.tgz",
+ "integrity": "sha512-c49WifNb8hix+gQH17TldmD6TC/Md2HBaTJLHexIUq4sZvo2pyHY/Pp25qFQjibksBu/SJRYUY7JsoaepNbiRA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@puppeteer/browsers": "2.10.5",
+ "chromium-bidi": "5.1.0",
+ "debug": "^4.4.1",
+ "devtools-protocol": "0.0.1464554",
+ "typed-query-selector": "^2.12.0",
+ "ws": "^8.18.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/qs": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
@@ -4370,6 +5264,15 @@
"react-dom": ">=16"
}
},
+ "node_modules/react-icons": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
+ "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -4496,7 +5399,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -4512,6 +5414,15 @@
"node": ">=18"
}
},
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/rxjs": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
@@ -4541,6 +5452,12 @@
],
"peer": true
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
"node_modules/sass": {
"version": "1.77.8",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz",
@@ -4595,9 +5512,10 @@
}
},
"node_modules/semver": {
- "version": "7.6.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
- "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -4691,6 +5609,44 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.5.tgz",
+ "integrity": "sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww==",
+ "license": "MIT",
+ "dependencies": {
+ "ip-address": "^9.0.5",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
+ "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "socks": "^2.8.3"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
@@ -4742,6 +5698,12 @@
"integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==",
"dev": true
},
+ "node_modules/sprintf-js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
@@ -4750,6 +5712,19 @@
"node": ">=10.0.0"
}
},
+ "node_modules/streamx": {
+ "version": "2.22.1",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz",
+ "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-fifo": "^1.3.2",
+ "text-decoder": "^1.1.0"
+ },
+ "optionalDependencies": {
+ "bare-events": "^2.2.0"
+ }
+ },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -4926,6 +5901,31 @@
"node": ">=18"
}
},
+ "node_modules/tar-fs": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.0.tgz",
+ "integrity": "sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w==",
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0",
+ "tar-stream": "^3.1.5"
+ },
+ "optionalDependencies": {
+ "bare-fs": "^4.0.1",
+ "bare-path": "^3.0.0"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
+ "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
+ "license": "MIT",
+ "dependencies": {
+ "b4a": "^1.6.4",
+ "fast-fifo": "^1.2.0",
+ "streamx": "^2.15.0"
+ }
+ },
"node_modules/terser": {
"version": "5.31.3",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz",
@@ -4978,6 +5978,15 @@
}
}
},
+ "node_modules/text-decoder": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz",
+ "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.6.4"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -5026,6 +6035,21 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
},
+ "node_modules/typed-query-selector": {
+ "version": "2.12.0",
+ "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz",
+ "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==",
+ "license": "MIT"
+ },
+ "node_modules/undici": {
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.11.0.tgz",
+ "integrity": "sha512-heTSIac3iLhsmZhUCjyS3JQEkZELateufzZuBaVM5RHXdSBMb1LPMQf5x+FH7qjsZYDP0ttAc3nnVpUB+wYbOg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
"node_modules/undici-types": {
"version": "6.11.1",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.11.1.tgz",
@@ -5284,6 +6308,27 @@
"node": ">=10.13.0"
}
},
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@@ -5319,7 +6364,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@@ -5349,10 +6393,17 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
"node_modules/ws": {
- "version": "8.18.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
- "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
+ "license": "MIT",
"engines": {
"node": ">=10.0.0"
},
@@ -5373,7 +6424,6 @@
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
"engines": {
"node": ">=10"
}
@@ -5391,7 +6441,6 @@
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
@@ -5409,11 +6458,29 @@
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
"engines": {
"node": ">=12"
}
},
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
+ "node_modules/zod": {
+ "version": "3.25.75",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.75.tgz",
+ "integrity": "sha512-OhpzAmVzabPOL6C3A3gpAifqr9MqihV/Msx3gor2b2kviCgcb+HM9SEOpMWwwNp9MRunWnhtAKUoo0AHhjyPPg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
"node_modules/zwitch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
diff --git a/package.json b/package.json
index 1115112..914affc 100644
--- a/package.json
+++ b/package.json
@@ -20,20 +20,24 @@
"@supabase/auth-ui-react": "^0.4.7",
"@supabase/ssr": "^0.5.1",
"@supabase/supabase-js": "^2.45.2",
+ "@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.1.11",
"aos": "^2.3.4",
- "axios": "^1.7.2",
+ "axios": "^1.10.0",
+ "cheerio": "^1.1.0",
"cookies-next": "^4.2.1",
"lucide-react": "^0.525.0",
"next": "^14.2.5",
"nocodb-sdk": "^0.255.0",
"node-fetch": "^3.3.2",
"postcss": "^8.5.6",
+ "puppeteer": "^24.11.2",
"react": "18.2.0",
"react-curved-text": "^3.0.0",
"react-dom": "18.2.0",
"react-google-recaptcha": "^3.1.0",
"react-hot-toast": "^2.5.2",
+ "react-icons": "^5.5.0",
"react-modal-video": "^2.0.1",
"react-phone-number-input": "^3.4.4",
"resend": "^3.5.0",