+ {frontmatter.title} +
+ + {/* Excerpt */} + {!compact && ( ++ {frontmatter.description} +
+ )} + + {/* Footer */} +diff --git a/client/src/App.tsx b/client/src/App.tsx
index 4d84c89e..10aa5b0a 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -23,6 +23,7 @@ const FAQ = lazy(() => import("./pages/faq"));
const Affiliates = lazy(() => import("./pages/affiliates"));
const BlogIndex = lazy(() => import("./pages/blog/index"));
const BlogPost = lazy(() => import("./pages/blog/post"));
+const BlogTagArchive = lazy(() => import("./pages/blog/tag/index"));
const AdminPanel = lazy(() => import("./pages/admin/index"));
const AboutPage = lazy(() => import("./pages/about"));
const StatusPage = lazy(() => import("./pages/status"));
@@ -252,6 +253,7 @@ function App() {
to use our styled CodeBlock
+ pre: ({ children, ...props }: any) => {
+ const codeEl = (children as any)?.props;
+ const lang = codeEl?.className?.replace(/^language-/, "") ?? "";
+ const filename = (props as any)["data-filename"] ?? "";
+ return (
+
+ {children}
+
+ );
+ },
+
+ // Anchor tags fire outbound click event for external links
+ a: ({ href, children, ...props }: any) => {
+ const isExternal = href?.startsWith("http");
+ return (
+
+ trackEvent({ category: "engagement", action: "blog_outbound_clicked", label: `${slug}::${href}` }),
+ }
+ : {})}
+ >
+ {children}
+
+ );
+ },
+ };
+}
diff --git a/client/src/blog/parse.ts b/client/src/blog/parse.ts
new file mode 100644
index 00000000..03df84b2
--- /dev/null
+++ b/client/src/blog/parse.ts
@@ -0,0 +1,103 @@
+import readingTime from "reading-time";
+import { PostFrontmatterSchema, type BlogPost, type PostFrontmatter } from "./schema";
+
+type MdxModule = {
+ default: React.ComponentType;
+ frontmatter: Record;
+};
+
+const modules = import.meta.glob("../../../content/blog/*.mdx");
+
+function slugFromPath(path: string): string {
+ return path.replace(/^.*\/([^/]+)\.mdx$/, "$1");
+}
+
+function countWords(text: string): number {
+ return text.trim().split(/\s+/).filter(Boolean).length;
+}
+
+let _cache: BlogPost[] | null = null;
+
+export async function getAllPosts(): Promise {
+ if (_cache) return _cache;
+
+ const entries = await Promise.all(
+ Object.entries(modules).map(async ([path, load]) => {
+ const mod = await load();
+ const slug = slugFromPath(path);
+
+ const result = PostFrontmatterSchema.safeParse(mod.frontmatter);
+ if (!result.success) {
+ console.error(`[blog] Invalid frontmatter in ${path}:`, result.error.flatten());
+ return null;
+ }
+
+ const fm = result.data;
+
+ if (import.meta.env.PROD && fm.draft) return null;
+
+ const bodyText = (mod.frontmatter as any).__rawBody ?? fm.description;
+ const rt = readingTime(bodyText);
+ const readingTimeMinutes = fm.readingTimeMinutes ?? Math.max(1, Math.ceil(rt.minutes));
+ const wordCount = countWords(bodyText);
+
+ return { slug, frontmatter: fm, readingTimeMinutes, wordCount } satisfies BlogPost;
+ })
+ );
+
+ _cache = (entries.filter(Boolean) as BlogPost[]).sort(
+ (a, b) =>
+ new Date(b.frontmatter.publishedAt).getTime() -
+ new Date(a.frontmatter.publishedAt).getTime()
+ );
+
+ return _cache;
+}
+
+export async function getPostBySlug(slug: string): Promise {
+ const posts = await getAllPosts();
+ return posts.find((p) => p.slug === slug);
+}
+
+export async function getPostsByTag(tag: string): Promise {
+ const posts = await getAllPosts();
+ return posts.filter((p) =>
+ p.frontmatter.tags.some((t) => t.toLowerCase() === tag.toLowerCase())
+ );
+}
+
+export async function getAllTags(): Promise<{ tag: string; count: number }[]> {
+ const posts = await getAllPosts();
+ const counts = new Map();
+ for (const post of posts) {
+ for (const tag of post.frontmatter.tags) {
+ counts.set(tag, (counts.get(tag) ?? 0) + 1);
+ }
+ }
+ return Array.from(counts.entries())
+ .map(([tag, count]) => ({ tag, count }))
+ .sort((a, b) => b.count - a.count);
+}
+
+export async function getRelatedPosts(post: BlogPost, max = 3): Promise {
+ const all = await getAllPosts();
+ const postTags = new Set(post.frontmatter.tags.map((t) => t.toLowerCase()));
+
+ return all
+ .filter((p) => p.slug !== post.slug)
+ .map((p) => ({
+ post: p,
+ score: p.frontmatter.tags.filter((t) => postTags.has(t.toLowerCase())).length,
+ }))
+ .filter((x) => x.score > 0)
+ .sort((a, b) => b.score - a.score || new Date(b.post.frontmatter.publishedAt).getTime() - new Date(a.post.frontmatter.publishedAt).getTime())
+ .slice(0, max)
+ .map((x) => x.post);
+}
+
+export async function getMdxComponent(slug: string): Promise {
+ const entry = Object.entries(modules).find(([path]) => slugFromPath(path) === slug);
+ if (!entry) return null;
+ const mod = await entry[1]();
+ return mod.default;
+}
diff --git a/client/src/blog/schema.ts b/client/src/blog/schema.ts
new file mode 100644
index 00000000..269181bf
--- /dev/null
+++ b/client/src/blog/schema.ts
@@ -0,0 +1,29 @@
+import { z } from "zod";
+
+const isoDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Must be ISO date (YYYY-MM-DD)");
+
+export const PostFrontmatterSchema = z.object({
+ title: z.string().max(60, "title must be ≤ 60 chars"),
+ description: z
+ .string()
+ .min(140, "description must be ≥ 140 chars")
+ .max(160, "description must be ≤ 160 chars"),
+ publishedAt: isoDate,
+ updatedAt: isoDate.optional(),
+ author: z.string(),
+ tags: z.array(z.string()).min(1, "at least 1 tag required").max(5, "max 5 tags"),
+ draft: z.boolean().default(true),
+ featured: z.boolean().default(false),
+ ogImage: z.string().optional(),
+ canonicalUrl: z.string().url().optional(),
+ readingTimeMinutes: z.number().positive().optional(),
+});
+
+export type PostFrontmatter = z.infer;
+
+export interface BlogPost {
+ slug: string;
+ frontmatter: PostFrontmatter;
+ readingTimeMinutes: number;
+ wordCount: number;
+}
diff --git a/client/src/components/blog/ArticleCard.tsx b/client/src/components/blog/ArticleCard.tsx
new file mode 100644
index 00000000..cfa2c912
--- /dev/null
+++ b/client/src/components/blog/ArticleCard.tsx
@@ -0,0 +1,83 @@
+import { Link } from "wouter";
+import { motion } from "framer-motion";
+import { Calendar, Clock, ArrowRight } from "lucide-react";
+import type { BlogPost } from "@/blog/schema";
+
+interface ArticleCardProps {
+ post: BlogPost;
+ index?: number;
+ compact?: boolean;
+}
+
+function formatDate(iso: string) {
+ return new Date(iso).toLocaleDateString("en-US", {
+ month: "long",
+ day: "numeric",
+ year: "numeric",
+ });
+}
+
+export function ArticleCard({ post, index = 0, compact = false }: ArticleCardProps) {
+ const { slug, frontmatter, readingTimeMinutes } = post;
+
+ return (
+
+
+
+ {/* Meta row */}
+
+
+
+ {formatDate(frontmatter.publishedAt)}
+
+
+
+ {readingTimeMinutes} min read
+
+
+
+ {/* Tags */}
+
+ {frontmatter.tags.slice(0, 2).map((tag) => (
+
+ {tag}
+
+ ))}
+ {frontmatter.tags.length > 2 && (
+
+ +{frontmatter.tags.length - 2}
+
+ )}
+
+
+ {/* Title */}
+
+ {frontmatter.title}
+
+
+ {/* Excerpt */}
+ {!compact && (
+
+ {frontmatter.description}
+
+ )}
+
+ {/* Footer */}
+
+ {frontmatter.author}
+
+ Read
+
+
+
+
+
+ );
+}
diff --git a/client/src/components/blog/ArticleCardHero.tsx b/client/src/components/blog/ArticleCardHero.tsx
new file mode 100644
index 00000000..39476c2a
--- /dev/null
+++ b/client/src/components/blog/ArticleCardHero.tsx
@@ -0,0 +1,96 @@
+import { Link } from "wouter";
+import { motion } from "framer-motion";
+import { Calendar, Clock, ArrowRight } from "lucide-react";
+import type { BlogPost } from "@/blog/schema";
+
+interface ArticleCardHeroProps {
+ post: BlogPost;
+}
+
+function formatDate(iso: string) {
+ return new Date(iso).toLocaleDateString("en-US", {
+ month: "long",
+ day: "numeric",
+ year: "numeric",
+ });
+}
+
+export function ArticleCardHero({ post }: ArticleCardHeroProps) {
+ const { slug, frontmatter, readingTimeMinutes } = post;
+ const imageUrl = frontmatter.ogImage;
+
+ return (
+
+
+
+ {/* Background image */}
+ {imageUrl && (
+ <>
+
+
+ >
+ )}
+ {!imageUrl && (
+
+ )}
+
+ {/* Featured badge */}
+
+
+ Featured
+
+
+
+ {/* Content */}
+
+ {/* Tags */}
+
+ {frontmatter.tags.slice(0, 3).map((tag) => (
+
+ {tag}
+
+ ))}
+
+
+ {/* Title */}
+
+ {frontmatter.title}
+
+
+ {/* Excerpt */}
+
+ {frontmatter.description}
+
+
+ {/* Footer */}
+
+
+
+
+ {formatDate(frontmatter.publishedAt)}
+
+
+
+ {readingTimeMinutes} min read
+
+
+
+ Read Article
+
+
+
+
+
+
+ );
+}
diff --git a/client/src/components/blog/AuthorCard.tsx b/client/src/components/blog/AuthorCard.tsx
new file mode 100644
index 00000000..9f34fd42
--- /dev/null
+++ b/client/src/components/blog/AuthorCard.tsx
@@ -0,0 +1,58 @@
+import { Github, Twitter } from "lucide-react";
+
+interface Author {
+ id: string;
+ name: string;
+ title: string;
+ avatar: string;
+ twitter?: string;
+ github?: string;
+ bio: string;
+}
+
+interface AuthorCardProps {
+ author: Author;
+}
+
+export function AuthorCard({ author }: AuthorCardProps) {
+ return (
+
+
+
+
+ );
+}
diff --git a/client/src/components/blog/Callout.tsx b/client/src/components/blog/Callout.tsx
new file mode 100644
index 00000000..7c613758
--- /dev/null
+++ b/client/src/components/blog/Callout.tsx
@@ -0,0 +1,50 @@
+import { Info, AlertTriangle, Lightbulb } from "lucide-react";
+import type { ReactNode } from "react";
+
+type CalloutType = "note" | "warning" | "tip";
+
+interface CalloutProps {
+ type?: CalloutType;
+ title?: string;
+ children: ReactNode;
+}
+
+const config: Record = {
+ note: {
+ icon: Info,
+ border: "border-[#00FF9F]",
+ bg: "bg-[#00FF9F]/6",
+ iconColor: "text-[#00FF9F]",
+ label: "Note",
+ },
+ warning: {
+ icon: AlertTriangle,
+ border: "border-[#F59E0B]",
+ bg: "bg-[#F59E0B]/6",
+ iconColor: "text-[#F59E0B]",
+ label: "Warning",
+ },
+ tip: {
+ icon: Lightbulb,
+ border: "border-[#3B82F6]",
+ bg: "bg-[#3B82F6]/6",
+ iconColor: "text-[#3B82F6]",
+ label: "Tip",
+ },
+};
+
+export function Callout({ type = "note", title, children }: CalloutProps) {
+ const { icon: Icon, border, bg, iconColor, label } = config[type];
+
+ return (
+
+
+
+ {title ?? label}
+
+
+ {children}
+
+
+ );
+}
diff --git a/client/src/components/blog/CodeBlock.tsx b/client/src/components/blog/CodeBlock.tsx
new file mode 100644
index 00000000..c9853402
--- /dev/null
+++ b/client/src/components/blog/CodeBlock.tsx
@@ -0,0 +1,72 @@
+import { useState } from "react";
+import type { ReactNode } from "react";
+
+interface CodeBlockProps {
+ children: ReactNode;
+ filename?: string;
+ language?: string;
+ className?: string;
+}
+
+export function CodeBlock({ children, filename, language, className }: CodeBlockProps) {
+ const [copied, setCopied] = useState(false);
+
+ const lang = language ?? className?.replace(/^language-/, "") ?? "";
+
+ const getPlainText = (node: ReactNode): string => {
+ if (typeof node === "string") return node;
+ if (typeof node === "number") return String(node);
+ if (!node) return "";
+ if (Array.isArray(node)) return node.map(getPlainText).join("");
+ if (typeof node === "object" && "props" in (node as any)) {
+ return getPlainText((node as any).props.children);
+ }
+ return "";
+ };
+
+ const handleCopy = async () => {
+ try {
+ await navigator.clipboard.writeText(getPlainText(children));
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ } catch {
+ // ignore
+ }
+ };
+
+ return (
+
+ {/* Header bar */}
+
+
+
+
+
+
+
+ {filename && (
+ {filename}
+ )}
+
+
+ {lang && (
+
+ {lang}
+
+ )}
+
+
+
+
+ {/* Code content */}
+
+ {children}
+
+
+ );
+}
diff --git a/client/src/components/blog/CxDemo.tsx b/client/src/components/blog/CxDemo.tsx
new file mode 100644
index 00000000..6ea70cf9
--- /dev/null
+++ b/client/src/components/blog/CxDemo.tsx
@@ -0,0 +1,54 @@
+import { useEffect, useState } from "react";
+
+interface CxDemoProps {
+ command: string;
+ output?: string;
+}
+
+export function CxDemo({ command, output }: CxDemoProps) {
+ const [displayed, setDisplayed] = useState("");
+ const [done, setDone] = useState(false);
+
+ useEffect(() => {
+ setDisplayed("");
+ setDone(false);
+ let i = 0;
+ const interval = setInterval(() => {
+ i++;
+ setDisplayed(command.slice(0, i));
+ if (i >= command.length) {
+ clearInterval(interval);
+ setDone(true);
+ }
+ }, 40);
+ return () => clearInterval(interval);
+ }, [command]);
+
+ return (
+
+ {/* Title bar */}
+
+
+
+
+ bash
+
+
+ {/* Command line */}
+
+ user@cx:~$
+ {displayed}
+ {!done && (
+
+ )}
+
+
+ {/* Output */}
+ {output && done && (
+
+ {output}
+
+ )}
+
+ );
+}
diff --git a/client/src/components/blog/PostImage.tsx b/client/src/components/blog/PostImage.tsx
new file mode 100644
index 00000000..1e5a806f
--- /dev/null
+++ b/client/src/components/blog/PostImage.tsx
@@ -0,0 +1,36 @@
+import type { ComponentType } from "react";
+
+interface PostImageProps {
+ slug: string;
+ SvgComponent?: ComponentType<{ className?: string }>;
+ src?: string;
+ alt: string;
+}
+
+export function PostImage({ slug, SvgComponent, src, alt }: PostImageProps) {
+ if (SvgComponent) {
+ return (
+
+
+
+ );
+ }
+
+ if (src) {
+ return (
+
+
+
+ );
+ }
+
+ return null;
+}
diff --git a/client/src/components/blog/ReadingProgress.tsx b/client/src/components/blog/ReadingProgress.tsx
new file mode 100644
index 00000000..90d909ad
--- /dev/null
+++ b/client/src/components/blog/ReadingProgress.tsx
@@ -0,0 +1,26 @@
+import { useEffect, useState } from "react";
+
+export function ReadingProgress() {
+ const [progress, setProgress] = useState(0);
+
+ useEffect(() => {
+ const update = () => {
+ const el = document.documentElement;
+ const scrollTop = window.scrollY;
+ const total = el.scrollHeight - el.clientHeight;
+ setProgress(total > 0 ? Math.min(100, (scrollTop / total) * 100) : 0);
+ };
+
+ window.addEventListener("scroll", update, { passive: true });
+ return () => window.removeEventListener("scroll", update);
+ }, []);
+
+ return (
+
+
+
+ );
+}
diff --git a/client/src/components/blog/ShareBar.tsx b/client/src/components/blog/ShareBar.tsx
new file mode 100644
index 00000000..90fd23a6
--- /dev/null
+++ b/client/src/components/blog/ShareBar.tsx
@@ -0,0 +1,47 @@
+import { useState } from "react";
+import { Twitter, Link2, Mail } from "lucide-react";
+
+interface ShareBarProps {
+ title: string;
+ url: string;
+ className?: string;
+}
+
+export function ShareBar({ title, url, className = "" }: ShareBarProps) {
+ const [copied, setCopied] = useState(false);
+
+ const handleCopy = async () => {
+ try {
+ await navigator.clipboard.writeText(url);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ } catch {
+ // fallback: select the URL
+ }
+ };
+
+ const twitterUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(title)}&url=${encodeURIComponent(url)}`;
+ const mailUrl = `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(url)}`;
+
+ const btnClass =
+ "w-9 h-9 flex items-center justify-center rounded-lg bg-white/5 border border-white/10 hover:border-[#00FF9F]/30 hover:bg-white/8 transition-all duration-150 text-gray-400 hover:text-white";
+
+ return (
+
+ );
+}
diff --git a/client/src/components/blog/TableOfContents.tsx b/client/src/components/blog/TableOfContents.tsx
new file mode 100644
index 00000000..1512c850
--- /dev/null
+++ b/client/src/components/blog/TableOfContents.tsx
@@ -0,0 +1,79 @@
+import { useEffect, useRef, useState } from "react";
+
+interface TocItem {
+ id: string;
+ text: string;
+ level: 2 | 3;
+}
+
+interface TableOfContentsProps {
+ contentRef: React.RefObject;
+}
+
+export function TableOfContents({ contentRef }: TableOfContentsProps) {
+ const [items, setItems] = useState([]);
+ const [activeId, setActiveId] = useState("");
+ const observerRef = useRef(null);
+
+ useEffect(() => {
+ const el = contentRef.current;
+ if (!el) return;
+
+ const headings = Array.from(el.querySelectorAll("h2[id], h3[id]")) as HTMLElement[];
+ setItems(
+ headings.map((h) => ({
+ id: h.id,
+ text: h.textContent ?? "",
+ level: h.tagName === "H2" ? 2 : 3,
+ }))
+ );
+
+ observerRef.current?.disconnect();
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ const visible = entries.filter((e) => e.isIntersecting);
+ if (visible.length > 0) {
+ setActiveId(visible[0].target.id);
+ }
+ },
+ { rootMargin: "-64px 0px -70% 0px", threshold: 0 }
+ );
+
+ headings.forEach((h) => observer.observe(h));
+ observerRef.current = observer;
+
+ return () => observer.disconnect();
+ }, [contentRef]);
+
+ if (items.length === 0) return null;
+
+ return (
+
+ );
+}
diff --git a/client/src/lib/analytics.ts b/client/src/lib/analytics.ts
index 1db70f8d..b3667054 100644
--- a/client/src/lib/analytics.ts
+++ b/client/src/lib/analytics.ts
@@ -97,4 +97,16 @@ export const analytics = {
},
};
+// Blog-specific events
+export const blogAnalytics = {
+ articleViewed: (slug: string) =>
+ trackEvent({ category: "engagement", action: "blog_article_viewed", label: slug }),
+ scrollDepth: (slug: string, pct: 25 | 50 | 75 | 100) =>
+ trackEvent({ category: "engagement", action: "blog_scroll_depth", label: `${slug}::${pct}` }),
+ copyCodeClick: (slug: string) =>
+ trackEvent({ category: "engagement", action: "blog_copy_code_click", label: slug }),
+ outboundClicked: (slug: string, url: string) =>
+ trackEvent({ category: "engagement", action: "blog_outbound_clicked", label: `${slug}::${url}` }),
+};
+
export default analytics;
diff --git a/client/src/mdx.d.ts b/client/src/mdx.d.ts
new file mode 100644
index 00000000..0718c43c
--- /dev/null
+++ b/client/src/mdx.d.ts
@@ -0,0 +1,6 @@
+declare module "*.mdx" {
+ import type { ComponentType } from "react";
+ const MDXComponent: ComponentType;
+ export default MDXComponent;
+ export const frontmatter: Record;
+}
diff --git a/client/src/pages/blog/index.tsx b/client/src/pages/blog/index.tsx
index 8ef7c1d3..fb1ebba3 100644
--- a/client/src/pages/blog/index.tsx
+++ b/client/src/pages/blog/index.tsx
@@ -1,87 +1,180 @@
-import { useEffect } from "react";
-import { Link } from "wouter";
+import { useEffect, useState, useMemo } from "react";
+import { Link, useSearch } from "wouter";
import { motion } from "framer-motion";
+import { Rss, Search } from "lucide-react";
import { updateSEO, seoConfigs } from "@/lib/seo";
-import { blogPosts } from "@/data/blog-posts";
-import { Calendar, Clock, ArrowRight, Tag } from "lucide-react";
+import { getAllPosts, getAllTags } from "@/blog/parse";
+import { ArticleCard } from "@/components/blog/ArticleCard";
+import { ArticleCardHero } from "@/components/blog/ArticleCardHero";
import Footer from "@/components/Footer";
+import type { BlogPost } from "@/blog/schema";
+
+const POSTS_PER_PAGE = 10;
export default function BlogIndex() {
+ const [posts, setPosts] = useState([]);
+ const [tags, setTags] = useState<{ tag: string; count: number }[]>([]);
+ const [loading, setLoading] = useState(true);
+ const search = useSearch();
+
+ const params = new URLSearchParams(search);
+ const activeTag = params.get("tag") ?? "";
+ const page = Math.max(1, parseInt(params.get("page") ?? "1", 10));
+ const [query, setQuery] = useState("");
+
useEffect(() => {
- const cleanup = updateSEO(seoConfigs.blog);
+ const cleanup = updateSEO({
+ ...seoConfigs.blog,
+ jsonLd: {
+ "@context": "https://schema.org",
+ "@type": "Blog",
+ "@id": "https://cxlinux.com/blog",
+ name: "CX Linux Blog",
+ description: seoConfigs.blog.description,
+ url: "https://cxlinux.com/blog",
+ publisher: {
+ "@type": "Organization",
+ name: "CX Linux",
+ logo: { "@type": "ImageObject", url: "https://cxlinux.com/logo.png" },
+ },
+ },
+ });
return cleanup;
}, []);
+ useEffect(() => {
+ getAllPosts().then((p) => {
+ setPosts(p);
+ setLoading(false);
+ });
+ getAllTags().then(setTags);
+ }, []);
+
+ const featured = useMemo(() => posts.find((p) => p.frontmatter.featured), [posts]);
+
+ const filtered = useMemo(() => {
+ let result = posts.filter((p) => !p.frontmatter.featured || activeTag || query);
+ if (activeTag) result = result.filter((p) => p.frontmatter.tags.some((t) => t.toLowerCase() === activeTag.toLowerCase()));
+ if (query) {
+ const q = query.toLowerCase();
+ result = result.filter(
+ (p) => p.frontmatter.title.toLowerCase().includes(q) || p.frontmatter.description.toLowerCase().includes(q)
+ );
+ }
+ return result;
+ }, [posts, activeTag, query]);
+
+ const totalPages = Math.ceil(filtered.length / POSTS_PER_PAGE);
+ const paginated = filtered.slice((page - 1) * POSTS_PER_PAGE, page * POSTS_PER_PAGE);
+
return (
-
-
-
-
- CX Linux Blog
-
-
- Tutorials, insights, and updates from the CX Linux team.
-
-
-
-
- {blogPosts.map((post, index) => (
-
-
-
-
-
-
- {new Date(post.date).toLocaleDateString("en-US", {
- month: "long",
- day: "numeric",
- year: "numeric",
- })}
-
-
-
- {post.readTime}
-
-
-
-
- {post.title}
-
-
-
- {post.excerpt}
-
-
-
-
- {post.tags.map((tag) => (
-
- {tag}
-
- ))}
-
-
- Read more
-
-
-
+
+ {/* Hero */}
+
+
+
+
+
+ CX Linux Blog
+
+
+ Tutorials, architecture deep-dives, and practical guides for AI-powered Linux engineering.
+
+
+
+
+
+
+ {/* Filters */}
+
+ {/* Search */}
+
+
+ setQuery(e.target.value)}
+ className="w-full bg-white/5 border border-white/10 rounded-lg pl-9 pr-4 py-2 text-sm text-white placeholder-gray-600 focus:outline-none focus:border-[#00FF9F]/40 focus:bg-white/8 transition-all"
+ />
+
+
+ {/* Tags */}
+
+
+
+ All
+
+
+ {tags.map(({ tag, count }) => (
+
+
+ {tag}
+ ({count})
+
-
- ))}
+ ))}
+
+
+
+ {loading ? (
+
+
+
+ ) : (
+ <>
+ {/* Featured hero (only on first page, no filter, no search) */}
+ {featured && !activeTag && !query && page === 1 && (
+
+
+
+ )}
+
+ {/* Post grid */}
+ {paginated.length > 0 ? (
+
+ {paginated.map((post, i) => (
+
+ ))}
+
+ ) : (
+
+ No posts found{query ? ` for "${query}"` : ""}{activeTag ? ` tagged "${activeTag}"` : ""}.
+
+ )}
+
+ {/* Pagination */}
+ {totalPages > 1 && (
+
+ {page > 1 && (
+
+ ← Prev
+
+ )}
+ {Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => (
+
+ {p}
+
+ ))}
+ {page < totalPages && (
+
+ Next →
+
+ )}
+
+ )}
+ >
+ )}
+
+ {/* RSS link */}
+
+
);
diff --git a/client/src/pages/blog/post.tsx b/client/src/pages/blog/post.tsx
index c2c76786..6b67b9df 100644
--- a/client/src/pages/blog/post.tsx
+++ b/client/src/pages/blog/post.tsx
@@ -1,169 +1,312 @@
-import { useEffect } from "react";
+import { useEffect, useState, useRef, useCallback } from "react";
import { useRoute, Link } from "wouter";
-import { motion } from "framer-motion";
+import { motion, AnimatePresence } from "framer-motion";
+import { MDXProvider } from "@mdx-js/react";
+import { ArrowLeft, ChevronUp } from "lucide-react";
import { updateSEO } from "@/lib/seo";
-import { getBlogPost, blogPosts } from "@/data/blog-posts";
-import { Calendar, Clock, ArrowLeft, Tag } from "lucide-react";
+import { getAllPosts, getRelatedPosts, getMdxComponent } from "@/blog/parse";
+import { getMDXComponents } from "@/blog/mdxComponents";
+import { ReadingProgress } from "@/components/blog/ReadingProgress";
+import { TableOfContents } from "@/components/blog/TableOfContents";
+import { ShareBar } from "@/components/blog/ShareBar";
+import { AuthorCard } from "@/components/blog/AuthorCard";
+import { ArticleCard } from "@/components/blog/ArticleCard";
+import { trackEvent } from "@/lib/analytics";
import Footer from "@/components/Footer";
+import authorsJson from "../../../../content/authors.json";
+import type { BlogPost } from "@/blog/schema";
-export default function BlogPost() {
+const BASE_URL = "https://cxlinux.com";
+
+function formatDate(iso: string) {
+ return new Date(iso).toLocaleDateString("en-US", {
+ month: "long",
+ day: "numeric",
+ year: "numeric",
+ });
+}
+
+export default function BlogPostPage() {
const [, params] = useRoute("/blog/:slug");
- const post = params?.slug ? getBlogPost(params.slug) : undefined;
+ const slug = params?.slug ?? "";
+
+ const [post, setPost] = useState(undefined);
+ const [allPosts, setAllPosts] = useState([]);
+ const [related, setRelated] = useState([]);
+ const [MdxContent, setMdxContent] = useState(null);
+ const [showScrollTop, setShowScrollTop] = useState(false);
+
+ const contentRef = useRef(null);
+ // Load post data
useEffect(() => {
- if (post) {
- const cleanup = updateSEO({
- title: `${post.title} | CX Linux Blog`,
- description: post.excerpt,
- canonicalPath: `/blog/${post.slug}`,
- ogType: "article",
- keywords: post.tags,
- jsonLd: {
+ getAllPosts().then((posts) => {
+ const found = posts.find((p) => p.slug === slug) ?? null;
+ setPost(found);
+ setAllPosts(posts);
+ if (found) getRelatedPosts(found, 3).then(setRelated);
+ });
+ getMdxComponent(slug).then(setMdxContent);
+ }, [slug]);
+
+ // SEO
+ useEffect(() => {
+ if (!post) return;
+ const fm = post.frontmatter;
+ const ogImage = fm.ogImage ?? `${BASE_URL}/og/${slug}.png`;
+ const canonicalUrl = `${BASE_URL}/blog/${slug}`;
+ const author = authorsJson.find((a) => a.id === fm.author) ?? authorsJson[0];
+
+ const cleanup = updateSEO({
+ title: `${fm.title} | CX Linux Blog`,
+ description: fm.description,
+ canonicalPath: `/blog/${slug}`,
+ ogType: "article",
+ ogImage,
+ keywords: fm.tags,
+ jsonLd: [
+ {
"@context": "https://schema.org",
- "@type": "BlogPosting",
- headline: post.title,
- description: post.excerpt,
- datePublished: post.date,
+ "@type": "Article",
+ headline: fm.title,
+ description: fm.description,
+ image: [ogImage],
author: {
- "@type": "Organization",
- name: post.author,
+ "@type": "Person",
+ name: author.name,
+ url: `https://twitter.com/${author.twitter}`,
},
publisher: {
"@type": "Organization",
name: "CX Linux",
- url: "https://cxlinux.com",
+ logo: { "@type": "ImageObject", url: `${BASE_URL}/logo.png` },
},
- mainEntityOfPage: {
- "@type": "WebPage",
- "@id": `https://cxlinux.com/blog/${post.slug}`,
+ datePublished: fm.publishedAt,
+ dateModified: fm.updatedAt ?? fm.publishedAt,
+ mainEntityOfPage: { "@type": "WebPage", "@id": canonicalUrl },
+ wordCount: post.wordCount,
+ keywords: fm.tags.join(", "),
+ inLanguage: "en-US",
+ isPartOf: {
+ "@type": "Blog",
+ "@id": `${BASE_URL}/blog`,
+ name: "CX Linux Blog",
},
},
- });
- return cleanup;
- }
- }, [post]);
+ {
+ "@context": "https://schema.org",
+ "@type": "BreadcrumbList",
+ itemListElement: [
+ { "@type": "ListItem", position: 1, name: "Home", item: BASE_URL },
+ { "@type": "ListItem", position: 2, name: "Blog", item: `${BASE_URL}/blog` },
+ { "@type": "ListItem", position: 3, name: fm.title, item: canonicalUrl },
+ ],
+ },
+ ],
+ });
+ return cleanup;
+ }, [post, slug]);
+
+ // Analytics: article viewed
+ useEffect(() => {
+ if (!post) return;
+ trackEvent({ category: "engagement", action: "blog_article_viewed", label: slug });
+ }, [post, slug]);
+
+ // Scroll depth tracking
+ useEffect(() => {
+ const thresholds = [25, 50, 75, 100];
+ const fired = new Set();
+ const onScroll = () => {
+ const el = document.documentElement;
+ const pct = Math.round((window.scrollY / (el.scrollHeight - el.clientHeight)) * 100);
+ for (const t of thresholds) {
+ if (pct >= t && !fired.has(t)) {
+ fired.add(t);
+ trackEvent({ category: "engagement", action: "blog_scroll_depth", label: `${slug}::${t}` });
+ }
+ }
+ setShowScrollTop(window.scrollY > 800);
+ };
+ window.addEventListener("scroll", onScroll, { passive: true });
+ return () => window.removeEventListener("scroll", onScroll);
+ }, [slug]);
+
+ if (post === undefined) {
+ return (
+
+
+
+ );
+ }
- if (!post) {
+ if (post === null) {
return (
-
-
+
+
Post Not Found
-
- The blog post you're looking for doesn't exist.
-
-
- ← Back to Blog
-
+ ← Back to Blog
);
}
- // Find next/prev posts
- const currentIndex = blogPosts.findIndex((p) => p.slug === post.slug);
- const prevPost = currentIndex > 0 ? blogPosts[currentIndex - 1] : null;
- const nextPost =
- currentIndex < blogPosts.length - 1 ? blogPosts[currentIndex + 1] : null;
+ const { frontmatter } = post;
+ const author = authorsJson.find((a) => a.id === frontmatter.author) ?? authorsJson[0];
+ const postIndex = allPosts.findIndex((p) => p.slug === slug);
+ const prevPost = postIndex < allPosts.length - 1 ? allPosts[postIndex + 1] : null;
+ const nextPost = postIndex > 0 ? allPosts[postIndex - 1] : null;
+ const canonicalUrl = `${BASE_URL}/blog/${slug}`;
return (
-
-
-
+
+
+
+
+
{/* Back link */}
-
+
- Back to Blog
+ All Posts
- {/* Header */}
-
-
-
-
- {new Date(post.date).toLocaleDateString("en-US", {
- month: "long",
- day: "numeric",
- year: "numeric",
- })}
-
-
-
- {post.readTime}
-
- by {post.author}
+ {/* Article header */}
+
+ {/* Tags */}
+
+ {frontmatter.tags.map((tag) => (
+
+
+ {tag}
+
+
+ ))}
-
- {post.title}
+ {/* Title */}
+
+ {frontmatter.title}
-
- {post.tags.map((tag) => (
-
- {tag}
-
- ))}
+ {/* Byline */}
+
+
+ {author.name}
+ ·
+
+ ·
+ {post.readingTimeMinutes} min read
+ ·
+ {post.wordCount.toLocaleString()} words
+ {frontmatter.updatedAt && frontmatter.updatedAt !== frontmatter.publishedAt && (
+ Updated {formatDate(frontmatter.updatedAt)}
+ )}
- {/* Content */}
-
-
- {/* Navigation */}
-
- {prevPost ? (
-
- ← Previous
-
- {prevPost.title}
-
-
- ) : (
-
- )}
- {nextPost ? (
-
+ {/* Left: TOC (sticky desktop) */}
+
+
+ {/* Center: Article content */}
+
+
- Next →
-
- {nextPost.title}
-
-
- ) : (
-
- )}
+ {MdxContent ? (
+
+
+
+ ) : (
+
+ {[...Array(8)].map((_, i) => (
+
+ ))}
+
+ )}
+
+
+ {/* Author card */}
+
+
+
+
+ {/* Prev / Next navigation */}
+
+ {prevPost ? (
+
+ ← Previous
+ {prevPost.frontmatter.title}
+
+ ) : }
+ {nextPost ? (
+
+ Next →
+ {nextPost.frontmatter.title}
+
+ ) : }
+
+
+ {/* Related posts */}
+ {related.length > 0 && (
+
+ Related Articles
+
+ {related.map((p, i) => (
+
+ ))}
+
+
+ )}
+
+
+ {/* Right: Share bar (sticky desktop) */}
+
-
+
+
+ {/* Scroll to top */}
+
+ {showScrollTop && (
+ window.scrollTo({ top: 0, behavior: "smooth" })}
+ className="fixed bottom-8 right-8 w-10 h-10 bg-[#00FF9F] text-black rounded-full flex items-center justify-center shadow-lg hover:bg-[#00CC7F] transition-colors z-50"
+ aria-label="Scroll to top"
+ >
+
+
+ )}
+
+
);
diff --git a/client/src/pages/blog/tag/index.tsx b/client/src/pages/blog/tag/index.tsx
new file mode 100644
index 00000000..6cbc7f11
--- /dev/null
+++ b/client/src/pages/blog/tag/index.tsx
@@ -0,0 +1,81 @@
+import { useEffect, useState } from "react";
+import { Link, useRoute } from "wouter";
+import { motion } from "framer-motion";
+import { ArrowLeft, Hash } from "lucide-react";
+import { updateSEO } from "@/lib/seo";
+import { getPostsByTag } from "@/blog/parse";
+import { ArticleCard } from "@/components/blog/ArticleCard";
+import Footer from "@/components/Footer";
+import type { BlogPost } from "@/blog/schema";
+
+export default function BlogTagArchive() {
+ const [, params] = useRoute("/blog/tag/:tag");
+ const tag = params?.tag ? decodeURIComponent(params.tag) : "";
+
+ const [posts, setPosts] = useState([]);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ if (!tag) return;
+ getPostsByTag(tag).then((p) => {
+ setPosts(p);
+ setLoading(false);
+ });
+ }, [tag]);
+
+ useEffect(() => {
+ if (!tag) return;
+ const cleanup = updateSEO({
+ title: `#${tag} Posts | CX Linux Blog`,
+ description: `Browse all CX Linux blog posts tagged with "${tag}". Tutorials, guides, and technical deep-dives for AI-powered Linux engineering.`,
+ canonicalPath: `/blog/tag/${encodeURIComponent(tag)}`,
+ });
+ return cleanup;
+ }, [tag]);
+
+ return (
+
+ {/* Hero */}
+
+
+
+
+
+
+ All Posts
+
+
+
+
+ {tag}
+
+
+ {!loading && (
+
+ {posts.length} {posts.length === 1 ? "post" : "posts"}
+
+ )}
+
+
+
+
+
+ {loading ? (
+
+
+
+ ) : posts.length > 0 ? (
+
+ {posts.map((post, i) => (
+
+ ))}
+
+ ) : (
+ No posts found for this tag.
+ )}
+
+
+
+
+ );
+}
diff --git a/content/authors.json b/content/authors.json
new file mode 100644
index 00000000..668406fe
--- /dev/null
+++ b/content/authors.json
@@ -0,0 +1,11 @@
+[
+ {
+ "id": "cx-team",
+ "name": "CX Linux Team",
+ "title": "AI Venture Holdings LLC",
+ "avatar": "/logo.png",
+ "twitter": "cxlinuxai",
+ "github": "cxlinux-ai",
+ "bio": "Building the AI layer for Linux. Open source, community-driven, shipping fast."
+ }
+]
diff --git a/content/blog/ai-ml-setup-5-minutes.mdx b/content/blog/ai-ml-setup-5-minutes.mdx
new file mode 100644
index 00000000..92407eb5
--- /dev/null
+++ b/content/blog/ai-ml-setup-5-minutes.mdx
@@ -0,0 +1,103 @@
+---
+title: "CX Linux for AI/ML: Full Stack in 5 Minutes"
+description: "Set up Python, CUDA, Ollama, PyTorch, and a full AI development environment on Linux in under 5 minutes using CX Linux natural language commands."
+publishedAt: "2026-03-25"
+author: "cx-team"
+tags: ["AI", "machine-learning", "tutorial"]
+draft: false
+featured: false
+ogImage: "https://images.unsplash.com/photo-1677442135703-1787eea5ce01?auto=format&fit=crop&w=1200&h=630&q=80"
+---
+
+Setting up a machine learning development environment on Linux is notoriously painful. CUDA version conflicts. Python environment hell. Driver mismatches that take half a day to diagnose. CX Linux was partially designed with AI engineers in mind — here's how to go from a fresh Ubuntu machine to a fully operational ML stack.
+
+## Detect Your Hardware First
+
+CX starts with hardware detection:
+
+
+
+This matters because CX will install the exact CUDA version compatible with your GPU — not the latest, not a generic recommendation.
+
+## Full ML Stack in One Command
+
+
+
+CX resolves all version dependencies automatically. If there's a conflict between CUDA 12.3 and the PyTorch build, CX flags it before installing anything.
+
+## Setting Up Ollama for Local LLMs
+
+With CX, you can run large language models locally without reading the Ollama docs:
+
+```bash
+cx "install Ollama and pull Mistral 7B, Llama 3 8B, and Code Llama 13B — configure to start on boot and expose the API on localhost:11434"
+```
+
+```bash
+# Test your local LLM
+cx "test my Ollama installation with a quick inference benchmark"
+```
+
+
+CX Linux itself uses Ollama under the hood for local mode. Once you've set up Ollama, you can switch CX to local mode with `cx config set llm.provider local` and all CX operations will run through your local GPU — zero API costs.
+
+
+## Python Environment Management
+
+CX handles the Python environment complexity that trips up most developers:
+
+```bash
+cx "create a clean Python 3.11 virtual environment for my stable-diffusion project — install all requirements from requirements.txt, resolving any conflicts"
+```
+
+```bash
+cx "my Python environment is broken — diagnose and rebuild it without losing my installed packages"
+```
+
+## GPU Monitoring and Optimization
+
+```bash
+cx "set up GPU monitoring: show me a live dashboard of GPU utilization, VRAM usage, temperature, and power draw — alert if temperature exceeds 85°C"
+```
+
+CX installs `nvtop` or `gpustat` based on your preference and configures alerting with your chosen notification method.
+
+## Running a Fine-Tuning Job
+
+```bash
+cx "set up LoRA fine-tuning for Llama 3 8B using my dataset in ./data/train.jsonl — 4-bit quantization, gradient checkpointing, save checkpoint every 500 steps"
+```
+
+CX generates the training script with the correct hyperparameters for your GPU's VRAM budget, configures distributed training if you have multiple GPUs, and sets up checkpoint saving.
+
+## From Notebook to Production API
+
+When your model is ready to serve:
+
+```bash
+cx "deploy my PyTorch model from ./models/best.pt as a FastAPI endpoint on port 8080 with HTTPS, request queuing, and GPU batching for throughput"
+```
+
+## Why CX Matters for AI Engineers
+
+The dirty secret of AI engineering is that most of the time isn't spent on model architecture — it's spent on environment setup, debugging CUDA errors, and managing dependencies. CX eliminates that overhead.
+
+You ship models. Not environment configs.
+
+[Get started with CX Linux →](/getting-started)
diff --git a/content/blog/cx-linux-2026-roadmap.mdx b/content/blog/cx-linux-2026-roadmap.mdx
new file mode 100644
index 00000000..770ca4f3
--- /dev/null
+++ b/content/blog/cx-linux-2026-roadmap.mdx
@@ -0,0 +1,101 @@
+---
+title: "CX Linux 2026 Roadmap: What's Coming Next"
+description: "Multi-agent workflows, a native GUI layer, fleet intelligence, and a plugin ecosystem. Here's everything we're building in 2026 and the reasoning behind each decision."
+publishedAt: "2026-04-10"
+author: "cx-team"
+tags: ["roadmap", "features", "announcement"]
+draft: false
+featured: true
+---
+
+import CxLinuxRoadmapImage from "@/blog/images/cx-linux-roadmap";
+
+
+
+We shipped CX Linux's first public version in late 2025. The response has pushed us to accelerate the roadmap significantly. Here's what we're building in 2026 — and more importantly, *why*.
+
+## Where We Are: v0.3
+
+The current release handles single-server operations well. You describe a task, CX generates and executes it with preview and rollback. That core loop works, and thousands of engineers use it daily.
+
+But the feedback has been consistent: teams want more. More collaboration. More automation. More intelligence about infrastructure state over time.
+
+## v0.4 · Multi-Agent Workflows (Q2 2026)
+
+The single biggest capability gap right now is long-horizon operations. "Deploy my entire application stack from scratch" requires 50+ commands across multiple services, with dependencies between them, error recovery paths, and conditional logic.
+
+No single LLM call handles this reliably. So v0.4 introduces **multi-agent workflows**: a planner agent that breaks operations into tasks, specialist agents that execute each task, and a coordinator that manages dependencies and error recovery.
+
+```bash
+# v0.4 preview
+cx workflow "deploy my full application: provision RDS, deploy ECS cluster, configure ALB, set up CloudFront, configure Route53, deploy application containers, run smoke tests"
+```
+
+Each step shows in a directed graph. You can approve the full workflow or step through it manually.
+
+
+Multi-agent mode is still cloud-only in v0.4. Local multi-agent support is planned for v0.5 with quantized model coordination.
+
+
+## v0.4 · Fleet Intelligence
+
+Fleet management in v0.3 is static: you target a group of servers and run a command. v0.4 introduces **fleet intelligence** — CX maintains a live model of your entire infrastructure.
+
+```bash
+# Ask questions about your fleet
+cx fleet "which servers are running outdated SSL certificates?"
+cx fleet "show me servers with disk usage above 80% that haven't been accessed in 30 days"
+cx fleet "what changed across my production fleet in the last 24 hours?"
+```
+
+This requires a lightweight agent running on each managed server that reports state changes to the CX coordinator. The agent uses less than 50MB of RAM and is fully open source.
+
+## v0.5 · Native GUI Layer (Q3 2026)
+
+CX has always been CLI-first, and that won't change. But we're building an optional native GUI for teams that need it — particularly for fleet visualization and workflow management.
+
+The GUI isn't a web console (we already have that). It's a native Linux application (GTK4/libadwaita) that gives you:
+
+- A live topology map of your infrastructure
+- Workflow builder with drag-and-drop task graph
+- Real-time log streaming from any managed server
+- Diff view for configuration changes before they apply
+
+The CLI and GUI share the same backend. Any operation you can do in the GUI, you can script with the CLI. They're two views of the same system.
+
+## v0.5 · Plugin Ecosystem
+
+The most-requested feature since launch: extensibility. v0.5 ships a plugin API that lets you build custom CX commands, custom agent types, and custom integrations.
+
+```bash
+# Install plugins from the CX registry
+cx plugin install kubernetes
+cx plugin install terraform
+cx plugin install datadog
+
+# Use them
+cx "scale my Kubernetes deployment to 5 replicas and verify rollout"
+cx "plan and apply my Terraform changes for the new VPC"
+```
+
+Plugins are TypeScript modules that declare their capabilities, required permissions, and LLM prompts. We'll open-source all first-party plugins as reference implementations.
+
+## v1.0 · General Availability (Q4 2026)
+
+The GA release is about stability, not new features. Three things:
+
+1. **API stability** — all CLI commands and plugin APIs are locked until v2
+2. **Compliance certifications** — SOC 2 Type II, completing the enterprise security requirements
+3. **SLA guarantees** — 99.9% uptime for cloud API and fleet coordination service
+
+## What We're Not Building
+
+Equally important is what's not on the roadmap:
+
+- **A new Linux distribution** — CX runs *on* your distro, it doesn't replace it
+- **A CI/CD platform** — CX complements GitHub Actions/GitLab CI, it doesn't compete
+- **An infrastructure-as-code tool** — Terraform and Pulumi are better at declarative infrastructure
+
+CX is an operations layer. We're going deep, not wide.
+
+[Follow our progress on GitHub →](https://github.com/cxlinux-ai/cx-core)
diff --git a/content/blog/cx-vs-warp-copilot-cli.mdx b/content/blog/cx-vs-warp-copilot-cli.mdx
new file mode 100644
index 00000000..51915412
--- /dev/null
+++ b/content/blog/cx-vs-warp-copilot-cli.mdx
@@ -0,0 +1,79 @@
+---
+title: "CX Linux vs Warp vs Copilot CLI: Who Wins?"
+description: "Three AI-powered terminal tools, three very different approaches. We compare CX Linux, Warp, and GitHub Copilot CLI across execution, context, safety, and real-world use cases."
+publishedAt: "2026-03-15"
+author: "cx-team"
+tags: ["comparison", "AI", "DevOps"]
+draft: false
+featured: false
+---
+
+import CxVsWarpImage from "@/blog/images/cx-vs-warp";
+
+
+
+The AI terminal tool landscape has exploded. If you're evaluating CX Linux, Warp, and GitHub Copilot CLI, you've probably noticed that they all claim to "use AI to help you with Linux." But they solve fundamentally different problems in fundamentally different ways.
+
+Here's the honest comparison.
+
+## What Each Tool Actually Does
+
+| | CX Linux | Warp | GitHub Copilot CLI |
+|---|---|---|---|
+| **Type** | OS-level AI layer | AI-enhanced terminal emulator | Command suggestion tool |
+| **Execution** | Generates + executes | You execute manually | Suggests, you execute |
+| **System context** | Full OS awareness | Shell history only | None |
+| **Safety** | Sandbox + preview + rollback | None | None |
+| **Multi-step workflows** | Yes, orchestrated | No | No |
+| **Works offline** | Yes (local LLM) | No | No |
+| **Price** | Free tier available | Free + paid | Requires Copilot subscription |
+
+## CX Linux: OS-Level Execution
+
+CX operates at a fundamentally different level than the other two tools. It's not a terminal emulator. It's not a CLI wrapper. It's a daemon with OS-wide awareness that can:
+
+- Detect your installed software, running services, open ports, and hardware
+- Generate multi-step workflows that span multiple commands
+- Execute those workflows in a sandbox with rollback capability
+
+
+
+The key word is *execute*. CX doesn't just tell you what to do. It does it for you — with your approval at each step.
+
+**Best for:** Anyone who manages Linux systems and wants to stop being an intermediary between what they need done and the commands that do it.
+
+## Warp: The Best Terminal Emulator with AI
+
+Warp is, genuinely, the best terminal emulator available today. The AI features help you autocomplete commands, explain errors, and search your history intelligently. The UI is excellent.
+
+But Warp's AI is advisory. When you ask Warp's AI to "set up nginx with SSL," it generates a command and pastes it into the input field. You run it. If it fails, you ask again. There's no system context, no awareness of what's already installed, and no safety layer.
+
+
+Warp and CX Linux are not mutually exclusive. Many CX users run CX through Warp's terminal. They complement each other well.
+
+
+**Best for:** Developers who want a beautiful, fast terminal with smart autocomplete and don't need AI-driven execution.
+
+## GitHub Copilot CLI: Smart Suggestions, Nothing More
+
+Copilot CLI (`gh copilot suggest`) translates natural language into shell commands. It's useful for remembering the syntax of obscure flags or one-liners you haven't used in a while.
+
+What it can't do: understand your system state, chain multi-step operations, execute anything, or recover from errors. It generates a suggestion — what you do with it is entirely up to you.
+
+**Best for:** Developers who already know Linux well and occasionally need to look up command syntax.
+
+## The Verdict
+
+If you need a tool that *does things* on your Linux system — not just suggests them — CX Linux is the only option in this comparison. The OS-level context, multi-step execution, and safety model are unique.
+
+If you want the most polished terminal UI, Warp is the clear winner in that category.
+
+If you want quick command lookup inside GitHub's ecosystem, Copilot CLI does that job.
+
+They're not really competing. They solve different problems at different levels of the stack. Use the right tool for the right job — or use all three.
+
+[Try CX Linux free →](/getting-started)
diff --git a/content/blog/devops-guide-cx-linux.mdx b/content/blog/devops-guide-cx-linux.mdx
new file mode 100644
index 00000000..fc29f8a8
--- /dev/null
+++ b/content/blog/devops-guide-cx-linux.mdx
@@ -0,0 +1,94 @@
+---
+title: "The DevOps Engineer's Guide to CX Linux"
+description: "How DevOps engineers are using CX Linux to automate server provisioning, CI/CD setup, monitoring, and incident response — with real command examples for each workflow."
+publishedAt: "2026-03-20"
+author: "cx-team"
+tags: ["DevOps", "tutorial", "automation"]
+draft: false
+featured: false
+ogImage: "https://images.unsplash.com/photo-1518432031352-d6fc5c10da5a?auto=format&fit=crop&w=1200&h=630&q=80"
+---
+
+DevOps engineering is fundamentally about reducing the gap between intention and infrastructure state. You know what the system should look like. Getting it there involves a hundred small decisions, lookups, and commands.
+
+CX Linux collapses that gap. Here's how to integrate it into a real DevOps workflow.
+
+## Server Provisioning in Minutes
+
+Provisioning a new server used to mean a playbook, an Ansible role, or a long runbook. With CX, you describe the desired end state:
+
+
+
+CX generates the full provisioning sequence in the correct order, with dependency resolution. Installing nginx before configuring it. Setting up the firewall *after* verifying SSH access won't be blocked.
+
+## CI/CD Pipeline Setup
+
+
+CX integrates with GitHub Actions, GitLab CI, and Jenkins. It can generate pipeline configs from a description of your deployment workflow.
+
+
+```bash
+cx "set up a GitHub Actions pipeline that: runs tests on every PR, deploys to staging on merge to develop, deploys to production on merge to main — with manual approval gate before production"
+```
+
+CX generates the complete `.github/workflows/` directory with staging and production workflows, environment protection rules, and notification hooks.
+
+## Zero-Downtime Deployments
+
+The hardest part of deployment automation isn't writing the script — it's handling the edge cases. What if the health check fails? What if the database migration takes too long? CX handles these patterns:
+
+```bash
+cx "deploy my Dockerized app with blue-green strategy — health check every 10s, auto-rollback if health check fails 3 times, keep old container running until new one is healthy"
+```
+
+## Incident Response
+
+When something breaks at 3am, you don't want to be googling commands. CX turns incident response into a guided workflow:
+
+
+
+CX reads the system state, traces the error chain, and presents you with a root-cause diagnosis and a fix — not a list of commands to try.
+
+## Infrastructure Auditing
+
+Security audits and compliance checks are tedious when done manually. CX automates the investigation:
+
+```bash
+cx "audit this server for CIS Benchmark Level 1 compliance — list all failures and generate remediation commands"
+```
+
+```bash
+cx "find all world-writable files, SUID binaries not in the expected set, and listening ports that shouldn't be open — report with risk level"
+```
+
+## Fleet Management with CX Pro
+
+CX Pro and Team plans include fleet management — run operations across multiple servers with a single command:
+
+```bash
+# Apply security patches to all staging servers
+cx fleet "apt upgrade -y security packages" --target staging
+
+# Check disk usage across all production servers
+cx fleet "disk usage summary" --target production --format table
+```
+
+
+Fleet commands go through the same preview + approval flow as single-server commands. You see the full plan across all targets before anything runs.
+
+
+## Integrating CX into Your Existing Stack
+
+CX isn't a replacement for Terraform, Ansible, or Kubernetes. It's a complement — an AI layer that handles the ad-hoc operations and day-two maintenance that automation tools aren't designed for.
+
+Think of it as the difference between infrastructure-as-code (declarative, reproducible) and operations-as-intent (imperative, adaptive). Both are necessary.
+
+[See CX Linux pricing for teams →](/pricing)
diff --git a/content/blog/how-we-built-cx.mdx b/content/blog/how-we-built-cx.mdx
new file mode 100644
index 00000000..8e575e5e
--- /dev/null
+++ b/content/blog/how-we-built-cx.mdx
@@ -0,0 +1,108 @@
+---
+title: "How We Built CX: Architecture of an AI-Native OS Layer"
+description: "The technical decisions behind CX Linux — from the NLP layer to the sandbox runtime, LLM selection, and why we chose to build an OS layer instead of a terminal wrapper."
+publishedAt: "2026-04-15"
+author: "cx-team"
+tags: ["engineering", "architecture", "AI"]
+draft: false
+featured: false
+---
+
+import HowWeBuiltCxImage from "@/blog/images/how-we-built-cx";
+
+
+
+When we started building CX, the obvious approach was to wrap a shell: intercept terminal input, pass it to an LLM, insert the generated command. Half the "AI terminal" tools on the market work this way.
+
+We decided not to do that. Here's why, and what we built instead.
+
+## The Problem with Terminal Wrappers
+
+A terminal wrapper sees what you type and what the terminal outputs. That's it. It has no idea what's already installed, what's running, what ports are open, or what the system's health is.
+
+When you ask a terminal wrapper to "set up nginx," it generates a generic `apt install nginx` and an nginx config that may or may not be right for your system. If nginx is already installed but misconfigured, it doesn't know. If port 80 is already in use, it doesn't know. If your Ubuntu version requires a different package name, it doesn't know.
+
+We wanted CX to know all of that before generating a single command.
+
+## The System Context Layer
+
+The foundation of CX is a system context collector — a lightweight process that maintains a real-time model of the system:
+
+- **Package state:** installed packages, versions, available updates
+- **Service state:** running services, their configs, resource usage
+- **Network state:** open ports, firewall rules, active connections
+- **Hardware:** CPU, RAM, GPU, storage, performance characteristics
+- **History:** recent CX operations, their outcomes, rollback points
+
+This context is injected into every LLM prompt. When you ask CX to "configure nginx," the model already knows your nginx version, your current config, what's running on which ports, and your hardware constraints.
+
+```bash
+# You can inspect the context CX has about your system
+cx context show
+
+# Or query specific aspects
+cx context show --network
+cx context show --services nginx
+```
+
+## Why We Chose Firejail for Sandboxing
+
+We evaluated several sandboxing options: Docker (too heavy, needs a daemon), bubblewrap (not available everywhere), nsjail (complex), and Firejail (lightweight, widely available, good seccomp support).
+
+Firejail won because it's already installed on most Debian/Ubuntu systems, adds less than 100ms of overhead, and gives us the isolation primitives we need: filesystem namespaces, network namespaces, process isolation, and seccomp filtering.
+
+
+For operations that require network access (package installs, API calls), CX uses Firejail's `--netfilter` option to restrict network access to specific hosts rather than blocking it entirely.
+
+
+## The Snapshot System
+
+Rollback was a late addition to the design, and it's now one of the most-used features. The implementation is simpler than you'd expect:
+
+For each operation, CX identifies which files will be modified. Before execution, it creates a content-addressed snapshot of those files. The snapshot metadata (file paths, content hashes, timestamps) is stored in `~/.cx/snapshots/`.
+
+Restoring is just copying files back. No btrfs, no LVM, no filesystem magic required.
+
+```bash
+# The snapshot format is intentionally simple
+cat ~/.cx/snapshots/2026-04-15T14:32:00.json
+{
+ "id": "snap_20260415143200",
+ "operation": "install nginx + SSL",
+ "modified_files": ["/etc/nginx/sites-available/default", "/etc/cron.d/certbot"],
+ "created_at": "2026-04-15T14:32:00Z"
+}
+```
+
+## LLM Selection: Why We Support Multiple Providers
+
+We built multi-provider LLM support from day one for two reasons:
+
+1. **Model quality changes fast.** The best model today won't be the best model in six months. Providers are changing monthly. We didn't want to bet on one.
+
+2. **Different operations need different capabilities.** Simple package installs work fine with Mistral 7B. Complex multi-service orchestration benefits from Claude's reasoning. Hybrid mode routes accordingly.
+
+The LLM abstraction layer uses a simple capability rating system — each registered provider declares its ratings for reasoning, code generation, speed, and cost. The hybrid mode router uses these ratings to select the provider for each operation type.
+
+## What We'd Do Differently
+
+Three things we'd change if we were starting today:
+
+1. **Build the plugin API earlier.** We shipped plugins in v0.5. We should have designed for extensibility from v0.1. The refactor was painful.
+
+2. **Invest in the test harness sooner.** Testing AI-generated command execution is hard. We built a mock execution environment eventually, but we shipped with less coverage than we should have.
+
+3. **Fleet management from the start.** We added fleet support as a feature on top of single-server architecture. A fleet-native design would have been cleaner.
+
+## The Stack
+
+For the curious:
+
+- **CLI:** Go (fast startup, single binary, great for system tooling)
+- **Context collector:** Rust (performance-critical, runs continuously)
+- **Web console:** React + TypeScript (same stack as this site)
+- **Fleet coordinator:** Go + gRPC
+- **LLM abstraction:** Go interfaces with provider plugins
+- **Sandbox:** Firejail (not written by us)
+
+All open source at [github.com/cxlinux-ai/cx-core](https://github.com/cxlinux-ai/cx-core).
diff --git a/content/blog/linux-tasks-30-seconds.mdx b/content/blog/linux-tasks-30-seconds.mdx
new file mode 100644
index 00000000..902cd42f
--- /dev/null
+++ b/content/blog/linux-tasks-30-seconds.mdx
@@ -0,0 +1,84 @@
+---
+title: "5 Linux Tasks Done in 30 Seconds with CX"
+description: "Setting up nginx, configuring firewalls, deploying Docker stacks — these tasks eat hours. Here's how CX Linux turns each one into a single natural language command."
+publishedAt: "2026-03-11"
+author: "cx-team"
+tags: ["tutorial", "productivity", "DevOps"]
+draft: false
+featured: false
+ogImage: "https://images.unsplash.com/photo-1629654297299-c8506221ca97?auto=format&fit=crop&w=1200&h=630&q=80"
+---
+
+Every sysadmin knows the drill. You need to set up a reverse proxy, so you open three browser tabs — one for the nginx docs, one for Stack Overflow, one for that blog post you bookmarked six months ago. Forty-five minutes later, you've got a working config. Maybe.
+
+CX Linux changes this equation entirely. Here are five real tasks that used to take 30+ minutes, now done in under 30 seconds.
+
+## 1. Set Up an Nginx Reverse Proxy with SSL
+
+**The old way:** Install nginx, write the config, install certbot, generate certificates, configure renewal, test, debug, restart. Repeat twice because you got the server block wrong.
+
+
+
+CX detects your system state, installs what's needed, generates the config, obtains the SSL certificate, and sets up auto-renewal. You review the commands, approve, and it's done.
+
+## 2. Harden SSH and Configure a Firewall
+
+**The old way:** Edit `sshd_config` (and hope you don't lock yourself out), install ufw, figure out which ports to open, test from another session before closing the current one.
+
+```bash
+cx "harden SSH: disable root login, key-only auth, change port to 2222 — then set up ufw allowing only SSH on 2222, HTTP, and HTTPS"
+```
+
+CX handles the full sequence in the right order: backup the current config, apply hardening changes, configure firewall rules, verify connectivity *before* restarting the SSH daemon, and create a rollback point in case anything goes wrong.
+
+
+CX automatically verifies that your new SSH config is valid and that you won't lose access before applying changes. This is the check that trips up manual configuration most often.
+
+
+## 3. Deploy a Full Docker Stack
+
+**The old way:** Install Docker, write `docker-compose.yml`, configure volumes, set up networking, figure out environment variables, debug port conflicts.
+
+
+
+CX generates the compose file with production-safe defaults, configures Traefik with automatic SSL via ACME, and sets up persistent volumes with the correct permissions.
+
+## 4. Set Up Automated Backups to S3
+
+**The old way:** Write a bash script, configure AWS CLI, set up cron jobs, handle errors, test restoration (usually skipped), pray.
+
+```bash
+cx "set up daily backups of /var/www and my PostgreSQL databases to S3 bucket my-backups — 30 days retention, AES-256 encryption, email alert on failure"
+```
+
+CX creates the backup scripts, configures server-side encryption, sets up the cron schedule with proper error handling, and includes a test restoration step to verify the backup actually works before you need it.
+
+## 5. Monitor System Health with Alerts
+
+**The old way:** Install Prometheus, configure exporters for each service, set up Grafana, write alert rules in PromQL, configure notification channels. Half a day minimum.
+
+
+
+CX sets up lightweight monitoring with sensible thresholds, configures alerting via email or Slack, and gives you a minimal status dashboard — without the full Prometheus/Grafana operational complexity.
+
+## The Pattern Behind All of These
+
+Every one of these tasks follows the same frustrating cycle: research → configure → test → debug → repeat. CX collapses it into: **describe → review → approve**.
+
+The AI handles the research and configuration. You keep full control with command preview and instant rollback. The result is that a single DevOps engineer can operate infrastructure that would previously have required an entire ops team's institutional knowledge.
+
+[Try CX Linux free →](/getting-started)
diff --git a/content/blog/local-vs-cloud-llm.mdx b/content/blog/local-vs-cloud-llm.mdx
new file mode 100644
index 00000000..19b9a8ba
--- /dev/null
+++ b/content/blog/local-vs-cloud-llm.mdx
@@ -0,0 +1,123 @@
+---
+title: "Local LLMs vs Cloud LLMs in CX: A Practical Guide"
+description: "CX Linux supports both local and cloud LLMs. This guide explains the real-world tradeoffs — privacy, cost, performance, and when to use each — with benchmarks."
+publishedAt: "2026-04-01"
+author: "cx-team"
+tags: ["AI", "LLM", "configuration"]
+draft: false
+featured: false
+---
+
+import LocalVsCloudLlmImage from "@/blog/images/local-vs-cloud-llm";
+
+
+
+One of CX Linux's defining features is flexibility in how it thinks. You can route CX's AI reasoning through a cloud API (Claude, GPT-4o, any OpenAI-compatible endpoint) or through a local LLM running on your own hardware. Here's everything you need to know to make the right choice.
+
+## The Three Modes
+
+CX supports three LLM modes, configurable per session or globally:
+
+| Mode | How it works | Best for |
+|---|---|---|
+| `cloud` | Calls Claude or GPT-4o via API | Most users — easiest setup, best results |
+| `local` | Runs Mistral 7B via Ollama on your GPU | Privacy-sensitive workloads, air-gapped systems |
+| `hybrid` | Uses local for simple commands, cloud for complex reasoning | Cost optimization at scale |
+
+```bash
+# Switch modes
+cx config set llm.provider cloud # default
+cx config set llm.provider local
+cx config set llm.provider hybrid
+
+# Override per-command
+cx --local "list all running services"
+cx --cloud "diagnose this intermittent networking issue"
+```
+
+## Cloud LLMs: The Default for Good Reason
+
+Cloud mode uses the strongest available models. As of 2026, that means Claude Sonnet or GPT-4o — models with broad world knowledge, strong reasoning, and excellent code generation.
+
+**Advantages:**
+- State-of-the-art reasoning for complex, multi-step operations
+- No GPU required — works on any machine with internet
+- Regular model updates without any action on your part
+- Fastest time to first result for complex commands
+
+**Tradeoffs:**
+- Requires internet connectivity
+- Per-request API cost (typically $0.002–$0.008 per CX operation)
+- Command context is sent to the cloud provider
+
+
+CX only sends the relevant context for each command — not your entire filesystem or environment. The exact data sent is shown in the preview before any command executes. Review CX's [privacy policy](/privacy) for full details.
+
+
+## Local LLMs: Full Privacy, Zero Cost
+
+Local mode runs Mistral 7B (or your custom model) entirely on your hardware via Ollama. Nothing leaves your machine.
+
+**Advantages:**
+- Complete data privacy — no external API calls
+- Zero marginal cost after initial setup
+- Works fully offline and in air-gapped environments
+- Fast for simple, well-scoped commands
+
+**Requirements:**
+- NVIDIA GPU with 8GB+ VRAM (RTX 3060 or better)
+- Or AMD GPU with ROCm support
+- 16GB+ system RAM recommended
+
+**Tradeoffs:**
+- Mistral 7B is meaningfully less capable than Claude/GPT-4o for complex reasoning
+- Slower for long, multi-step operations
+- Requires initial setup (CX handles this automatically)
+
+### Setting Up Local Mode
+
+```bash
+# CX installs Ollama and pulls the model automatically
+cx "install Ollama with Mistral 7B and configure CX to use local mode"
+
+# Or manually
+cx config set llm.provider local
+cx config set llm.local.model mistral:7b
+```
+
+## Performance Benchmarks
+
+We benchmarked cloud vs local across five common operation types:
+
+| Operation type | Cloud (Claude) | Local (Mistral 7B) |
+|---|---|---|
+| Simple package install | ★★★★★ | ★★★★☆ |
+| Nginx + SSL setup | ★★★★★ | ★★★★☆ |
+| Multi-service Docker stack | ★★★★★ | ★★★☆☆ |
+| Complex security audit | ★★★★★ | ★★★☆☆ |
+| Shell script generation | ★★★★★ | ★★★★☆ |
+
+Local mode handles roughly 80% of common operations well. For complex reasoning tasks — diagnosing intermittent issues, multi-system orchestration, security audits — cloud mode produces significantly better results.
+
+## Hybrid Mode: The Smart Default for Teams
+
+Hybrid mode routes commands based on complexity. Simple operations (package installs, service restarts, file operations) go local. Complex operations (multi-step deployments, incident diagnosis, security audits) go to the cloud.
+
+```bash
+cx config set llm.provider hybrid
+cx config set llm.hybrid.threshold medium # low | medium | high
+```
+
+At medium threshold, roughly 60% of operations run locally — reducing API costs significantly while maintaining quality where it matters.
+
+## Choosing the Right Configuration
+
+| Your situation | Recommended mode |
+|---|---|
+| Personal use, standard hardware | Cloud (simplest) |
+| Handling sensitive/regulated data | Local or Hybrid |
+| Air-gapped or offline environment | Local |
+| High-volume team usage | Hybrid |
+| Maximum quality regardless of cost | Cloud |
+
+[Configure your CX LLM settings →](/getting-started)
diff --git a/content/blog/multi-server-fleet-management.mdx b/content/blog/multi-server-fleet-management.mdx
new file mode 100644
index 00000000..68ad0537
--- /dev/null
+++ b/content/blog/multi-server-fleet-management.mdx
@@ -0,0 +1,118 @@
+---
+title: "Managing a Multi-Server Fleet with CX Linux"
+description: "How to use CX Linux Pro and Team plans to manage dozens of servers with a single command — patching, auditing, deploying, and monitoring across your entire fleet."
+publishedAt: "2026-04-05"
+author: "cx-team"
+tags: ["DevOps", "fleet", "tutorial"]
+draft: false
+featured: false
+ogImage: "https://images.unsplash.com/photo-1558494949-ef010cbdcc31?auto=format&fit=crop&w=1200&h=630&q=80"
+---
+
+Managing one server with CX is straightforward. The real power shows when you're running operations across a fleet of 10, 50, or 500 servers. Here's how CX Pro and Team plans handle fleet operations.
+
+## Setting Up Fleet Management
+
+First, install the CX agent on each server:
+
+```bash
+# On each server you want to manage
+curl -fsSL https://cxlinux.com/install.sh | bash
+cx agent start --coordinator your-coordinator-url --token $FLEET_TOKEN
+```
+
+Then register servers in your fleet:
+
+```bash
+# On your local machine
+cx fleet add server-01.prod.internal --group production --tags nginx,app
+cx fleet add server-02.prod.internal --group production --tags nginx,app
+cx fleet add db-01.prod.internal --group production --tags postgres
+cx fleet add staging-01.internal --group staging
+```
+
+
+
+## Mass Security Patching
+
+The most common fleet operation is applying security updates:
+
+```bash
+# Preview what would be updated across all servers
+cx fleet "show pending security patches" --target production
+
+# Apply security patches with rolling restart
+cx fleet "apply all pending security patches — rolling update, 2 servers at a time, health check between batches" --target production
+```
+
+CX handles the rolling update logic automatically: patches 2 servers, waits for health checks to pass, patches the next 2, and so on. If health checks fail, the rollout pauses and alerts you.
+
+
+Always preview fleet operations before approving. The `--dry-run` flag shows you exactly what would happen on each server without executing anything.
+
+
+## Fleet-Wide Auditing
+
+```bash
+# Security audit across all production servers
+cx fleet "check for: outdated packages with CVEs, world-writable files outside /tmp, listening ports that shouldn't be open, SSH root login enabled"
+
+# Compliance check
+cx fleet "verify all servers meet CIS Benchmark Level 1 — list failures per server"
+```
+
+CX aggregates the results into a unified report, grouping findings by severity and server.
+
+## Configuration Drift Detection
+
+One of the hardest problems in fleet management is configuration drift — servers that were identical when provisioned but have diverged over time.
+
+```bash
+# Find servers that differ from the baseline
+cx fleet diff --baseline server-01.prod.internal --target production
+
+# Output shows what's different on each server:
+# server-03: nginx version mismatch (1.24.0 vs 1.26.1)
+# server-07: unexpected package installed: redis-server
+# server-08: firewall rule differs from baseline
+```
+
+## Deploying Application Updates
+
+```bash
+# Deploy new app version with blue-green on all app servers
+cx fleet "deploy app version 2.4.1 from registry.mycompany.com/app:2.4.1 — blue-green deployment, health check /health, auto-rollback if error rate > 1%" --target production --group app
+```
+
+CX coordinates the deployment across servers, maintaining a minimum number of healthy instances throughout.
+
+## Emergency Response
+
+When something goes wrong across your fleet:
+
+
+
+CX narrows down the affected servers and identifies the root cause before you've opened a single SSH session.
+
+## Cost and Plan Details
+
+Fleet management is available on CX Pro (up to 5 servers), CX Team (up to 25 servers), and CX Enterprise (unlimited). Each managed server requires one seat.
+
+[See fleet management pricing →](/pricing)
diff --git a/content/blog/sandboxed-execution-safety.mdx b/content/blog/sandboxed-execution-safety.mdx
new file mode 100644
index 00000000..7c40eecf
--- /dev/null
+++ b/content/blog/sandboxed-execution-safety.mdx
@@ -0,0 +1,97 @@
+---
+title: "How CX Linux Keeps Your System Safe"
+description: "Running AI-generated commands on your production system sounds risky. Here's exactly how CX Linux uses sandboxing, command preview, and instant rollback to make it safe."
+publishedAt: "2026-03-08"
+author: "cx-team"
+tags: ["security", "sandboxing", "safety"]
+draft: false
+featured: false
+---
+
+import SandboxedExecutionImage from "@/blog/images/sandboxed-execution";
+
+
+
+The number one question we get: *"What if CX runs something destructive?"*
+
+It's the right question. Giving an AI access to your Linux system without safety rails would be reckless. So before we wrote a single line of CX's execution engine, we designed the safety model. Here's exactly how it works.
+
+## Three Independent Safety Layers
+
+CX doesn't rely on a single safety mechanism. It uses three independent layers, each of which must be satisfied before any command touches your system.
+
+### Layer 1: Command Preview
+
+Every command CX generates is displayed in a structured preview before execution. You see:
+
+- The exact command that will run
+- Which files or directories it will affect
+- What permissions it requires
+- A plain-English explanation of what it does
+
+Nothing executes until you explicitly approve. This isn't optional — there is no "just run it" mode.
+
+### Layer 2: Firejail Sandbox
+
+When you approve a command, it runs inside a Firejail container with:
+
+- **Limited filesystem access** — only the directories explicitly needed
+- **Restricted network** — no network access unless the command requires it
+- **Process isolation** — the command can't see or signal other processes
+- **Automatic timeout** — runaway processes are killed after a configurable limit
+
+```bash
+# CX wraps every approved command internally like this:
+firejail --private-tmp --net=none --noroot
+```
+
+
+Firejail is an open-source SUID sandbox that uses Linux namespaces and seccomp to isolate processes. It's the same technology used to sandbox browsers and media players.
+
+
+### Layer 3: Snapshot and Instant Rollback
+
+Before any command that modifies system state, CX creates a snapshot of the affected files and configuration. This happens automatically — you don't need to think about it.
+
+If something goes wrong, one command undoes everything:
+
+```bash
+cx rollback
+```
+
+You can also view the full rollback history and selectively restore specific snapshots:
+
+```bash
+cx rollback --list
+cx rollback --id
+```
+
+## Dangerous Command Blocking
+
+CX maintains a blocklist of destructive command patterns. These are flagged automatically:
+
+- `rm -rf` on system directories
+- `dd` writing to block devices
+- Commands that modify boot configuration
+- Privilege escalation without an explicit reason
+- Mass file operations on `/`, `/etc`, `/boot`
+
+When a blocked pattern is detected, CX requires you to explicitly acknowledge the risk with a confirmation phrase — not just press `y`.
+
+## Open Source Security Model
+
+Our entire safety model is open source. You can audit every line of code that touches your system at [github.com/cxlinux-ai/cx-core](https://github.com/cxlinux-ai/cx-core).
+
+We believe security through obscurity is no security at all. The more eyes on the code, the safer everyone is.
+
+
+Enterprise and Team plan users get additional audit logging: every command executed through CX is logged with timestamp, user, and session context. These logs are immutable and can be exported for compliance reporting.
+
+
+## What This Means in Practice
+
+In over a year of production use, the safety model has prevented hundreds of potentially destructive operations — not from CX generating bad commands, but from users who pasted the wrong thing, ran the right command in the wrong directory, or didn't notice a typo in a path.
+
+The preview + sandbox + rollback combination means that even if the worst happens, you're one command away from recovery.
+
+[Read the full security documentation →](/faq)
diff --git a/content/blog/what-is-cx-linux.mdx b/content/blog/what-is-cx-linux.mdx
new file mode 100644
index 00000000..d515fb44
--- /dev/null
+++ b/content/blog/what-is-cx-linux.mdx
@@ -0,0 +1,84 @@
+---
+title: "What Is CX Linux? The AI Layer for Linux"
+description: "CX Linux is not just another distro. It's an AI layer that sits on top of any Debian or Ubuntu system and lets you control Linux with natural language. Here's how it works."
+publishedAt: "2026-03-10"
+author: "cx-team"
+tags: ["introduction", "AI", "Linux"]
+draft: false
+featured: true
+---
+
+import WhatIsCxLinuxImage from "@/blog/images/what-is-cx-linux";
+
+
+
+If you've ever spent an afternoon searching Stack Overflow for the right nginx config, or lost an hour to a failed package dependency chain — you know the hidden tax of working with Linux. The commands are powerful. The knowledge required to use them well takes years.
+
+CX Linux was built to change that equation.
+
+## What CX Linux Actually Is
+
+CX Linux is not a new distribution. It doesn't replace your OS. It's an **AI layer** — a daemon that runs alongside any Debian or Ubuntu system and intercepts your intent before you ever have to look up a command.
+
+You describe what you want. CX figures out how to get there.
+
+
+
+The key difference from every other AI terminal tool: CX operates **at the OS level**. It has full awareness of your hardware, installed packages, running services, active ports, and system configuration. It doesn't generate a generic answer — it generates the exact right answer *for your machine, right now*.
+
+## The Three Pillars
+
+### 1. Intent-Based Execution
+
+Instead of remembering commands, you describe outcomes. CX handles the translation from English to Linux. Multi-step operations that would normally require a checklist of ten commands become a single natural language request.
+
+### 2. Command Preview + Approval
+
+CX never runs anything without showing you first. Every generated command appears in a diff-style preview. You review, approve, and only then does anything execute. This isn't just a safety feature — it's how you learn. Over time, you internalize the patterns.
+
+
+CX runs every approved command inside a Firejail container with limited filesystem access, restricted network, and process isolation. Nothing can escape the sandbox.
+
+
+### 3. Instant Rollback
+
+Before any system modification, CX snapshots the affected state. If something goes wrong — or you simply change your mind — one command reverts everything:
+
+```bash
+cx rollback
+```
+
+No manual backups. No "I hope I remember what I changed." Just a clean undo.
+
+## Who Is CX For?
+
+CX is purpose-built for people who work with Linux every day:
+
+- **Developers** setting up local environments, managing Docker stacks, configuring databases
+- **DevOps engineers** provisioning servers, configuring CI/CD, hardening security
+- **Sysadmins** managing fleets, automating maintenance, auditing configurations
+- **AI/ML engineers** setting up GPU drivers, Ollama, Python environments, CUDA toolchains
+
+If you've ever felt like Linux makes you work *for it* instead of the other way around, CX Linux is for you.
+
+## How It's Different from a Chatbot or Terminal Wrapper
+
+Other tools generate suggestions. CX generates and executes — with context.
+
+When you ask CX to set up a web server, it checks what's already installed, detects your current nginx config, identifies port conflicts, and produces commands that are guaranteed to work on *your specific system*. It's the difference between a recommendation and a solution.
+
+## Getting Started in 5 Minutes
+
+CX installs on any Debian or Ubuntu system with a single command:
+
+```bash
+curl -fsSL https://cxlinux.com/install.sh | bash
+```
+
+The free Community edition gives you local LLM support (Mistral 7B), full CLI access, and unlimited personal use on a single machine. No credit card required.
+
+[Get started with CX Linux →](/getting-started)
diff --git a/package-lock.json b/package-lock.json
index 6b383045..2bfc5cb0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,9 @@
"version": "1.0.0",
"license": "BSL-1.1",
"dependencies": {
+ "@fontsource/inter": "^5.2.8",
+ "@mdx-js/react": "^3.1.1",
+ "@mdx-js/rollup": "^3.1.1",
"@neondatabase/serverless": "^0.10.4",
"@radix-ui/react-accordion": "^1.2.4",
"@radix-ui/react-alert-dialog": "^1.1.7",
@@ -37,6 +40,8 @@
"@radix-ui/react-toggle": "^1.1.3",
"@radix-ui/react-toggle-group": "^1.1.3",
"@radix-ui/react-tooltip": "^1.2.0",
+ "@resvg/resvg-js": "^2.6.2",
+ "@shikijs/rehype": "^4.0.2",
"@tanstack/react-query": "^5.60.5",
"@types/express-rate-limit": "^5.1.3",
"class-variance-authority": "^0.7.1",
@@ -48,7 +53,10 @@
"embla-carousel-react": "^8.6.0",
"express": "^4.21.2",
"express-rate-limit": "^8.2.1",
+ "feed": "^5.2.1",
"framer-motion": "^11.13.1",
+ "glob": "^13.0.6",
+ "gray-matter": "^4.0.3",
"helmet": "^8.1.0",
"input-otp": "^1.4.2",
"lucide-react": "^0.453.0",
@@ -59,8 +67,14 @@
"react-hook-form": "^7.55.0",
"react-icons": "^5.4.0",
"react-resizable-panels": "^2.1.7",
+ "reading-time": "^1.5.0",
"recharts": "^2.15.2",
+ "rehype-autolink-headings": "^7.1.0",
+ "rehype-slug": "^6.0.0",
+ "remark-gfm": "^4.0.1",
"resend": "^6.7.0",
+ "satori": "^0.26.0",
+ "shiki": "^4.0.2",
"stripe": "^20.1.2",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
@@ -76,6 +90,7 @@
"@tailwindcss/typography": "^0.5.15",
"@tailwindcss/vite": "^4.1.3",
"@types/express": "4.17.21",
+ "@types/mdx": "^2.0.13",
"@types/node": "20.16.11",
"@types/pdfkit": "^0.13.9",
"@types/react": "^18.3.11",
@@ -1321,6 +1336,15 @@
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
"license": "MIT"
},
+ "node_modules/@fontsource/inter": {
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz",
+ "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==",
+ "license": "OFL-1.1",
+ "funding": {
+ "url": "https://github.com/sponsors/ayuhito"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -1367,6 +1391,97 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@mdx-js/mdx": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz",
+ "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/mdx": "^2.0.0",
+ "acorn": "^8.0.0",
+ "collapse-white-space": "^2.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-is-identifier-name": "^3.0.0",
+ "estree-util-scope": "^1.0.0",
+ "estree-walker": "^3.0.0",
+ "hast-util-to-jsx-runtime": "^2.0.0",
+ "markdown-extensions": "^2.0.0",
+ "recma-build-jsx": "^1.0.0",
+ "recma-jsx": "^1.0.0",
+ "recma-stringify": "^1.0.0",
+ "rehype-recma": "^1.0.0",
+ "remark-mdx": "^3.0.0",
+ "remark-parse": "^11.0.0",
+ "remark-rehype": "^11.0.0",
+ "source-map": "^0.7.0",
+ "unified": "^11.0.0",
+ "unist-util-position-from-estree": "^2.0.0",
+ "unist-util-stringify-position": "^4.0.0",
+ "unist-util-visit": "^5.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/@mdx-js/mdx/node_modules/source-map": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/@mdx-js/react": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz",
+ "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdx": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ },
+ "peerDependencies": {
+ "@types/react": ">=16",
+ "react": ">=16"
+ }
+ },
+ "node_modules/@mdx-js/rollup": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@mdx-js/rollup/-/rollup-3.1.1.tgz",
+ "integrity": "sha512-v8satFmBB+DqDzYohnm1u2JOvxx6Hl3pUvqzJvfs2Zk/ngZ1aRUhsWpXvwPkNeGN9c2NCm/38H29ZqXQUjf8dw==",
+ "license": "MIT",
+ "dependencies": {
+ "@mdx-js/mdx": "^3.0.0",
+ "@rollup/pluginutils": "^5.0.0",
+ "source-map": "^0.7.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ },
+ "peerDependencies": {
+ "rollup": ">=2"
+ }
+ },
+ "node_modules/@mdx-js/rollup/node_modules/source-map": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/@neondatabase/serverless": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/@neondatabase/serverless/-/serverless-0.10.4.tgz",
@@ -3082,6 +3197,233 @@
"@jridgewell/trace-mapping": "^0.3.25"
}
},
+ "node_modules/@resvg/resvg-js": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.6.2.tgz",
+ "integrity": "sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==",
+ "license": "MPL-2.0",
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@resvg/resvg-js-android-arm-eabi": "2.6.2",
+ "@resvg/resvg-js-android-arm64": "2.6.2",
+ "@resvg/resvg-js-darwin-arm64": "2.6.2",
+ "@resvg/resvg-js-darwin-x64": "2.6.2",
+ "@resvg/resvg-js-linux-arm-gnueabihf": "2.6.2",
+ "@resvg/resvg-js-linux-arm64-gnu": "2.6.2",
+ "@resvg/resvg-js-linux-arm64-musl": "2.6.2",
+ "@resvg/resvg-js-linux-x64-gnu": "2.6.2",
+ "@resvg/resvg-js-linux-x64-musl": "2.6.2",
+ "@resvg/resvg-js-win32-arm64-msvc": "2.6.2",
+ "@resvg/resvg-js-win32-ia32-msvc": "2.6.2",
+ "@resvg/resvg-js-win32-x64-msvc": "2.6.2"
+ }
+ },
+ "node_modules/@resvg/resvg-js-android-arm-eabi": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.2.tgz",
+ "integrity": "sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-android-arm64": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.2.tgz",
+ "integrity": "sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-darwin-arm64": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.2.tgz",
+ "integrity": "sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-darwin-x64": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.2.tgz",
+ "integrity": "sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-linux-arm-gnueabihf": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.2.tgz",
+ "integrity": "sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-linux-arm64-gnu": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.2.tgz",
+ "integrity": "sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-linux-arm64-musl": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.2.tgz",
+ "integrity": "sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-linux-x64-gnu": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.2.tgz",
+ "integrity": "sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-linux-x64-musl": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.2.tgz",
+ "integrity": "sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-win32-arm64-msvc": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.2.tgz",
+ "integrity": "sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-win32-ia32-msvc": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.2.tgz",
+ "integrity": "sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@resvg/resvg-js-win32-x64-msvc": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.2.tgz",
+ "integrity": "sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.27",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
@@ -3089,6 +3431,46 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
+ "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/pluginutils/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT"
+ },
+ "node_modules/@rollup/pluginutils/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.53.5",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.5.tgz",
@@ -3096,7 +3478,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3110,7 +3491,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3124,7 +3504,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3138,7 +3517,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3152,7 +3530,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3166,7 +3543,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3180,7 +3556,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3194,7 +3569,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3208,7 +3582,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3222,7 +3595,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3236,7 +3608,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3250,7 +3621,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3264,7 +3634,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3278,7 +3647,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3292,7 +3660,6 @@
"cpu": [
"s390x"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3306,7 +3673,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3320,7 +3686,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3334,7 +3699,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3348,7 +3712,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3362,7 +3725,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3376,7 +3738,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -3390,26 +3751,158 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
- "node_modules/@stablelib/base64": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz",
- "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==",
- "license": "MIT"
- },
- "node_modules/@swc/helpers": {
- "version": "0.5.18",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz",
- "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
- "license": "Apache-2.0",
+ "node_modules/@shikijs/core": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz",
+ "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==",
+ "license": "MIT",
"dependencies": {
- "tslib": "^2.8.0"
+ "@shikijs/primitive": "4.0.2",
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4",
+ "hast-util-to-html": "^9.0.5"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/engine-javascript": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz",
+ "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "oniguruma-to-es": "^4.3.4"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/engine-oniguruma": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz",
+ "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/langs": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz",
+ "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/primitive": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.2.tgz",
+ "integrity": "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/rehype": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-4.0.2.tgz",
+ "integrity": "sha512-cmPlKLD8JeojasNFoY64162ScpEdEdQUMuVodPCrv1nx1z3bjmGwoKWDruQWa/ejSznImlaeB0Ty6Q3zPaVQAA==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2",
+ "@types/hast": "^3.0.4",
+ "hast-util-to-string": "^3.0.1",
+ "shiki": "4.0.2",
+ "unified": "^11.0.5",
+ "unist-util-visit": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/themes": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz",
+ "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "4.0.2"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/types": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz",
+ "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@shikijs/vscode-textmate": {
+ "version": "10.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
+ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
+ "license": "MIT"
+ },
+ "node_modules/@shuding/opentype.js": {
+ "version": "1.4.0-beta.0",
+ "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz",
+ "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==",
+ "license": "MIT",
+ "dependencies": {
+ "fflate": "^0.7.3",
+ "string.prototype.codepointat": "^0.2.1"
+ },
+ "bin": {
+ "ot": "bin/ot"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/@stablelib/base64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz",
+ "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==",
+ "license": "MIT"
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.18",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz",
+ "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
}
},
"node_modules/@tailwindcss/node": {
@@ -3924,13 +4417,30 @@
"integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
"license": "MIT"
},
+ "node_modules/@types/debug": {
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz",
+ "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/ms": "*"
+ }
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/@types/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/express": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
@@ -3964,12 +4474,42 @@
"@types/send": "*"
}
},
+ "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-errors": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
"integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
"license": "MIT"
},
+ "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/mdx": {
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz",
+ "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==",
+ "license": "MIT"
+ },
+ "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": "20.16.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.11.tgz",
@@ -4004,7 +4544,6 @@
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
- "devOptional": true,
"license": "MIT"
},
"node_modules/@types/qs": {
@@ -4023,7 +4562,6 @@
"version": "18.3.27",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
- "devOptional": true,
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
@@ -4059,6 +4597,12 @@
"@types/node": "*"
}
},
+ "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/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
@@ -4069,6 +4613,12 @@
"@types/node": "*"
}
},
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz",
+ "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==",
+ "license": "ISC"
+ },
"node_modules/@vitejs/plugin-react": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
@@ -4103,6 +4653,27 @@
"node": ">= 0.6"
}
},
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
@@ -4128,6 +4699,15 @@
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
"license": "MIT"
},
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
"node_modules/aria-hidden": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
@@ -4146,6 +4726,15 @@
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
+ "node_modules/astring": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz",
+ "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==",
+ "license": "MIT",
+ "bin": {
+ "astring": "bin/astring"
+ }
+ },
"node_modules/autoprefixer": {
"version": "10.4.23",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz",
@@ -4183,6 +4772,25 @@
"postcss": "^8.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": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -4264,6 +4872,18 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
+ "node_modules/brace-expansion": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@@ -4387,6 +5007,15 @@
"node": ">= 6"
}
},
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001761",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz",
@@ -4408,6 +5037,56 @@
],
"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/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/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -4490,6 +5169,32 @@
"react-dom": "^18 || ^19 || ^19.0.0-rc"
}
},
+ "node_modules/collapse-white-space": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz",
+ "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "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/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -4539,6 +5244,47 @@
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
"license": "MIT"
},
+ "node_modules/css-background-parser": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz",
+ "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==",
+ "license": "MIT"
+ },
+ "node_modules/css-box-shadow": {
+ "version": "1.0.0-3",
+ "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz",
+ "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==",
+ "license": "MIT"
+ },
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/css-gradient-parser": {
+ "version": "0.0.17",
+ "resolved": "https://registry.npmjs.org/css-gradient-parser/-/css-gradient-parser-0.0.17.tgz",
+ "integrity": "sha512-w2Xy9UMMwlKtou0vlRnXvWglPAceXCTtcmVSo8ZBUvqCV5aXEFP/PC6d+I464810I9FT++UACwTD5511bmGPUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -4692,7 +5438,6 @@
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -4712,6 +5457,19 @@
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
"license": "MIT"
},
+ "node_modules/decode-named-character-reference": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
+ "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "character-entities": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -4721,6 +5479,15 @@
"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/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
@@ -4747,6 +5514,19 @@
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
"license": "MIT"
},
+ "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/dfa": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
@@ -4973,6 +5753,15 @@
"embla-carousel": "8.6.0"
}
},
+ "node_modules/emoji-regex-xs": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-2.0.1.tgz",
+ "integrity": "sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
@@ -5026,12 +5815,44 @@
"node": ">= 0.4"
}
},
- "node_modules/esbuild": {
- "version": "0.25.12",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
- "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
- "dev": true,
- "hasInstallScript": true,
+ "node_modules/esast-util-from-estree": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz",
+ "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-visit": "^2.0.0",
+ "unist-util-position-from-estree": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/esast-util-from-js": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz",
+ "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "acorn": "^8.0.0",
+ "esast-util-from-estree": "^2.0.0",
+ "vfile-message": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
@@ -5097,6 +5918,131 @@
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
+ "node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/estree-util-attach-comments": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz",
+ "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/estree-util-build-jsx": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz",
+ "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-is-identifier-name": "^3.0.0",
+ "estree-walker": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "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/estree-util-scope": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz",
+ "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "devlop": "^1.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/estree-util-to-js": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz",
+ "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "astring": "^1.8.0",
+ "source-map": "^0.7.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/estree-util-to-js/node_modules/source-map": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/estree-util-visit": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz",
+ "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "@types/unist": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
@@ -5191,6 +6137,24 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"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/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "license": "MIT",
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -5249,6 +6213,25 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/feed": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/feed/-/feed-5.2.1.tgz",
+ "integrity": "sha512-jTynzYPWs9ALjro0GW8j7sv9y7cJBeOdD4Y88kVqYy/eyusIX3g+499JiTDIlD9Ge/unebx57T4Uzo6vpYvMtA==",
+ "license": "MIT",
+ "dependencies": {
+ "xml-js": "^1.6.11"
+ },
+ "engines": {
+ "node": ">=20",
+ "pnpm": ">=10"
+ }
+ },
+ "node_modules/fflate": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
+ "license": "MIT"
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -5462,6 +6445,29 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
+ "node_modules/github-slugger": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz",
+ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==",
+ "license": "ISC"
+ },
+ "node_modules/glob": {
+ "version": "13.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
+ "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "minimatch": "^10.2.2",
+ "minipass": "^7.1.3",
+ "path-scurry": "^2.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -5493,6 +6499,21 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/gray-matter": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
+ "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-yaml": "^3.13.1",
+ "kind-of": "^6.0.2",
+ "section-matter": "^1.0.0",
+ "strip-bom-string": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@@ -5517,6 +6538,136 @@
"node": ">= 0.4"
}
},
+ "node_modules/hast-util-heading-rank": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz",
+ "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-is-element": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz",
+ "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-to-estree": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz",
+ "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "comma-separated-tokens": "^2.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-attach-comments": "^3.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",
+ "zwitch": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-to-html": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz",
+ "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/unist": "^3.0.0",
+ "ccount": "^2.0.0",
+ "comma-separated-tokens": "^2.0.0",
+ "hast-util-whitespace": "^3.0.0",
+ "html-void-elements": "^3.0.0",
+ "mdast-util-to-hast": "^13.0.0",
+ "property-information": "^7.0.0",
+ "space-separated-tokens": "^2.0.0",
+ "stringify-entities": "^4.0.0",
+ "zwitch": "^2.0.4"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "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-to-string": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz",
+ "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.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",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz",
@@ -5526,6 +6677,28 @@
"node": ">=18.0.0"
}
},
+ "node_modules/hex-rgb": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz",
+ "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/html-void-elements": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz",
+ "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/http-errors": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
@@ -5564,6 +6737,12 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"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/input-otp": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz",
@@ -5601,6 +6780,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-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -5628,6 +6831,25 @@
"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-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -5649,6 +6871,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",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@@ -5658,6 +6890,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/jiti": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
@@ -5681,6 +6925,19 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT"
},
+ "node_modules/js-yaml": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
@@ -5707,6 +6964,15 @@
"node": ">=6"
}
},
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/lightningcss": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
@@ -6011,6 +7277,16 @@
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"license": "MIT"
},
+ "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",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -6052,15 +7328,324 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
- "node_modules/math-intrinsics": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
- "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "node_modules/markdown-extensions": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz",
+ "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/markdown-table": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz",
+ "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
+ "node_modules/mdast-util-find-and-replace": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz",
+ "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "escape-string-regexp": "^5.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/mdast-util-from-markdown": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz",
+ "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==",
+ "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-gfm": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz",
+ "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-gfm-autolink-literal": "^2.0.0",
+ "mdast-util-gfm-footnote": "^2.0.0",
+ "mdast-util-gfm-strikethrough": "^2.0.0",
+ "mdast-util-gfm-table": "^2.0.0",
+ "mdast-util-gfm-task-list-item": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-autolink-literal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz",
+ "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "ccount": "^2.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-find-and-replace": "^3.0.0",
+ "micromark-util-character": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-footnote": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz",
+ "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.1.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-strikethrough": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
+ "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.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-gfm-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
+ "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "markdown-table": "^3.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-gfm-task-list-item": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
+ "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@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": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz",
+ "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==",
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-mdx-expression": "^2.0.0",
+ "mdast-util-mdx-jsx": "^3.0.0",
+ "mdast-util-mdxjs-esm": "^2.0.0",
+ "mdast-util-to-markdown": "^2.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",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -6075,28 +7660,745 @@
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "license": "MIT",
+ "engines": {
+ "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-extension-gfm": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
+ "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-extension-gfm-autolink-literal": "^2.0.0",
+ "micromark-extension-gfm-footnote": "^2.0.0",
+ "micromark-extension-gfm-strikethrough": "^2.0.0",
+ "micromark-extension-gfm-table": "^2.0.0",
+ "micromark-extension-gfm-tagfilter": "^2.0.0",
+ "micromark-extension-gfm-task-list-item": "^2.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-autolink-literal": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz",
+ "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-footnote": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz",
+ "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-strikethrough": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz",
+ "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-table": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz",
+ "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-tagfilter": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
+ "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-task-list-item": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz",
+ "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-mdx-expression": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz",
+ "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-factory-mdx-expression": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-events-to-acorn": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-extension-mdx-jsx": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz",
+ "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-is-identifier-name": "^3.0.0",
+ "micromark-factory-mdx-expression": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-events-to-acorn": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "vfile-message": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-mdx-md": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz",
+ "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-mdxjs": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz",
+ "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==",
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.0.0",
+ "acorn-jsx": "^5.0.0",
+ "micromark-extension-mdx-expression": "^3.0.0",
+ "micromark-extension-mdx-jsx": "^3.0.0",
+ "micromark-extension-mdx-md": "^2.0.0",
+ "micromark-extension-mdxjs-esm": "^3.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-mdxjs-esm": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz",
+ "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-events-to-acorn": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "unist-util-position-from-estree": "^2.0.0",
+ "vfile-message": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "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-mdx-expression": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz",
+ "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-events-to-acorn": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "unist-util-position-from-estree": "^2.0.0",
+ "vfile-message": "^4.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-events-to-acorn": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz",
+ "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "@types/unist": "^3.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-visit": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "vfile-message": "^4.0.0"
+ }
+ },
+ "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/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "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",
- "engines": {
- "node": ">= 8"
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-encode": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0"
}
},
- "node_modules/methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "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",
- "engines": {
- "node": ">= 0.6"
+ "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",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@@ -6143,6 +8445,30 @@
"node": ">= 0.6"
}
},
+ "node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
@@ -6291,12 +8617,64 @@
"node": ">= 0.8"
}
},
+ "node_modules/oniguruma-parser": {
+ "version": "0.12.2",
+ "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz",
+ "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==",
+ "license": "MIT"
+ },
+ "node_modules/oniguruma-to-es": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz",
+ "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==",
+ "license": "MIT",
+ "dependencies": {
+ "oniguruma-parser": "^0.12.2",
+ "regex": "^6.1.0",
+ "regex-recursion": "^6.0.2"
+ }
+ },
"node_modules/pako": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
"license": "MIT"
},
+ "node_modules/parse-css-color": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/parse-css-color/-/parse-css-color-0.2.1.tgz",
+ "integrity": "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.1.4",
+ "hex-rgb": "^4.1.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",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -6312,6 +8690,31 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"license": "MIT"
},
+ "node_modules/path-scurry": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+ "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz",
+ "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/path-to-regexp": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
@@ -6646,6 +9049,16 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
+ "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",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -6861,113 +9274,340 @@
"integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==",
"license": "MIT",
"dependencies": {
- "fast-equals": "^5.0.1",
- "prop-types": "^15.8.1",
- "react-transition-group": "^4.4.5"
+ "fast-equals": "^5.0.1",
+ "prop-types": "^15.8.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/react-style-singleton": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+ "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "get-nonce": "^1.0.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "license": "MIT",
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/reading-time": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz",
+ "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==",
+ "license": "MIT"
+ },
+ "node_modules/recharts": {
+ "version": "2.15.4",
+ "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz",
+ "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==",
+ "license": "MIT",
+ "dependencies": {
+ "clsx": "^2.0.0",
+ "eventemitter3": "^4.0.1",
+ "lodash": "^4.17.21",
+ "react-is": "^18.3.1",
+ "react-smooth": "^4.0.4",
+ "recharts-scale": "^0.4.4",
+ "tiny-invariant": "^1.3.1",
+ "victory-vendor": "^36.6.8"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/recharts-scale": {
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
+ "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
+ "license": "MIT",
+ "dependencies": {
+ "decimal.js-light": "^2.4.1"
+ }
+ },
+ "node_modules/recma-build-jsx": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz",
+ "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-util-build-jsx": "^3.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/recma-jsx": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz",
+ "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==",
+ "license": "MIT",
+ "dependencies": {
+ "acorn-jsx": "^5.0.0",
+ "estree-util-to-js": "^2.0.0",
+ "recma-parse": "^1.0.0",
+ "recma-stringify": "^1.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ },
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/recma-parse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz",
+ "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "esast-util-from-js": "^2.0.0",
+ "unified": "^11.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/recma-stringify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz",
+ "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-util-to-js": "^2.0.0",
+ "unified": "^11.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/regex": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz",
+ "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==",
+ "license": "MIT",
+ "dependencies": {
+ "regex-utilities": "^2.3.0"
+ }
+ },
+ "node_modules/regex-recursion": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz",
+ "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==",
+ "license": "MIT",
+ "dependencies": {
+ "regex-utilities": "^2.3.0"
+ }
+ },
+ "node_modules/regex-utilities": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz",
+ "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==",
+ "license": "MIT"
+ },
+ "node_modules/regexparam": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz",
+ "integrity": "sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/rehype-autolink-headings": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz",
+ "integrity": "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@ungap/structured-clone": "^1.0.0",
+ "hast-util-heading-rank": "^3.0.0",
+ "hast-util-is-element": "^3.0.0",
+ "unified": "^11.0.0",
+ "unist-util-visit": "^5.0.0"
},
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
- "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/react-style-singleton": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
- "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+ "node_modules/rehype-recma": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz",
+ "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==",
"license": "MIT",
"dependencies": {
- "get-nonce": "^1.0.0",
- "tslib": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ "@types/estree": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "hast-util-to-estree": "^3.0.0"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/react-transition-group": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
- "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
- "license": "BSD-3-Clause",
+ "node_modules/rehype-slug": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz",
+ "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==",
+ "license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.5.5",
- "dom-helpers": "^5.0.1",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.6.2"
+ "@types/hast": "^3.0.0",
+ "github-slugger": "^2.0.0",
+ "hast-util-heading-rank": "^3.0.0",
+ "hast-util-to-string": "^3.0.0",
+ "unist-util-visit": "^5.0.0"
},
- "peerDependencies": {
- "react": ">=16.6.0",
- "react-dom": ">=16.6.0"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/read-cache": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
- "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "node_modules/remark-gfm": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
+ "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
"license": "MIT",
"dependencies": {
- "pify": "^2.3.0"
+ "@types/mdast": "^4.0.0",
+ "mdast-util-gfm": "^3.0.0",
+ "micromark-extension-gfm": "^3.0.0",
+ "remark-parse": "^11.0.0",
+ "remark-stringify": "^11.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "node_modules/remark-mdx": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz",
+ "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==",
"license": "MIT",
"dependencies": {
- "picomatch": "^2.2.1"
+ "mdast-util-mdx": "^3.0.0",
+ "micromark-extension-mdxjs": "^3.0.0"
},
- "engines": {
- "node": ">=8.10.0"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/recharts": {
- "version": "2.15.4",
- "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz",
- "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==",
+ "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": {
- "clsx": "^2.0.0",
- "eventemitter3": "^4.0.1",
- "lodash": "^4.17.21",
- "react-is": "^18.3.1",
- "react-smooth": "^4.0.4",
- "recharts-scale": "^0.4.4",
- "tiny-invariant": "^1.3.1",
- "victory-vendor": "^36.6.8"
- },
- "engines": {
- "node": ">=14"
+ "@types/mdast": "^4.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "unified": "^11.0.0"
},
- "peerDependencies": {
- "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
- "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/recharts-scale": {
- "version": "0.4.5",
- "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
- "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
+ "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": {
- "decimal.js-light": "^2.4.1"
+ "@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/regexparam": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz",
- "integrity": "sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==",
+ "node_modules/remark-stringify": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
+ "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
"license": "MIT",
- "engines": {
- "node": ">=8"
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
"node_modules/resend": {
@@ -7040,7 +9680,6 @@
"version": "4.53.5",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.5.tgz",
"integrity": "sha512-iTNAbFSlRpcHeeWu73ywU/8KuU/LZmNCSxp6fjQkJBD3ivUb8tpDrXhIxEzA05HlYMEwmtaUnb3RP+YNv162OQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.8"
@@ -7127,6 +9766,37 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
+ "node_modules/satori": {
+ "version": "0.26.0",
+ "resolved": "https://registry.npmjs.org/satori/-/satori-0.26.0.tgz",
+ "integrity": "sha512-tkMFrfIs3l2mQ2JEcyW0ADTy3zGggFRFzi6Ef8YozQSFsFKEqaSO1Y8F9wJg4//PJGQauMalHGTUEkPrFwhVPA==",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "@shuding/opentype.js": "1.4.0-beta.0",
+ "css-background-parser": "^0.1.0",
+ "css-box-shadow": "1.0.0-3",
+ "css-gradient-parser": "^0.0.17",
+ "css-to-react-native": "^3.0.0",
+ "emoji-regex-xs": "^2.0.1",
+ "escape-html": "^1.0.3",
+ "linebreak": "^1.1.0",
+ "parse-css-color": "^0.2.1",
+ "postcss-value-parser": "^4.2.0",
+ "yoga-layout": "^3.2.1"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/sax": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
+ "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=11.0.0"
+ }
+ },
"node_modules/scheduler": {
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
@@ -7136,6 +9806,19 @@
"loose-envify": "^1.1.0"
}
},
+ "node_modules/section-matter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
+ "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
+ "license": "MIT",
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -7206,6 +9889,25 @@
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
+ "node_modules/shiki": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz",
+ "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/core": "4.0.2",
+ "@shikijs/engine-javascript": "4.0.2",
+ "@shikijs/engine-oniguruma": "4.0.2",
+ "@shikijs/langs": "4.0.2",
+ "@shikijs/themes": "4.0.2",
+ "@shikijs/types": "4.0.2",
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/side-channel": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
@@ -7308,6 +10010,22 @@
"source-map": "^0.6.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/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/standardwebhooks": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz",
@@ -7327,6 +10045,35 @@
"node": ">= 0.8"
}
},
+ "node_modules/string.prototype.codepointat": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
+ "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==",
+ "license": "MIT"
+ },
+ "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-bom-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
+ "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/stripe": {
"version": "20.1.2",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-20.1.2.tgz",
@@ -7347,6 +10094,24 @@
}
}
},
+ "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.1",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
@@ -7591,6 +10356,26 @@
"node": ">=0.6"
}
},
+ "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/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",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -8134,6 +10919,106 @@
"tiny-inflate": "^1.0.0"
}
},
+ "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-position-from-estree": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz",
+ "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==",
+ "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.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz",
+ "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",
+ "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",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -8276,6 +11161,34 @@
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc"
}
},
+ "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/victory-vendor": {
"version": "36.9.2",
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
@@ -8439,6 +11352,18 @@
}
}
},
+ "node_modules/xml-js": {
+ "version": "1.6.11",
+ "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
+ "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
+ "license": "MIT",
+ "dependencies": {
+ "sax": "^1.2.4"
+ },
+ "bin": {
+ "xml-js": "bin/cli.js"
+ }
+ },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@@ -8446,6 +11371,12 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/yoga-layout": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz",
+ "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==",
+ "license": "MIT"
+ },
"node_modules/zod": {
"version": "3.25.76",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
@@ -8454,6 +11385,16 @@
"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",
+ "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
}
}
}
diff --git a/package.json b/package.json
index fe15900e..d281c626 100644
--- a/package.json
+++ b/package.json
@@ -5,12 +5,19 @@
"license": "BSL-1.1",
"scripts": {
"dev": "NODE_ENV=development tsx server/index.ts",
- "build": "vite build && esbuild server/index.ts --platform=node --packages=external --bundle --format=esm --outdir=dist",
+ "build:og": "tsx scripts/generate-og.ts",
+ "build:rss": "tsx scripts/generate-rss.ts",
+ "build:sitemap": "tsx scripts/generate-blog-sitemap.ts",
+ "build:blog": "npm run build:og && npm run build:rss && npm run build:sitemap",
+ "build": "npm run build:og && vite build && esbuild server/index.ts --platform=node --packages=external --bundle --format=esm --outdir=dist && npm run build:rss && npm run build:sitemap",
"start": "NODE_ENV=production node dist/index.js",
"check": "tsc",
"db:push": "drizzle-kit push"
},
"dependencies": {
+ "@fontsource/inter": "^5.2.8",
+ "@mdx-js/react": "^3.1.1",
+ "@mdx-js/rollup": "^3.1.1",
"@neondatabase/serverless": "^0.10.4",
"@radix-ui/react-accordion": "^1.2.4",
"@radix-ui/react-alert-dialog": "^1.1.7",
@@ -39,6 +46,8 @@
"@radix-ui/react-toggle": "^1.1.3",
"@radix-ui/react-toggle-group": "^1.1.3",
"@radix-ui/react-tooltip": "^1.2.0",
+ "@resvg/resvg-js": "^2.6.2",
+ "@shikijs/rehype": "^4.0.2",
"@tanstack/react-query": "^5.60.5",
"@types/express-rate-limit": "^5.1.3",
"class-variance-authority": "^0.7.1",
@@ -50,7 +59,10 @@
"embla-carousel-react": "^8.6.0",
"express": "^4.21.2",
"express-rate-limit": "^8.2.1",
+ "feed": "^5.2.1",
"framer-motion": "^11.13.1",
+ "glob": "^13.0.6",
+ "gray-matter": "^4.0.3",
"helmet": "^8.1.0",
"input-otp": "^1.4.2",
"lucide-react": "^0.453.0",
@@ -61,8 +73,14 @@
"react-hook-form": "^7.55.0",
"react-icons": "^5.4.0",
"react-resizable-panels": "^2.1.7",
+ "reading-time": "^1.5.0",
"recharts": "^2.15.2",
+ "rehype-autolink-headings": "^7.1.0",
+ "rehype-slug": "^6.0.0",
+ "remark-gfm": "^4.0.1",
"resend": "^6.7.0",
+ "satori": "^0.26.0",
+ "shiki": "^4.0.2",
"stripe": "^20.1.2",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
@@ -78,6 +96,7 @@
"@tailwindcss/typography": "^0.5.15",
"@tailwindcss/vite": "^4.1.3",
"@types/express": "4.17.21",
+ "@types/mdx": "^2.0.13",
"@types/node": "20.16.11",
"@types/pdfkit": "^0.13.9",
"@types/react": "^18.3.11",
diff --git a/public/blog/rss.xml b/public/blog/rss.xml
new file mode 100644
index 00000000..7c656822
--- /dev/null
+++ b/public/blog/rss.xml
@@ -0,0 +1,118 @@
+
+
+
+ CX Linux Blog
+ https://cxlinux.com/blog
+ Tutorials, architecture deep-dives, and practical guides for AI-powered Linux engineering.
+ Fri, 15 May 2026 12:26:38 GMT
+ https://validator.w3.org/feed/docs/rss2.html
+ https://github.com/jpmonette/feed
+ en
+
+ CX Linux Blog
+ https://cxlinux.com/og-image.png
+ https://cxlinux.com/blog
+
+ © 2026 AI Venture Holdings LLC
+ -
+
+ https://cxlinux.com/blog/how-we-built-cx
+ https://cxlinux.com/blog/how-we-built-cx
+ Wed, 15 Apr 2026 00:00:00 GMT
+
+ The technical decisions behind CX Linux — from the NLP layer to the sandbox runtime, LLM selection, and why we chose to build an OS layer instead of a terminal wrapper.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/cx-linux-2026-roadmap
+ https://cxlinux.com/blog/cx-linux-2026-roadmap
+ Fri, 10 Apr 2026 00:00:00 GMT
+
+ Multi-agent workflows, a native GUI layer, fleet intelligence, and a plugin ecosystem. Here's everything we're building in 2026 and the reasoning behind each decision.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/multi-server-fleet-management
+ https://cxlinux.com/blog/multi-server-fleet-management
+ Sun, 05 Apr 2026 00:00:00 GMT
+
+ How to use CX Linux Pro and Team plans to manage dozens of servers with a single command — patching, auditing, deploying, and monitoring across your entire fleet.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/local-vs-cloud-llm
+ https://cxlinux.com/blog/local-vs-cloud-llm
+ Wed, 01 Apr 2026 00:00:00 GMT
+
+ CX Linux supports both local and cloud LLMs. This guide explains the real-world tradeoffs — privacy, cost, performance, and when to use each — with benchmarks.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/ai-ml-setup-5-minutes
+ https://cxlinux.com/blog/ai-ml-setup-5-minutes
+ Wed, 25 Mar 2026 00:00:00 GMT
+
+ Set up Python, CUDA, Ollama, PyTorch, and a full AI development environment on Linux in under 5 minutes using CX Linux natural language commands.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/devops-guide-cx-linux
+ https://cxlinux.com/blog/devops-guide-cx-linux
+ Fri, 20 Mar 2026 00:00:00 GMT
+
+ How DevOps engineers are using CX Linux to automate server provisioning, CI/CD setup, monitoring, and incident response — with real command examples for each workflow.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/cx-vs-warp-copilot-cli
+ https://cxlinux.com/blog/cx-vs-warp-copilot-cli
+ Sun, 15 Mar 2026 00:00:00 GMT
+
+ Three AI-powered terminal tools, three very different approaches. We compare CX Linux, Warp, and GitHub Copilot CLI across execution, context, safety, and real-world use cases.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/linux-tasks-30-seconds
+ https://cxlinux.com/blog/linux-tasks-30-seconds
+ Wed, 11 Mar 2026 00:00:00 GMT
+
+ Setting up nginx, configuring firewalls, deploying Docker stacks — these tasks eat hours. Here's how CX Linux turns each one into a single natural language command.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/what-is-cx-linux
+ https://cxlinux.com/blog/what-is-cx-linux
+ Tue, 10 Mar 2026 00:00:00 GMT
+
+ CX Linux is not just another distro. It's an AI layer that sits on top of any Debian or Ubuntu system and lets you control Linux with natural language. Here's how it works.]]>
+ CX Linux Team
+
+
+ -
+
+ https://cxlinux.com/blog/sandboxed-execution-safety
+ https://cxlinux.com/blog/sandboxed-execution-safety
+ Sun, 08 Mar 2026 00:00:00 GMT
+
+ Running AI-generated commands on your production system sounds risky. Here's exactly how CX Linux uses sandboxing, command preview, and instant rollback to make it safe.]]>
+ CX Linux Team
+
+
+
+
\ No newline at end of file
diff --git a/public/og/ai-ml-setup-5-minutes.png b/public/og/ai-ml-setup-5-minutes.png
new file mode 100644
index 00000000..335058ba
Binary files /dev/null and b/public/og/ai-ml-setup-5-minutes.png differ
diff --git a/public/og/cx-linux-2026-roadmap.png b/public/og/cx-linux-2026-roadmap.png
new file mode 100644
index 00000000..9e73717c
Binary files /dev/null and b/public/og/cx-linux-2026-roadmap.png differ
diff --git a/public/og/cx-vs-warp-copilot-cli.png b/public/og/cx-vs-warp-copilot-cli.png
new file mode 100644
index 00000000..bde99380
Binary files /dev/null and b/public/og/cx-vs-warp-copilot-cli.png differ
diff --git a/public/og/devops-guide-cx-linux.png b/public/og/devops-guide-cx-linux.png
new file mode 100644
index 00000000..d92997ae
Binary files /dev/null and b/public/og/devops-guide-cx-linux.png differ
diff --git a/public/og/how-we-built-cx.png b/public/og/how-we-built-cx.png
new file mode 100644
index 00000000..62075b53
Binary files /dev/null and b/public/og/how-we-built-cx.png differ
diff --git a/public/og/linux-tasks-30-seconds.png b/public/og/linux-tasks-30-seconds.png
new file mode 100644
index 00000000..037250cf
Binary files /dev/null and b/public/og/linux-tasks-30-seconds.png differ
diff --git a/public/og/local-vs-cloud-llm.png b/public/og/local-vs-cloud-llm.png
new file mode 100644
index 00000000..97775071
Binary files /dev/null and b/public/og/local-vs-cloud-llm.png differ
diff --git a/public/og/multi-server-fleet-management.png b/public/og/multi-server-fleet-management.png
new file mode 100644
index 00000000..cf7f317d
Binary files /dev/null and b/public/og/multi-server-fleet-management.png differ
diff --git a/public/og/sandboxed-execution-safety.png b/public/og/sandboxed-execution-safety.png
new file mode 100644
index 00000000..8355ad12
Binary files /dev/null and b/public/og/sandboxed-execution-safety.png differ
diff --git a/public/og/what-is-cx-linux.png b/public/og/what-is-cx-linux.png
new file mode 100644
index 00000000..0dae6de0
Binary files /dev/null and b/public/og/what-is-cx-linux.png differ
diff --git a/public/sitemap.xml b/public/sitemap.xml
new file mode 100644
index 00000000..e66b5580
--- /dev/null
+++ b/public/sitemap.xml
@@ -0,0 +1,190 @@
+
+
+
+
+ https://cxlinux.com/blog
+ 2026-04-15
+ daily
+ 0.8
+
+
+ https://cxlinux.com/blog/how-we-built-cx
+ 2026-04-15
+ monthly
+ 0.7
+
+
+ https://cxlinux.com/blog/cx-linux-2026-roadmap
+ 2026-04-10
+ monthly
+ 0.9
+
+
+ https://cxlinux.com/blog/multi-server-fleet-management
+ 2026-04-05
+ monthly
+ 0.7
+
+
+ https://cxlinux.com/blog/local-vs-cloud-llm
+ 2026-04-01
+ monthly
+ 0.7
+
+
+ https://cxlinux.com/blog/ai-ml-setup-5-minutes
+ 2026-03-25
+ monthly
+ 0.7
+
+
+ https://cxlinux.com/blog/devops-guide-cx-linux
+ 2026-03-20
+ monthly
+ 0.7
+
+
+ https://cxlinux.com/blog/cx-vs-warp-copilot-cli
+ 2026-03-15
+ monthly
+ 0.7
+
+
+ https://cxlinux.com/blog/linux-tasks-30-seconds
+ 2026-03-11
+ monthly
+ 0.7
+
+
+ https://cxlinux.com/blog/what-is-cx-linux
+ 2026-03-10
+ monthly
+ 0.9
+
+
+ https://cxlinux.com/blog/sandboxed-execution-safety
+ 2026-03-08
+ monthly
+ 0.7
+
+
+ https://cxlinux.com/blog/tag/engineering
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/architecture
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/AI
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/roadmap
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/features
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/announcement
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/DevOps
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/fleet
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/tutorial
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/LLM
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/configuration
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/machine-learning
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/automation
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/comparison
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/productivity
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/introduction
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/Linux
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/security
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/sandboxing
+ 2026-04-15
+ weekly
+ 0.5
+
+
+ https://cxlinux.com/blog/tag/safety
+ 2026-04-15
+ weekly
+ 0.5
+
+
\ No newline at end of file
diff --git a/scripts/generate-blog-sitemap.ts b/scripts/generate-blog-sitemap.ts
new file mode 100644
index 00000000..b05b5404
--- /dev/null
+++ b/scripts/generate-blog-sitemap.ts
@@ -0,0 +1,83 @@
+import { readFileSync, writeFileSync, existsSync } from "fs";
+import { join, dirname } from "path";
+import { fileURLToPath } from "url";
+import { glob } from "glob";
+import matter from "gray-matter";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const ROOT = join(__dirname, "..");
+const BASE_URL = "https://cxlinux.com";
+const SITEMAP_PATH = join(ROOT, "public", "sitemap.xml");
+
+async function main() {
+ const files = await glob(join(ROOT, "content", "blog", "*.mdx"));
+
+ const posts: Array<{ slug: string; publishedAt: string; updatedAt?: string; featured: boolean; tags: string[] }> = [];
+
+ for (const file of files) {
+ const src = readFileSync(file, "utf-8");
+ const { data } = matter(src);
+ if (data.draft) continue;
+ const slug = file.replace(/^.*\/([^/]+)\.mdx$/, "$1");
+ posts.push({ slug, publishedAt: data.publishedAt, updatedAt: data.updatedAt, featured: !!data.featured, tags: data.tags ?? [] });
+ }
+
+ posts.sort((a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime());
+
+ const allTags = [...new Set(posts.flatMap((p) => p.tags))];
+ const newestDate = posts[0]?.publishedAt ?? new Date().toISOString().slice(0, 10);
+
+ const urlEntries: string[] = [];
+
+ // Blog index
+ urlEntries.push(`
+ ${BASE_URL}/blog
+ ${newestDate}
+ daily
+ 0.8
+ `);
+
+ // Individual posts
+ for (const post of posts) {
+ const lastmod = post.updatedAt ?? post.publishedAt;
+ const priority = post.featured ? "0.9" : "0.7";
+ urlEntries.push(`
+ ${BASE_URL}/blog/${post.slug}
+ ${lastmod}
+ monthly
+ ${priority}
+ `);
+ }
+
+ // Tag pages
+ for (const tag of allTags) {
+ urlEntries.push(`
+ ${BASE_URL}/blog/tag/${encodeURIComponent(tag)}
+ ${newestDate}
+ weekly
+ 0.5
+ `);
+ }
+
+ // Merge with existing sitemap or create new
+ let existingContent = "";
+ if (existsSync(SITEMAP_PATH)) {
+ existingContent = readFileSync(SITEMAP_PATH, "utf-8")
+ .replace(/<\?xml[^>]+\?>/, "")
+ .replace(/]+>/, "")
+ .replace(/<\/urlset>/, "")
+ // Remove existing blog URLs to avoid duplication
+ .replace(/\s*\s*[^<]*\/blog[^<]*<\/loc>[\s\S]*?<\/url>/g, "");
+ }
+
+ const sitemap = `
+
+${existingContent.trim()}
+${urlEntries.join("\n")}
+ `;
+
+ writeFileSync(SITEMAP_PATH, sitemap.trim());
+ console.log(`✓ /public/sitemap.xml (${posts.length} posts + ${allTags.length} tags)`);
+}
+
+main().catch(console.error);
diff --git a/scripts/generate-og.ts b/scripts/generate-og.ts
new file mode 100644
index 00000000..88d862e8
--- /dev/null
+++ b/scripts/generate-og.ts
@@ -0,0 +1,159 @@
+import { readFileSync, writeFileSync, mkdirSync } from "fs";
+import { join, dirname } from "path";
+import { fileURLToPath } from "url";
+import { glob } from "glob";
+import matter from "gray-matter";
+import satori from "satori";
+import { Resvg } from "@resvg/resvg-js";
+import { createElement } from "react";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const ROOT = join(__dirname, "..");
+const OUT_DIR = join(ROOT, "public", "og");
+mkdirSync(OUT_DIR, { recursive: true });
+
+// Load Inter font for satori
+const interFontPath = join(ROOT, "node_modules", "@fontsource", "inter", "files", "inter-latin-700-normal.woff");
+let fontBuffer: Buffer;
+try {
+ fontBuffer = readFileSync(interFontPath);
+} catch {
+ // Fallback: use a system font path
+ console.warn("Inter font not found via @fontsource, using fallback");
+ fontBuffer = Buffer.alloc(0);
+}
+
+function truncate(str: string, max: number) {
+ return str.length > max ? str.slice(0, max - 1) + "…" : str;
+}
+
+async function generateOg(slug: string, title: string, description: string, tags: string[], readingTime: number, author: string) {
+ const tag = tags[0] ?? "";
+
+ const svg = await satori(
+ createElement("div", {
+ style: {
+ width: 1200,
+ height: 630,
+ display: "flex",
+ flexDirection: "column",
+ background: "#1E1E1E",
+ padding: "56px 64px",
+ position: "relative",
+ },
+ },
+ // Green radial glow (top right)
+ createElement("div", {
+ style: {
+ position: "absolute",
+ top: 0,
+ right: 0,
+ width: 480,
+ height: 480,
+ borderRadius: "50%",
+ background: "radial-gradient(circle, rgba(0,255,159,0.08) 0%, transparent 70%)",
+ },
+ }),
+ // Wordmark
+ createElement("div", {
+ style: { display: "flex", alignItems: "center", gap: 6, marginBottom: "auto" },
+ },
+ createElement("span", { style: { color: "#FFFFFF", fontSize: 22, fontWeight: 700, letterSpacing: "-0.02em" } }, "CX"),
+ createElement("span", { style: { color: "#00FF9F", fontSize: 22, fontWeight: 700, letterSpacing: "-0.02em" } }, "LINUX"),
+ ),
+ // Title
+ createElement("div", {
+ style: {
+ color: "#FFFFFF",
+ fontSize: title.length > 50 ? 54 : 68,
+ fontWeight: 700,
+ lineHeight: 1.1,
+ letterSpacing: "-0.03em",
+ maxWidth: 960,
+ marginBottom: 20,
+ },
+ }, truncate(title, 80)),
+ // Description
+ createElement("div", {
+ style: {
+ color: "#9CA3AF",
+ fontSize: 20,
+ lineHeight: 1.5,
+ maxWidth: 880,
+ marginBottom: 40,
+ },
+ }, truncate(description, 120)),
+ // Footer row
+ createElement("div", {
+ style: {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ borderTop: "1px solid rgba(255,255,255,0.1)",
+ paddingTop: 24,
+ },
+ },
+ createElement("div", {
+ style: { display: "flex", alignItems: "center", gap: 16, color: "#6B7280", fontSize: 16 },
+ },
+ createElement("span", {}, author),
+ createElement("span", {}, "·"),
+ createElement("span", {}, `${readingTime} min read`),
+ ),
+ tag && createElement("div", {
+ style: {
+ background: "rgba(0,255,159,0.1)",
+ border: "1px solid rgba(0,255,159,0.3)",
+ borderRadius: 6,
+ padding: "6px 14px",
+ color: "#00FF9F",
+ fontSize: 13,
+ fontWeight: 600,
+ textTransform: "uppercase",
+ letterSpacing: "0.08em",
+ },
+ }, tag),
+ ),
+ // Bottom accent bar
+ createElement("div", {
+ style: {
+ position: "absolute",
+ bottom: 0,
+ left: 0,
+ width: 200,
+ height: 4,
+ background: "#00FF9F",
+ borderRadius: "0 2px 0 0",
+ },
+ }),
+ ),
+ {
+ width: 1200,
+ height: 630,
+ fonts: fontBuffer.length > 0 ? [{ name: "Inter", data: fontBuffer, weight: 700, style: "normal" }] : [],
+ }
+ );
+
+ const resvg = new Resvg(svg, { fitTo: { mode: "width", value: 1200 } });
+ const png = resvg.render().asPng();
+ writeFileSync(join(OUT_DIR, `${slug}.png`), png);
+ console.log(`✓ /public/og/${slug}.png`);
+}
+
+async function main() {
+ const files = await glob(join(ROOT, "content", "blog", "*.mdx"));
+ for (const file of files) {
+ const src = readFileSync(file, "utf-8");
+ const { data } = matter(src);
+ if (data.draft) continue;
+
+ const slug = file.replace(/^.*\/([^/]+)\.mdx$/, "$1");
+ const words = src.replace(/---[\s\S]*?---/, "").trim().split(/\s+/).length;
+ const readingTime = Math.max(1, Math.ceil(words / 200));
+
+ await generateOg(slug, data.title ?? slug, data.description ?? "", data.tags ?? [], readingTime, "CX Linux Team");
+ }
+ console.log("OG images generated.");
+}
+
+main().catch(console.error);
diff --git a/scripts/generate-rss.ts b/scripts/generate-rss.ts
new file mode 100644
index 00000000..9fc70c65
--- /dev/null
+++ b/scripts/generate-rss.ts
@@ -0,0 +1,69 @@
+import { readFileSync, writeFileSync, mkdirSync } from "fs";
+import { join, dirname } from "path";
+import { fileURLToPath } from "url";
+import { glob } from "glob";
+import matter from "gray-matter";
+import { Feed } from "feed";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const ROOT = join(__dirname, "..");
+const BASE_URL = "https://cxlinux.com";
+
+mkdirSync(join(ROOT, "public", "blog"), { recursive: true });
+
+async function main() {
+ const files = await glob(join(ROOT, "content", "blog", "*.mdx"));
+
+ const posts: Array<{ slug: string; data: Record; body: string }> = [];
+
+ for (const file of files) {
+ const src = readFileSync(file, "utf-8");
+ const { data, content } = matter(src);
+ if (data.draft) continue;
+ const slug = file.replace(/^.*\/([^/]+)\.mdx$/, "$1");
+ posts.push({ slug, data, body: content });
+ }
+
+ posts.sort((a, b) => new Date(b.data.publishedAt).getTime() - new Date(a.data.publishedAt).getTime());
+
+ const feed = new Feed({
+ title: "CX Linux Blog",
+ description: "Tutorials, architecture deep-dives, and practical guides for AI-powered Linux engineering.",
+ id: `${BASE_URL}/blog`,
+ link: `${BASE_URL}/blog`,
+ language: "en",
+ image: `${BASE_URL}/og-image.png`,
+ favicon: `${BASE_URL}/favicon.ico`,
+ copyright: `© ${new Date().getFullYear()} AI Venture Holdings LLC`,
+ feedLinks: { rss2: `${BASE_URL}/blog/rss.xml` },
+ author: { name: "CX Linux Team", link: BASE_URL },
+ });
+
+ for (const { slug, data, body } of posts) {
+ const url = `${BASE_URL}/blog/${slug}`;
+ const ogImage = data.ogImage ?? `${BASE_URL}/og/${slug}.png`;
+ // Strip MDX components for the feed — render as plain text
+ const plainBody = body
+ .replace(/<[A-Z][^>]*>[\s\S]*?<\/[A-Z][^>]*>/g, "")
+ .replace(/<[A-Z][^/]*/g, "")
+ .replace(/^import .+$/gm, "")
+ .trim();
+
+ feed.addItem({
+ title: data.title,
+ id: url,
+ link: url,
+ description: data.description,
+ content: `${data.description}
`,
+ author: [{ name: "CX Linux Team", link: BASE_URL }],
+ date: new Date(data.publishedAt),
+ image: ogImage,
+ });
+ }
+
+ const rss = feed.rss2();
+ writeFileSync(join(ROOT, "public", "blog", "rss.xml"), rss);
+ console.log(`✓ /public/blog/rss.xml (${posts.length} posts)`);
+}
+
+main().catch(console.error);
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 6814410e..63863926 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -2,7 +2,11 @@ import type { Config } from "tailwindcss";
export default {
darkMode: ["class"],
- content: ["./client/index.html", "./client/src/**/*.{js,jsx,ts,tsx}"],
+ content: [
+ "./client/index.html",
+ "./client/src/**/*.{js,jsx,ts,tsx}",
+ "./content/blog/**/*.mdx",
+ ],
theme: {
extend: {
borderRadius: {
diff --git a/vite.config.ts b/vite.config.ts
index 7a2ccb14..e6bd1eeb 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,10 +1,25 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
+import mdx from "@mdx-js/rollup";
+import remarkGfm from "remark-gfm";
+import rehypeSlug from "rehype-slug";
+import rehypeAutolinkHeadings from "rehype-autolink-headings";
import path from "path";
import runtimeErrorOverlay from "@replit/vite-plugin-runtime-error-modal";
export default defineConfig({
plugins: [
+ {
+ enforce: "pre",
+ ...mdx({
+ remarkPlugins: [remarkGfm],
+ rehypePlugins: [
+ rehypeSlug,
+ [rehypeAutolinkHeadings, { behavior: "wrap" }],
+ ],
+ providerImportSource: "@mdx-js/react",
+ }),
+ },
react(),
runtimeErrorOverlay(),
...(process.env.NODE_ENV !== "production" &&
@@ -32,8 +47,7 @@ export default defineConfig({
},
server: {
fs: {
- strict: true,
- deny: ["**/.*"],
+ strict: false,
},
},
});