diff options
| author | Dominik Koch <dominik@koch-bautechnik.de> | 2025-07-21 23:18:07 +0200 |
|---|---|---|
| committer | Dominik Koch <dominik@koch-bautechnik.de> | 2025-07-21 23:18:07 +0200 |
| commit | e21c4674890a6f4b33d5623c19957b0741cde572 (patch) | |
| tree | b11f6e9324b68e8e1f9cba73186209032c20b4c0 | |
| parent | 1b3d42b2a92a6c4ba65fbc6378d193570a530d97 (diff) | |
| download | opencut-e21c4674890a6f4b33d5623c19957b0741cde572.tar.gz | |
feat: add opencut blog
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | apps/web/.env.example | 4 | ||||
| -rw-r--r-- | apps/web/next.config.ts | 12 | ||||
| -rw-r--r-- | apps/web/package.json | 7 | ||||
| -rw-r--r-- | apps/web/src/app/blog/[slug]/page.tsx | 145 | ||||
| -rw-r--r-- | apps/web/src/app/blog/page.tsx | 98 | ||||
| -rw-r--r-- | apps/web/src/app/metadata.ts | 3 | ||||
| -rw-r--r-- | apps/web/src/components/header.tsx | 5 | ||||
| -rw-r--r-- | apps/web/src/components/ui/prose.tsx | 22 | ||||
| -rw-r--r-- | apps/web/src/components/ui/separator.tsx | 14 | ||||
| -rw-r--r-- | apps/web/src/lib/blog-query.ts | 70 | ||||
| -rw-r--r-- | apps/web/src/types/post.ts | 93 | ||||
| -rw-r--r-- | apps/web/tailwind.config.ts | 3 | ||||
| -rw-r--r-- | bun.lock | 61 |
14 files changed, 533 insertions, 9 deletions
@@ -23,6 +23,7 @@ - Real-time preview - No watermarks or subscriptions - Analytics provided by [Databuddy](https://www.databuddy.cc?utm_source=opencut), 100% Anonymized & Non-invasive. +- Blog powered by [Marble](https://marblecms.com?utm_source=opencut), Headless CMS. ## Project Structure @@ -113,6 +114,10 @@ Before you begin, ensure you have the following installed on your system: UPSTASH_REDIS_REST_URL="http://localhost:8079" UPSTASH_REDIS_REST_TOKEN="example_token" + # Marble Blog + MARBLE_WORKSPACE_KEY=cm6ytuq9x0000i803v0isidst # example organization key + MARBLE_API_URL=https://api.marblecms.com + # Development NODE_ENV="development" ``` diff --git a/apps/web/.env.example b/apps/web/.env.example index d63df851..267e2cab 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -13,3 +13,7 @@ NODE_ENV=development # Redis UPSTASH_REDIS_REST_URL=http://localhost:8079 UPSTASH_REDIS_REST_TOKEN=example_token + +# Marble Blog +MARBLE_WORKSPACE_KEY=cm6ytuq9x0000i803v0isidst # example organization key +MARBLE_API_URL=https://api.marblecms.com
\ No newline at end of file diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index 02261068..980c5827 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -18,6 +18,18 @@ const nextConfig: NextConfig = { protocol: "https", hostname: "images.unsplash.com", }, + { + protocol: "https", + hostname: "images.marblecms.com", + }, + { + protocol: "https", + hostname: "lh3.googleusercontent.com", + }, + { + protocol: "https", + hostname: "avatars.githubusercontent.com", + }, ], }, }; diff --git a/apps/web/package.json b/apps/web/package.json index f7b09de8..46797068 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -21,6 +21,7 @@ "@hookform/resolvers": "^3.9.1", "@opencut/auth": "workspace:*", "@opencut/db": "workspace:*", + "@radix-ui/react-separator": "^1.1.7", "@t3-oss/env-core": "^0.13.8", "@t3-oss/env-nextjs": "^0.13.8", "@upstash/ratelimit": "^2.0.5", @@ -52,14 +53,20 @@ "react-phone-number-input": "^3.4.11", "react-resizable-panels": "^2.1.7", "recharts": "^2.14.1", + "rehype-autolink-headings": "^7.1.0", + "rehype-parse": "^9.0.1", + "rehype-slug": "^6.0.0", + "rehype-stringify": "^10.0.1", "sonner": "^1.7.1", "tailwind-merge": "^2.5.5", "tailwindcss-animate": "^1.0.7", + "unified": "^11.0.5", "vaul": "^1.1.1", "zod": "^3.25.67", "zustand": "^5.0.2" }, "devDependencies": { + "@tailwindcss/typography": "^0.5.16", "@types/bun": "latest", "@types/pg": "^8.15.4", "@types/react": "^18.2.48", diff --git a/apps/web/src/app/blog/[slug]/page.tsx b/apps/web/src/app/blog/[slug]/page.tsx new file mode 100644 index 00000000..ad5bb548 --- /dev/null +++ b/apps/web/src/app/blog/[slug]/page.tsx @@ -0,0 +1,145 @@ +import { Header } from "@/components/header"; +import Prose from "@/components/ui/prose"; +import { Separator } from "@/components/ui/separator"; +import { + getPosts, + getSinglePost, + processHtmlContent, +} from "@/lib/blog-query"; +import { Metadata } from "next"; +import Image from "next/image"; +import { notFound } from "next/navigation"; + +type PageProps = { + params: Promise<{ slug: string }>; + searchParams: Promise<{ [key: string]: string | string[] | undefined }>; +}; + +export async function generateMetadata({ + params, +}: PageProps): Promise<Metadata> { + const slug = (await params).slug; + + const data = await getSinglePost(slug); + + if (!data || !data.post) return {}; + + return { + title: data.post.title, + description: data.post.description, + twitter: { + title: `${data.post.title}`, + description: `${data.post.description}`, + card: "summary_large_image", + images: [ + { + url: data.post.coverImage, + width: "1200", + height: "630", + alt: data.post.title, + }, + ], + }, + openGraph: { + type: "article", + siteName: "", + images: [ + { + url: data.post.coverImage, + width: "1200", + height: "630", + alt: data.post.title, + }, + ], + title: data.post.title, + description: data.post.description, + publishedTime: new Date(data.post.publishedAt).toISOString(), + authors: [ + ...data.post.authors.map((author: { name: string }) => author.name), + ], + }, + }; +} + +export async function generateStaticParams() { + const data = await getPosts(); + if (!data || !data.posts.length) return []; + + return data.posts.map((post) => ({ + slug: post.slug, + })); +} + +async function Page({ params }: PageProps) { + const slug = (await params).slug; + const data = await getSinglePost(slug); + if (!data || !data.post) return notFound(); + + const html = await processHtmlContent(data.post.content); + + const formattedDate = new Date(data.post.publishedAt).toLocaleDateString( + "en-US", + { + day: "numeric", + month: "long", + year: "numeric", + } + ); + + return ( + <div className="min-h-screen bg-background"> + <Header /> + + <main className="relative"> + <div className="absolute inset-0 overflow-hidden pointer-events-none"> + <div className="absolute -top-40 -right-40 w-96 h-96 bg-gradient-to-br from-muted/20 to-transparent rounded-full blur-3xl" /> + <div className="absolute top-1/2 -left-40 w-80 h-80 bg-gradient-to-tr from-muted/10 to-transparent rounded-full blur-3xl" /> + </div> + + <div className="relative container max-w-3xl mx-auto px-4 py-16"> + <div className="text-center mb-6"> + {data.post.coverImage && ( + <div className="relative aspect-video rounded-lg overflow-hidden mb-6"> + <Image + src={data.post.coverImage} + alt={data.post.title} + loading="eager" + fill + className="object-cover rounded-lg" + /> + </div> + )} + <div className="flex items-center justify-center mb-6"> + <time dateTime={data.post.publishedAt.toString()}> + {formattedDate} + </time> + </div> + + <h1 className="text-5xl md:text-4xl font-bold tracking-tight mb-6"> + {data.post.title} + </h1> + <div className="flex items-center justify-center gap-2"> + <Image + src={data.post.authors[0].image} + alt={data.post.authors[0].name} + width={36} + height={36} + loading="eager" + className="aspect-square shrink-0 size-8 rounded-full" + /> + <p className="text-muted-foreground"> + {data.post.authors[0].name} + </p> + </div> + </div> + <Separator /> + <section className="mt-14"> + <Prose html={html} /> + </section> + </div> + </main> + </div> + ); +} + +export default Page; diff --git a/apps/web/src/app/blog/page.tsx b/apps/web/src/app/blog/page.tsx new file mode 100644 index 00000000..ca553a67 --- /dev/null +++ b/apps/web/src/app/blog/page.tsx @@ -0,0 +1,98 @@ +import { Metadata } from "next"; +import { Header } from "@/components/header"; +import { Card, CardContent } from "@/components/ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import Link from "next/link"; +import { getPosts } from "@/lib/blog-query"; +import Image from "next/image"; + +export const metadata: Metadata = { + title: "Blog - OpenCut", + description: + "Read the latest news and updates about OpenCut, the free and open-source video editor.", + openGraph: { + title: "Blog - OpenCut", + description: + "Read the latest news and updates about OpenCut, the free and open-source video editor.", + type: "website", + }, +}; + +export default async function BlogPage() { + const data = await getPosts(); + if (!data || !data.posts) return <div>No posts yet</div>; + + return ( + <div className="min-h-screen bg-background"> + <Header /> + + <main className="relative"> + <div className="absolute inset-0 overflow-hidden pointer-events-none"> + <div className="absolute -top-40 -right-40 w-96 h-96 bg-gradient-to-br from-muted/20 to-transparent rounded-full blur-3xl" /> + <div className="absolute top-1/2 -left-40 w-80 h-80 bg-gradient-to-tr from-muted/10 to-transparent rounded-full blur-3xl" /> + </div> + + <div className="relative container max-w-3xl mx-auto px-4 py-16"> + <div className="text-center mb-20"> + <h1 className="text-5xl md:text-6xl font-bold tracking-tight mb-6"> + Blog + </h1> + <p className="text-xl text-muted-foreground mb-8 max-w-2xl mx-auto leading-relaxed"> + Read the latest news and updates about OpenCut, the free and + open-source video editor. + </p> + </div> + <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> + {data.posts.map((post) => ( + <Link key={post.id} href={`/blog/${post.slug}`}> + <Card className="h-full hover:shadow-lg transition-shadow overflow-hidden"> + {post.coverImage && ( + <div className="relative aspect-video"> + <Image + src={post.coverImage} + alt={post.title} + fill + className="object-cover rounded-xl" + /> + </div> + )} + + <CardContent className="p-6"> + {post.authors && post.authors.length > 0 && ( + <div className="flex items-center gap-2 mb-4"> + {post.authors.map((author, index) => ( + <div + key={author.id} + className="flex items-center gap-2" + > + <Avatar className="w-6 h-6"> + <AvatarImage + src={author.image} + alt={author.name} + /> + <AvatarFallback className="text-xs"> + {author.name.charAt(0).toUpperCase()} + </AvatarFallback> + </Avatar> + <span className="text-sm text-muted-foreground"> + {author.name} + </span> + {index < post.authors.length - 1 && ( + <span className="text-muted-foreground">•</span> + )} + </div> + ))} + </div> + )} + <h2 className="text-xl font-semibold mb-2">{post.title}</h2> + <p className="text-muted-foreground">{post.description}</p> + </CardContent> + </Card> + </Link> + ))} + </div> + </div> + </main> + </div> + ); +} diff --git a/apps/web/src/app/metadata.ts b/apps/web/src/app/metadata.ts index 47f0020b..6f9e6023 100644 --- a/apps/web/src/app/metadata.ts +++ b/apps/web/src/app/metadata.ts @@ -33,6 +33,9 @@ export const baseMetaData: Metadata = { creator: "@opencutapp", images: [twitterImageUrl], }, + pinterest: { + richPin: false, + }, robots: { index: true, follow: true, diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index 720abd3d..7d11e68a 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -16,6 +16,11 @@ export function Header() { const rightContent = (
<nav className="flex items-center gap-3">
+ <Link href="/blog">
+ <Button variant="text" className="text-sm p-0">
+ Blog
+ </Button>
+ </Link>
<Link href="/contributors">
<Button variant="text" className="text-sm p-0">
Contributors
diff --git a/apps/web/src/components/ui/prose.tsx b/apps/web/src/components/ui/prose.tsx new file mode 100644 index 00000000..c25a5a65 --- /dev/null +++ b/apps/web/src/components/ui/prose.tsx @@ -0,0 +1,22 @@ +import { cn } from "@/lib/utils"; +import type React from "react"; + +type ProseProps = React.HTMLAttributes<HTMLElement> & { + as?: "article"; + html: string; +}; + +function Prose({ children, html, className }: ProseProps) { + return ( + <article + className={cn( + "prose prose-h2:font-semibold max-w-none prose-h1:text-xl prose-a:text-blue-600 prose-p:text-justify dark:prose-invert mx-auto", + className + )} + > + {html ? <div dangerouslySetInnerHTML={{ __html: html }} /> : children} + </article> + ); +} + +export default Prose; diff --git a/apps/web/src/components/ui/separator.tsx b/apps/web/src/components/ui/separator.tsx index 6138cabf..12d81c4a 100644 --- a/apps/web/src/components/ui/separator.tsx +++ b/apps/web/src/components/ui/separator.tsx @@ -1,9 +1,9 @@ -"use client"; +"use client" -import * as React from "react"; -import { Separator as SeparatorPrimitive } from "radix-ui"; +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" -import { cn } from "../../lib/utils"; +import { cn } from "@/lib/utils" const Separator = React.forwardRef< React.ElementRef<typeof SeparatorPrimitive.Root>, @@ -25,7 +25,7 @@ const Separator = React.forwardRef< {...props} /> ) -); -Separator.displayName = SeparatorPrimitive.Root.displayName; +) +Separator.displayName = SeparatorPrimitive.Root.displayName -export { Separator }; +export { Separator } diff --git a/apps/web/src/lib/blog-query.ts b/apps/web/src/lib/blog-query.ts new file mode 100644 index 00000000..71ee7341 --- /dev/null +++ b/apps/web/src/lib/blog-query.ts @@ -0,0 +1,70 @@ +import type { MarbleAuthorList, MarbleCategoryList, MarblePost, MarblePostList, MarbleTagList } from '@/types/post'; +import { unified } from "unified"; +import rehypeParse from "rehype-parse"; +import rehypeStringify from "rehype-stringify"; +import rehypeSlug from "rehype-slug"; +import rehypeAutolinkHeadings from "rehype-autolink-headings"; + +const url = process.env.MARBLE_API_URL; +const key = process.env.MARBLE_WORKSPACE_KEY; + +export async function getPosts() { + try { + const raw = await fetch(`${url}/${key}/posts`); + const data: MarblePostList = await raw.json(); + return data; + } catch (error) { + console.log(error); + } +} + +export async function getTags() { + try { + const raw = await fetch(`${url}/${key}/tags`); + const data: MarbleTagList = await raw.json(); + return data; + } catch (error) { + console.log(error); + } +} + +export async function getSinglePost(slug: string) { + try { + const raw = await fetch(`${url}/${key}/posts/${slug}`); + const data: MarblePost = await raw.json(); + return data; + } catch (error) { + console.log(error); + } +} + +export async function getCategories() { + try { + const raw = await fetch(`${url}/${key}/categories`); + const data: MarbleCategoryList = await raw.json(); + return data; + } catch (error) { + console.log(error); + } +} + +export async function getAuthors() { + try { + const raw = await fetch(`${url}/${key}/authors`); + const data: MarbleAuthorList = await raw.json(); + return data; + } catch (error) { + console.log(error); + } +} + +export async function processHtmlContent(html: string): Promise<string> { + const processor = unified() + .use(rehypeParse, { fragment: true }) + .use(rehypeSlug) + .use(rehypeAutolinkHeadings, { behavior: "append" }) + .use(rehypeStringify); + + const file = await processor.process(html); + return String(file); +}
\ No newline at end of file diff --git a/apps/web/src/types/post.ts b/apps/web/src/types/post.ts new file mode 100644 index 00000000..c3436847 --- /dev/null +++ b/apps/web/src/types/post.ts @@ -0,0 +1,93 @@ +export type Post = { + id: string; + slug: string; + title: string; + content: string; + description: string; + coverImage: string; + publishedAt: Date; + updatedAt: Date; + authors: { + id: string; + name: string; + image: string; + }[]; + category: { + id: string; + slug: string; + name: string; + }; + tags: { + id: string; + slug: string; + name: string; + }[]; + attribution: { + author: string; + url: string; + } | null; + }; + + export type Pagination = { + limit: number; + currpage: number; + nextPage: number | null; + prevPage: number | null; + totalItems: number; + totalPages: number; + }; + + export type MarblePostList = { + posts: Post[]; + pagination: Pagination; + }; + + export type MarblePost = { + post: Post; + }; + + export type Tag = { + id: string; + name: string; + slug: string; + }; + + export type MarbleTag = { + tag: Tag; + }; + + export type MarbleTagList = { + tags: Tag[]; + pagination: Pagination; + }; + + export type Category = { + id: string; + name: string; + slug: string; + }; + + export type MarbleCategory = { + category: Category; + }; + + export type MarbleCategoryList = { + categories: Category[]; + pagination: Pagination; + }; + + export type Author = { + id: string; + name: string; + image: string; + }; + + export type MarbleAuthor = { + author: Author; + }; + + export type MarbleAuthorList = { + authors: Author[]; + pagination: Pagination; + }; +
\ No newline at end of file diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts index 049add76..d992b7b4 100644 --- a/apps/web/tailwind.config.ts +++ b/apps/web/tailwind.config.ts @@ -1,4 +1,6 @@ import type { Config } from "tailwindcss"; + + export default { darkMode: ["class"], content: [ @@ -106,6 +108,7 @@ export default { }, }, plugins: [ + require("@tailwindcss/typography"), require("tailwindcss-animate"), function ({ addUtilities, @@ -23,6 +23,7 @@ "@hookform/resolvers": "^3.9.1", "@opencut/auth": "workspace:*", "@opencut/db": "workspace:*", + "@radix-ui/react-separator": "^1.1.7", "@t3-oss/env-core": "^0.13.8", "@t3-oss/env-nextjs": "^0.13.8", "@upstash/ratelimit": "^2.0.5", @@ -54,14 +55,20 @@ "react-phone-number-input": "^3.4.11", "react-resizable-panels": "^2.1.7", "recharts": "^2.14.1", + "rehype-autolink-headings": "^7.1.0", + "rehype-parse": "^9.0.1", + "rehype-slug": "^6.0.0", + "rehype-stringify": "^10.0.1", "sonner": "^1.7.1", "tailwind-merge": "^2.5.5", "tailwindcss-animate": "^1.0.7", + "unified": "^11.0.5", "vaul": "^1.1.1", "zod": "^3.25.67", "zustand": "^5.0.2", }, "devDependencies": { + "@tailwindcss/typography": "^0.5.16", "@types/bun": "latest", "@types/pg": "^8.15.4", "@types/react": "^18.2.48", @@ -425,7 +432,9 @@ "@t3-oss/env-nextjs": ["@t3-oss/env-nextjs@0.13.8", "", { "dependencies": { "@t3-oss/env-core": "0.13.8" }, "peerDependencies": { "arktype": "^2.1.0", "typescript": ">=5.0.0", "valibot": "^1.0.0-beta.7 || ^1.0.0", "zod": "^3.24.0 || ^4.0.0-beta.0" }, "optionalPeers": ["arktype", "typescript", "valibot", "zod"] }, "sha512-QmTLnsdQJ8BiQad2W2nvV6oUpH4oMZMqnFEjhVpzU0h3sI9hn8zb8crjWJ1Amq453mGZs6A4v4ihIeBFDOrLeQ=="], - "@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="], + "@tailwindcss/typography": ["@tailwindcss/typography@0.5.16", "", { "dependencies": { "lodash.castarray": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.merge": "^4.6.2", "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA=="], + + "@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="], "@types/d3-array": ["@types/d3-array@3.2.1", "", {}, "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="], @@ -629,6 +638,8 @@ "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "esbuild": ["esbuild@0.25.6", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.6", "@esbuild/android-arm": "0.25.6", "@esbuild/android-arm64": "0.25.6", "@esbuild/android-x64": "0.25.6", "@esbuild/darwin-arm64": "0.25.6", "@esbuild/darwin-x64": "0.25.6", "@esbuild/freebsd-arm64": "0.25.6", "@esbuild/freebsd-x64": "0.25.6", "@esbuild/linux-arm": "0.25.6", "@esbuild/linux-arm64": "0.25.6", "@esbuild/linux-ia32": "0.25.6", "@esbuild/linux-loong64": "0.25.6", "@esbuild/linux-mips64el": "0.25.6", "@esbuild/linux-ppc64": "0.25.6", "@esbuild/linux-riscv64": "0.25.6", "@esbuild/linux-s390x": "0.25.6", "@esbuild/linux-x64": "0.25.6", "@esbuild/netbsd-arm64": "0.25.6", "@esbuild/netbsd-x64": "0.25.6", "@esbuild/openbsd-arm64": "0.25.6", "@esbuild/openbsd-x64": "0.25.6", "@esbuild/openharmony-arm64": "0.25.6", "@esbuild/sunos-x64": "0.25.6", "@esbuild/win32-arm64": "0.25.6", "@esbuild/win32-ia32": "0.25.6", "@esbuild/win32-x64": "0.25.6" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg=="], "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], @@ -659,18 +670,38 @@ "get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="], + "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], + "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "hast-util-from-html": ["hast-util-from-html@2.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", "hast-util-from-parse5": "^8.0.0", "parse5": "^7.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw=="], + + "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="], + + "hast-util-heading-rank": ["hast-util-heading-rank@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA=="], + + "hast-util-is-element": ["hast-util-is-element@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g=="], + + "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="], + + "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "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" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], + "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "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" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], + "hast-util-to-string": ["hast-util-to-string@3.0.1", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A=="], + "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], + "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], + "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="], + "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], + "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], "input-format": ["input-format@0.3.14", "", { "dependencies": { "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">=18.1.0", "react-dom": ">=18.1.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-gHMrgrbCgmT4uK5Um5eVDUohuV9lcs95ZUUN9Px2Y0VIfjTzT2wF8Q3Z4fwLFm7c5Z2OXCm53FHoovj6SlOKdg=="], @@ -723,6 +754,12 @@ "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "lodash.castarray": ["lodash.castarray@4.4.0", "", {}, "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q=="], + + "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], @@ -827,6 +864,8 @@ "parse-entities": ["parse-entities@4.0.2", "", { "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" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], @@ -867,7 +906,7 @@ "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], - "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="], "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], @@ -937,6 +976,14 @@ "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], + "rehype-autolink-headings": ["rehype-autolink-headings@7.1.0", "", { "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" } }, "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw=="], + + "rehype-parse": ["rehype-parse@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-from-html": "^2.0.0", "unified": "^11.0.0" } }, "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag=="], + + "rehype-slug": ["rehype-slug@6.0.0", "", { "dependencies": { "@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" } }, "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A=="], + + "rehype-stringify": ["rehype-stringify@10.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-to-html": "^9.0.0", "unified": "^11.0.0" } }, "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA=="], + "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="], @@ -1067,12 +1114,16 @@ "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], + "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], + "vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="], "victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="], "wavesurfer.js": ["wavesurfer.js@7.10.0", "", {}, "sha512-GiyAHdorqGtUYG5fe4BfTf5lmtSLhrXoHeNlMsR80JOiOZxOrIOv9QaIR8RnqlleJ6D8R9cqvZKR9lfJcWcapg=="], + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], @@ -1091,6 +1142,8 @@ "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + "@types/bun/bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="], + "better-auth/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -1105,6 +1158,8 @@ "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + "postcss-nested/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], @@ -1113,6 +1168,8 @@ "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], |
