diff --git a/.env.example b/.env.example index 18c0c82..8106c98 100644 --- a/.env.example +++ b/.env.example @@ -6,5 +6,3 @@ NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME= NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET= CLOUDINARY_API_KEY= CLOUDINARY_API_SECRET= -RESEND_API_KEY= -CONTACT_NOTIFICATION_EMAIL= diff --git a/AGENTS.md b/AGENTS.md index 5997de7..a0fc6e6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ ## 0. Project Overview **What this project is:** -codeddevs.com is the official company website for CODEDDEVS TECHNOLOGY LTD — a Nigerian technology startup building AI-first software products for African markets. The site audience is investors, press, and partners. +codeddevs.com is the official company website for CODEDDEVS TECHNOLOGY LTD - a Nigerian technology company registered with the Corporate Affairs Commission (RC: 9426867), incorporated in March 2026, and headquartered in Lagos. The site audience is investors, press, partners, collaborators, and people who want to understand what CodedDevs is building. **How the system works:** The project is a full-stack Next.js 15 monolith — the frontend (public pages), backend (API routes), and admin dashboard all live in one codebase and deploy together on Vercel. @@ -19,12 +19,13 @@ There is a built-in admin dashboard at `/admin` that serves as the company's CMS **The public site:** The public site at `/` reads all content from a Neon PostgreSQL database via Drizzle ORM. Pages are statically generated at build time and revalidated every hour via ISR. This means the site is fast for visitors but content updates appear within 60 minutes of being published from the admin dashboard. +The CodedDevs site is the company destination, not the product destination. Products are surfaced through company blog updates and direct external calls to action. The public site does not maintain internal product listing, product-detail, or standalone product-spotlight routes. + **The database:** -A single Neon PostgreSQL database stores all content — team members, products, blog posts, careers, applications, and contact submissions. The schema is defined in `src/db/schema.ts` and managed via Drizzle Kit migrations. The database stores only text, JSON, and Cloudinary URLs — no images or binary files. +A single Neon PostgreSQL database stores all content for team members, products, blog posts, and admin users. The schema is defined in `src/db/schema.ts` and managed via Drizzle Kit migrations. The database stores only text, JSON, and Cloudinary URLs - no images or binary files. **External services:** - **Cloudinary** — stores all content images. Images are uploaded via the admin dashboard, never stored locally. -- **Resend** — sends email notifications when someone submits the contact form or applies for a job. - **Vercel** — hosts the entire application. Deploys automatically when code merges to `main`. **What this site is NOT:** @@ -40,10 +41,11 @@ Official company website for **CODEDDEVS TECHNOLOGY LTD** (RC: 9426867). - **URL:** codeddevs.com (placeholder until domain is confirmed) - **Audience:** Investors, press, and partners — NOT merchants, buyers, or end users -- **Purpose:** Present CODEDDEVS as a serious, product-driven technology company. Communicate what we are building, what's coming next, and how our products are evolving. Share product updates, releases, version changes, roadmaps, and announcements. -- **Tone:** Professional, minimal, text-first — like Anthropic.com or Stripe.com +- **Purpose:** Present CODEDDEVS as a serious, product-driven Nigerian technology company building software, payment, and AI products for African markets. Communicate why the company exists, what it is building, what is coming next, and how its products are evolving. Share product updates, releases, version changes, roadmaps, announcements, partnerships, and company stories. +- **Tone:** Professional, confident, company-first, and grounded in African market realities. The writing should be clear and human, not generic startup language. - **This is NOT a portfolio site.** Do not treat it like a project showcase or personal portfolio. It is an official company website structured the way established tech companies present themselves. - **This is NOT the twizrr product site.** twizrr.com is a completely separate codebase and repo. Every mention of twizrr on this site links OUT to twizrr.com. +- **No dedicated public product pages.** Do not create `/products` or `/products/[slug]` routes. Product CTAs open the relevant external product website. --- @@ -60,8 +62,8 @@ Do not change any of these without explicit instruction from the user. | Auth | NextAuth.js v5 (credentials, single admin) | | Blog editor | TipTap (rich text, stores JSON) | | File storage | Cloudinary | -| Email | Resend | | Image cropping | react-image-crop (admin only — never on public pages) | +| Admin UI primitives | shadcn/ui (admin dashboard only) | | Fonts | JetBrains Mono + IBM Plex Sans | | Hosting | Vercel | | Package manager | pnpm — NEVER use npm or yarn | @@ -91,19 +93,48 @@ Brand Silver: #D1D6E0 — the secondary brand color --color-text-muted: #6B7896; /* captions, labels, secondary */ --color-accent: #121F38; /* primary buttons, links, highlights */ --color-accent-hover: #1A2D4F; /* button/link hover */ +--color-accent-amber: #C98A3A; /* warm commerce and energy accent */ +--color-accent-green: #2F6F4E; /* growth, community, ecosystem accent */ +--color-accent-clay: #A85D3A; /* grounded editorial and African warmth accent */ +--color-accent-blue: #3B82F6; /* technology and AI accent */ --color-success: #16A34A; --color-error: #DC2626; ``` +### Supporting Accent Colors + +The public site is allowed to use a small supporting palette when it improves meaning, hierarchy, or emotional warmth. These accents should support the brand system, not replace it. + +- **Amber `#C98A3A`** — commerce, payments, energy, warmth +- **Green `#2F6F4E`** — community, growth, ecosystems +- **Clay `#A85D3A`** — grounded editorial warmth and African context +- **Blue `#3B82F6`** — AI, software, infrastructure, technical signals + +Use supporting accents sparingly: icons, small tags, data marks, section highlights, illustration details, and category cues. Do not use them as dominant page backgrounds unless explicitly requested. + +### Color Composition + +The public site must not default to white and gray for nearly every section. Use the three core brand surfaces creatively and intentionally: + +- **Navy `#121F38`** — strong brand bands, footer, calls to action, selected feature sections, and high-emphasis moments. +- **Brand Silver `#D1D6E0`** — structural contrast, editorial bands, supporting panels, dividers, and secondary emphasis. +- **White `#FFFFFF`** — breathing room, primary reading surfaces, and visual reset between stronger sections. +- Use `#F4F5F8` as a quiet supporting surface, not as the automatic background for every card or section. +- Create page rhythm by alternating white, navy, and silver surfaces where the content hierarchy supports it. +- Dark navy sections are brand compositions, not dark mode. They must use white primary text and silver secondary text with accessible contrast. +- Do not make the site one-note: neither an all-white/gray interface nor a navy-dominated interface is acceptable. +- Do not introduce gradients or unrelated accent colors. Creativity should come from proportion, contrast, layout, typography, imagery, and the deliberate mixing of the approved brand and supporting colors. + ### Typography Fonts loaded via `next/font/google` in `src/app/layout.tsx`. Never use a `` tag or CDN. | Element | Font | Size | Weight | Line Height | |---|---|---|---|---| -| H1 | JetBrains Mono | 56px | 700 | 1.1 | -| H2 | JetBrains Mono | 40px | 700 | 1.2 | -| H3 | JetBrains Mono | 28px | 600 | 1.3 | +| Hero H1 | JetBrains Mono | 56–72px | 700 | 1.05–1.1 | +| Page H1 | JetBrains Mono | 48–56px | 700 | 1.1 | +| H2 | JetBrains Mono | 36–48px | 700 | 1.2 | +| H3 | JetBrains Mono | 24–32px | 600 | 1.3 | | H4 / Subheading | JetBrains Mono | 20px | 500 | 1.4 | | Body large | IBM Plex Sans | 18px | 400 | 1.75 | | Body | IBM Plex Sans | 16px | 400 | 1.7 | @@ -113,8 +144,14 @@ Fonts loaded via `next/font/google` in `src/app/layout.tsx`. Never use a ` ### Spacing - Base unit: 4px (Tailwind default) -- Section vertical padding: `py-24` desktop, `py-16` mobile -- Max content width: `max-w-5xl` (1024px), centered with `mx-auto px-6` +- Section vertical padding: generally `py-20` to `py-32` on desktop and `py-14` to `py-20` on mobile, based on hierarchy +- Do not give every section identical vertical spacing; vary rhythm deliberately while preserving clear separation +- Standard desktop content width: `max-w-7xl` (1280px), centered +- Hero and media-led layouts may use up to `max-w-[1440px]` when the composition benefits from it +- Editorial prose and long-form reading content stays narrow at `max-w-3xl` +- Page introductions may use `max-w-4xl`, but should be left-aligned by default +- Responsive page gutters: `px-6 md:px-8 lg:px-10 xl:px-12` +- Full-width color bands must contain a properly constrained inner layout; do not place body copy directly against viewport edges ### Component Styles @@ -122,54 +159,70 @@ Fonts loaded via `next/font/google` in `src/app/layout.tsx`. Never use a ` Navbar: bg-white border-b border-[#C4CAD6], sticky top Button primary: bg-[#121F38] text-white hover:bg-[#1A2D4F] Button secondary: border border-[#C4CAD6] text-[#121F38] hover:bg-[#F4F5F8] -Cards: bg-[#F4F5F8] border border-[#C4CAD6] rounded-lg +Cards: choose the lightest appropriate treatment — open editorial, white with a light border, or surface background Inputs: bg-white border border-[#C4CAD6] text-[#121F38] rounded-md Active/selected: bg-[#D1D6E0] text-[#121F38] Badge / tag: bg-[#D1D6E0] text-[#121F38] -Footer: bg-[#F4F5F8] border-t border-[#C4CAD6] +Footer: bg-[#121F38] text-white; secondary copy/icons use #D1D6E0 ``` ### Design Direction - **Professional, not generic.** Must feel like a real company website — not AI-generated. -- **Minimal and clean.** Strong typography, clear messaging, generous whitespace. -- **Content balance: 70% text, 30% images.** +- **Clean, but not plain.** Strong typography, clear messaging, generous whitespace, and intentional visual moments. Minimal does not mean empty, cold, or limited to white/gray/navy. +- **Text-led, not text-only.** Use imagery, illustration, photography, texture, interactive visuals, motion, and rich editorial layouts where they add evidence, product context, African market context, identity, or emotional clarity. - **Light theme only.** No dark mode. No `dark:` Tailwind variants. -- **No animations.** Nothing moves. No keyframes, no motion libraries. -- **Minimal hover effects.** Color or opacity changes only. -- **No UI component libraries.** Build everything from scratch with Tailwind. -- **No gradients.** Solid colors only. -- **Use borders sparingly.** Prefer spacing and background contrast. -- **No shadows** except subtle `shadow-sm` on cards where needed. -- **No visual clutter.** Every element must earn its place. -- **No generic AI-style layouts.** +- **Purposeful motion is allowed.** Motion may be used in hero visuals, section reveals, interactive illustrations, and storytelling moments when it is subtle, performance-safe, and disabled by `prefers-reduced-motion`. +- **Hover effects should feel controlled.** Use color, opacity, transform, shadow, or underline effects when they improve feedback. Avoid excessive movement or gimmicks. +- **Public site uses custom components.** shadcn/ui is permitted only in the admin dashboard; never use it to define the public site's visual identity. +- **Gradients are allowed sparingly.** Use gradients only when they support atmosphere, depth, or storytelling. Avoid generic purple/blue SaaS gradients and decorative blobs. +- **Use borders intentionally.** Borders, spacing, color contrast, backgrounds, imagery, and depth can all be used to create hierarchy. +- **Shadows are allowed sparingly.** Use soft, intentional depth for layered UI, editorial cards, media surfaces, floating panels, or interactive elements. Avoid heavy default shadows. +- **Visual richness is allowed.** The site can use stronger section compositions, color, illustration, real media, product screenshots, African technology context, and brand storytelling when it supports the company narrative. +- **No generic AI-style layouts.** Avoid arbitrary blobs, stock-looking sections, template-heavy cards, fake dashboards, and visual filler. + +### Desktop Composition + +- The current visual-design phase is desktop-led. Establish and approve the 1280px and 1440px compositions first, then perform dedicated tablet and mobile refinement. +- Mobile layouts must remain functional during desktop work, but mobile visual polish may follow after the desktop system is approved. +- Public page headings and section introductions are left-aligned by default. Center text only when it creates a deliberate editorial focal point. +- Avoid stacking every section inside the same centered `max-w-5xl` container. +- Use wider desktop grids, asymmetric columns, editorial rows, split layouts, full-width color bands, and varied media proportions where they improve hierarchy. +- Section-to-section rhythm should vary. Do not repeat the same heading-plus-three-identical-cards composition throughout a page. +- Preserve readable line lengths: wide containers are for composition, not for stretching paragraphs across the full width. +- Cards are not the default container. Prefer open layouts and spacing when content does not require a framed boundary. +- Use one strong compositional idea per section. Avoid decorative filler, nested cards, excessive badges, or arbitrary shapes. ### Logo Usage Logo files in `public/logos/`: -- **Full logo SVG** (`/public/logos/wordmark.svg`) — Navbar, Footer, formal contexts -- **Icon-only SVG** (`/public/logos/mark.svg`) — small spaces, mobile nav +- **Full logo SVG** (`/public/logos/wordmark.svg`) — Footer and formal contexts +- **Icon-only SVG** (`/public/logos/mark.svg`) — Navbar, mobile nav, and compact spaces - **PNG** (`/public/fav-icon/logo.png`) — favicon only - Never recreate the logo in code. Always use the actual files. - Navbar logo always links to `/` ### Icons -- **Never install an icon library** (no lucide-react, heroicons package, react-icons, etc.) -- All icons live in the shared file `src/components/ui/icons.tsx` -- Only add icons to icons.tsx that are actually used — never pre-populate with unused icons -- Import only what you need in each component — named imports only -- SVG paths sourced from heroicons.com or lucide.dev — copy raw SVG markup only -- All SVGs: appropriate size per context, stroke="currentColor" or fill="#121F38" -- **Never use emojis as UI icons** — always use inline SVGs from icons.tsx +- **`lucide-react` is the only approved icon library.** Do not install Heroicons, React Icons, Font Awesome, or another icon package. +- Use Lucide icons for standard interface actions, navigation, controls, arrows, status indicators, and common symbols whenever a suitable icon exists. +- Import Lucide icons by name only. Never import the complete library or create dynamic icon maps that prevent tree-shaking. +- Keep icon sizing and stroke weight consistent within each interface. Use `currentColor` so icons inherit the surrounding text color. +- The shared file `src/components/ui/icons.tsx` remains available only for brand marks, social-network logos, or a genuinely custom icon that Lucide does not provide. +- Do not duplicate a Lucide icon manually inside `icons.tsx`. +- Only add custom icons that are actually used; never pre-populate unused icons. +- **Never use emojis as UI icons.** Use Lucide or an approved custom icon from `icons.tsx`. ```tsx -// CORRECT — named import from shared icons file -import { TrophyIcon, ArrowRightIcon } from '@/components/ui/icons' +// CORRECT — named imports from the approved library +import { ArrowRight, Menu, Search } from 'lucide-react' + +// CORRECT — custom brand/social icon not available in Lucide +import { TiktokIcon } from '@/components/ui/icons' -// WRONG — never install or import from icon libraries -import { Trophy } from 'lucide-react' -import * as Icons from '@/components/ui/icons' // never import everything +// WRONG — no alternate icon libraries or wildcard imports +import { TrophyIcon } from '@heroicons/react/24/outline' +import * as Icons from 'lucide-react' ``` --- @@ -183,16 +236,10 @@ codeddevs-website/ │ │ ├── (public)/ │ │ │ ├── layout.tsx │ │ │ ├── page.tsx # Home -│ │ │ ├── about/page.tsx -│ │ │ ├── products/ -│ │ │ │ ├── page.tsx -│ │ │ │ └── [slug]/page.tsx │ │ │ ├── blog/ -│ │ │ │ ├── page.tsx # displayed as "Updates" +│ │ │ │ ├── page.tsx │ │ │ │ └── [slug]/page.tsx │ │ │ ├── team/page.tsx -│ │ │ ├── careers/page.tsx -│ │ │ └── contact/page.tsx │ │ ├── admin/ │ │ │ ├── layout.tsx │ │ │ ├── login/page.tsx @@ -200,21 +247,13 @@ codeddevs-website/ │ │ │ ├── team/ (page, new, [id]) │ │ │ ├── products/ (page, new, [id]) │ │ │ ├── blog/ (page, new, [id]) -│ │ │ ├── careers/ (page, new, [id]) -│ │ │ ├── applications/page.tsx -│ │ │ └── messages/page.tsx │ │ ├── api/ │ │ │ ├── auth/[...nextauth]/route.ts -│ │ │ ├── contact/route.ts -│ │ │ ├── careers/apply/route.ts │ │ │ ├── upload/route.ts │ │ │ └── admin/ │ │ │ ├── team/ (route, [id]) │ │ │ ├── products/ (route, [id]) │ │ │ ├── blog/ (route, [id]) -│ │ │ ├── careers/ (route, [id]) -│ │ │ ├── applications/ (route, [id]) -│ │ │ └── messages/ (route, [id]) │ │ ├── layout.tsx │ │ ├── not-found.tsx │ │ ├── robots.ts @@ -234,21 +273,23 @@ codeddevs-website/ │ │ │ └── icons.tsx # shared inline SVG icons │ │ ├── sections/ │ │ │ ├── HeroSection.tsx -│ │ │ ├── ProductsSection.tsx +│ │ │ ├── FeaturedStorySection.tsx │ │ │ ├── LatestReleasesSection.tsx │ │ │ ├── RecognitionSection.tsx -│ │ │ ├── AboutTeaser.tsx -│ │ │ └── TeamSection.tsx │ │ ├── blog/ │ │ │ └── PostContent.tsx -│ │ ├── careers/ -│ │ │ └── ApplicationForm.tsx -│ │ ├── contact/ -│ │ │ └── ContactForm.tsx │ │ └── admin/ -│ │ ├── RichTextEditor.tsx -│ │ ├── ImageUpload.tsx # includes react-image-crop -│ │ └── DataTable.tsx +│ │ ├── actions/ +│ │ │ └── AdminDeleteButton.tsx +│ │ ├── editors/ +│ │ │ └── RichTextEditor.tsx +│ │ ├── forms/ +│ │ │ └── ResourceForms.tsx +│ │ ├── media/ +│ │ │ └── ImageUpload.tsx # includes react-image-crop +│ │ ├── tables/ +│ │ │ ├── DataTable.tsx +│ │ └── ui/ # shadcn-generated admin primitives only │ ├── db/ │ │ ├── index.ts │ │ ├── schema.ts @@ -264,6 +305,7 @@ codeddevs-website/ ├── scripts/ │ └── seed-admin.ts # gitignored — local use only ├── drizzle.config.ts +├── components.json # shadcn CLI config; admin UI alias points to components/admin/ui ├── middleware.ts ├── next.config.mjs ├── tailwind.config.ts @@ -311,27 +353,6 @@ Values: `'1st' | '2nd' | '3rd' | 'winner' | null` Only relevant when show_in_recognition is true. Displayed as an inline SVG icon + label from icons.tsx — never as an emoji. -### careers -```ts -id, title, type, location, description, -requirements, is_open, created_at, updated_at -``` - -**type enum:** `'full-time' | 'contract' | 'volunteer'` - -### career_applications -```ts -id, career_id (→ careers.id onDelete cascade), -full_name, email, portfolio_url, github_url, -cover_letter, status, created_at -``` - -**status enum:** `'pending' | 'reviewed' | 'rejected'` - -### contact_submissions -```ts -id, full_name, email, subject, message, is_read, created_at -``` ### admin_users ```ts @@ -351,8 +372,6 @@ NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME= NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET= CLOUDINARY_API_KEY= CLOUDINARY_API_SECRET= -RESEND_API_KEY= -CONTACT_NOTIFICATION_EMAIL=codeddevs.team@gmail.com ``` **Local development:** `.env.local` points to Neon `dev` branch connection strings. @@ -367,8 +386,6 @@ Use `DATABASE_URL_UNPOOLED` only in `drizzle.config.ts` for migrations. ### Public | Method | Route | Description | |---|---|---| -| POST | `/api/contact` | Save + email notification | -| POST | `/api/careers/apply` | Save + email notification | ### Admin (401 if no session) | Method | Route | Description | @@ -380,12 +397,6 @@ Use `DATABASE_URL_UNPOOLED` only in `drizzle.config.ts` for migrations. | GET/PUT/DELETE | `/api/admin/products/[id]` | Read / update / delete | | GET/POST | `/api/admin/blog` | List / create | | GET/PUT/DELETE | `/api/admin/blog/[id]` | Read / update / delete | -| GET/POST | `/api/admin/careers` | List / create | -| GET/PUT/DELETE | `/api/admin/careers/[id]` | Read / update / delete | -| GET | `/api/admin/applications` | List | -| PUT | `/api/admin/applications/[id]` | Update status | -| GET | `/api/admin/messages` | List | -| PUT/DELETE | `/api/admin/messages/[id]` | Mark read / delete | ### Upload folder routing - Team photos → `?folder=team` @@ -410,23 +421,38 @@ All uploads go to `codeddevs-website/[folder]/` in Cloudinary. ## 9. Page Content & Structure +### Public navigation model + +- Internal navigation is company-focused: Blog and Team, with product CTAs linking externally. +- Do not include an internal "Products" navigation link. +- The primary navigation CTA is **"Try twizrr"** and links directly to `https://twizrr.com`. +- Product CTAs always open externally with `target="_blank"` and `rel="noopener noreferrer"`. +- On mobile, "Try twizrr" remains a clear CTA inside the navigation menu. +- Footer product links point directly to the external product website; they never point to `/products`. +- The navbar uses `mark.svg`; the footer uses `wordmark.svg`. +- Keep primary navigation concise. Deeper company, editorial, product, and external-resource links belong in the footer. +- If CodedDevs launches multiple products later, the primary CTA may become a compact product menu. Every product destination must still be external unless the user explicitly changes this architecture. + +This follows the company/product separation demonstrated by Anthropic: company-level information remains on the corporate site, while the primary product action sends visitors to the product experience. + ### Home (/) -Six sections in this exact order: +Five sections in this exact order: **1. Hero** - Headline: "Engineering Software That Works for Africa" - Subtext: "We build AI-first software products for African markets — from first principles, not adaptations." -- CTAs: "See Our Products" → /products | "Get in Touch" → /contact -- Kody mascot (kodyfigma.svg — neutral) featured in hero +- CTA: "Try twizrr" -> https://twizrr.com (external) +- Kody mascot (`kody.svg` — neutral/confident) featured in hero -**2. Products Section** -- Heading: "What We're Building" -- Fetches products where is_featured = true -- Cards: name, tagline, status badge, external link +**2. Featured Story** +- Uses the most recent published blog post as the editorial lead +- Shows cover image when available, category, title, excerpt, date, and a link to `/blog/[slug]` +- Product updates, company announcements, roadmaps, and stories all use this same editorial system +- Do not create a separate Twizrr or product spotlight on the home page **3. Latest Releases** - Heading: "Latest Releases" -- Fetches 3 most recent published posts (ALL categories) +- Fetches the next 3 most recent published posts after the featured story (ALL categories) - Cards: title, excerpt, date, category badge, dynamic CTA **4. Recognition** @@ -437,17 +463,6 @@ Six sections in this exact order: - Placement display uses inline SVG icons from icons.tsx — never emojis - If no recognition posts exist, section does not render in production -**5. About Teaser** -- Company mission — 2 paragraphs -- No "Meet the Team" link — TeamSection below handles that - -**6. Team Section** -- Heading: "The Team" -- Shows only 3 founders (order_index 0, 1, 2) -- Each card: photo (80x80 rounded-full), name, role — no bio -- "Meet the full team →" link to /team -- TeamSection fetches its own data internally — no props from page.tsx - ### Empty states behaviour Sections behave differently based on environment: ```ts @@ -457,25 +472,20 @@ const isDev = process.env.NODE_ENV === 'development' // In production: return null (hide section completely) ``` -This applies to: ProductsSection, LatestReleasesSection, RecognitionSection, TeamSection. +This applies to: FeaturedStorySection, LatestReleasesSection, and RecognitionSection. Empty state style: bg-[#F4F5F8] rounded-lg p-8, text-sm text-[#6B7896], centered. -### About (/about) -- Mission, approach, open-source commitment -- Company facts: RC 9426867 | Lagos, Nigeria | Est. March 2026 -### Products (/products) -- Lists all products from DB ordered by order_index -- Each card: name, tagline, status badge -- Links to /products/[slug] (internal) and external_url (external) +### Product presence +- There is no `/products` page and no `/products/[slug]` page. +- Products are introduced through company blog posts and direct external CTAs. +- Twizrr does not receive a standalone home-page spotlight. Product updates and featured blog stories provide that context. +- Product-specific marketing, onboarding, pricing, and detailed feature content belong on the product's own website. +- twizrr links to `https://twizrr.com` and must never be recreated as an internal CodedDevs product page. +- Product-related blog posts remain on `/blog` because they are company updates and editorial content. -### Products — Dedicated Page (/products/[slug]) -- Full product page: name, tagline, description, status, cover image -- External link + GitHub link -- Related blog posts - -### Blog (/blog) — displayed as "Updates" -- URL stays /blog. All user-facing labels say "Updates" +### Blog (/blog) +- URL stays /blog. - Lists published posts ordered by published_at DESC - Filterable by: All | Product Update | Announcement | Roadmap | Story - Each card: category badge, title, excerpt, author, date, dynamic CTA @@ -495,25 +505,14 @@ By [author] · [formatted date] · [X min read] - Fetches ALL team_members where is_active = true, ordered by order_index - Each card: photo, name, role, bio, social links - Founders: - - **Kareem Aliameen — Founder & CEO** - Kareem is the Founder and CEO of CodedDevs Technology LTD, leading the company's strategy, product vision and development, and technical direction. A full-stack engineer working primarily in JavaScript and TypeScript, he is highly skilled at leveraging AI for development, research, and productivity. He brings a background spanning graphic design, digital commerce, and entrepreneurship, and is currently studying at Miva University. - - **Yusuf Ibrahim Ayinla — Co-Founder & CTO** - Yusuf is the Co-Founder and CTO of CodedDevs Technology LTD, responsible for the technical architecture across the company's products. A full-stack engineer working in JavaScript and TypeScript, he is highly skilled at leveraging AI for development and research, and is known for his curiosity, depth of thinking, and ability to move quickly across technologies. - - **Amoo Mustakheem Olamilekan — Co-Founder & COO** - Mustakheem is the Co-Founder and COO of CodedDevs Technology LTD, leading business development, partnerships, and growth strategy. A full-stack engineer with a background in Node.js and Python, he brings strong skills in networking, outreach, and identifying opportunities. - -### Careers (/careers) -- Lists open roles -- Empty state: "No open roles right now. Send us a message." → /contact -- Application form: inline below role card, 'use client' - -### Contact (/contact) -- Two columns desktop, stacked mobile -- Left: company info, email, social links -- Right: contact form -- Subjects: General Inquiry | Partnership | Press | Investment | Other -- Email: codeddevs.team@gmail.com -- Socials: GitHub, X, TikTok, YouTube, Instagram + - **Kareem Aliameen - Founder & CEO** + Kareem is a Founder of CodedDevs Technology LTD, helping lead company strategy, product direction, and technical execution. + - **Yusuf Saheed - Co-Founder** + Yusuf is a Co-Founder of CodedDevs Technology LTD, helping shape the company's technical direction and product development across software, payments, commerce, and AI. + - **Amoo Mustakheem - Co-Founder** + Mustakheem is a Co-Founder of CodedDevs Technology LTD, helping lead operations, partnerships, business development, and growth strategy. + + --- @@ -522,8 +521,8 @@ By [author] · [formatted date] · [X min read] ### Static brand assets → `public/` only - `/public/logos/wordmark.svg` — full logo - `/public/logos/mark.svg` — icon only -- `/public/mascot/kody-smilefigma.svg` — smiling Kody -- `/public/mascot/kodyfigma.svg` — neutral Kody +- `/public/mascot/kodysmile.svg` — smiling Kody +- `/public/mascot/kody.svg` — neutral/confident Kody - `/public/fav-icon/logo.png` — favicon - Nothing else goes in public/ @@ -562,8 +561,8 @@ getProductCoverUrl(url) // f_auto,q_auto,w_1200,h_630,c_fill | File | Variant | Use where | |---|---|---| -| `kody-smilefigma.svg` | Smiling | 404 page, empty states, contact page | -| `kodyfigma.svg` | Neutral/confident | Hero section, careers page | +| `kodysmile.svg` | Smiling | 404 page and empty states | +| `kody.svg` | Neutral/confident | Optional hero visual | - Never smaller than 120px - Always on white or light surface @@ -584,8 +583,12 @@ const [products, posts] = await Promise.all([...]) ``` ### Selective columns -- Blog list: never fetch `content` column -- Products list: never fetch `description` on list view +- Blog list and home editorial queries: never fetch the `content` column + +### Sitemap rules +- Include company routes: `/`, `/blog`, and `/team` +- Include published `/blog/[slug]` routes +- Do not include `/products` or `/products/[slug]`; product destinations are external ### Caching note (Next.js 15) In Next.js 15, `fetch()` is NOT cached by default. If using fetch() directly in server components, add appropriate cache settings explicitly. @@ -647,27 +650,26 @@ export default async function Page({ 4. Zod validation on every API route that accepts a body 5. pnpm only — never npm or yarn 6. Cloudinary for all content images — use transformation helpers -7. Resend for all email — never nodemailer or sendgrid 8. next/font/google for fonts — no CDN link tags -9. No UI component libraries on public pages — build from scratch with Tailwind. Exception: `react-image-crop` in `ImageUpload.tsx` admin only +9. Public pages use custom Tailwind components only. shadcn/ui and react-image-crop are admin-only and must never be imported by a public page or public component 10. cn() for all conditional classNames -11. No animations — nothing moves +11. Purposeful motion is allowed when it supports storytelling, interaction, or hierarchy. Motion must be performance-safe and respect `prefers-reduced-motion` 12. Light theme only — no dark: variants -13. No gradients — solid colors only +13. Gradients are allowed sparingly when they support atmosphere, depth, or storytelling. Avoid generic SaaS gradients and decorative blobs 14. TypeScript strict — no any, no @ts-ignore 15. @/ imports only — no relative ../../ imports 16. Product/external links always target="_blank" rel="noopener noreferrer" 17. migrations/ is read-only — only Drizzle Kit writes here 18. Logo files only — never recreate logo in code 19. "Products" not "Projects" — everywhere in UI, routes, and code -20. Blog URL /blog, displayed as "Updates" in all user-facing labels +20. Blog URL /blog, displayed as "blog" in all user-facing labels 21. Use borders sparingly — prefer spacing and background contrast 22. Design must feel human, not AI-generated -23. No emojis in UI components — use inline SVG icons from icons.tsx only -24. Never install icon libraries — use shared icons.tsx with raw SVG paths +23. No emojis in UI components — use Lucide icons or approved custom icons from icons.tsx +24. `lucide-react` is the only approved icon library. Use named imports; reserve shared `icons.tsx` for brand/social or genuinely custom icons unavailable in Lucide 25. Always await params and searchParams in dynamic route pages (Next.js 15) 26. seed scripts go in scripts/ folder and are gitignored — never commit them -27. Mobile-first responsive design always. Use Tailwind breakpoints in this order: base (mobile) → md (tablet 768px) → lg (desktop 1024px). Never design desktop-first and patch mobile after. +27. The current visual-design phase is desktop-led: establish the 1280px and 1440px compositions first, then refine tablet and mobile. Implementation must remain responsive and mobile must stay functional throughout. --- @@ -677,7 +679,7 @@ export default async function Page({ |---|---| | Company | CODEDDEVS TECHNOLOGY LTD | | RC Number | 9426867 | -| Incorporated | 18 March 2026 | +| Incorporated | March 2026 | | Location | Lagos, Nigeria | | Email | codeddevs.team@gmail.com | | GitHub | github.com/coded-devs | @@ -685,7 +687,11 @@ export default async function Page({ | TikTok | @CodedDevs | | YouTube | @CodedDevs | | Instagram | @codeddevs_ | -| Main product | twizrr → twizrr.com | +| Founders | Kareem Aliameen, Yusuf Saheed, Amoo Mustakheem | +| Team model | Three founders supported by a growing team of designers, developers, and creators | +| Focus | Software, payment, and AI products for African markets | +| Core belief | The African market deserves technology built for it, not borrowed or adapted | +| Main product | twizrr -> twizrr.com | --- @@ -720,7 +726,7 @@ Record saved to team_members table ↓ Within 1 hour: - Appears on /team page (full bio, all details) -- Appears in TeamSection on home page (photo + name + role only, limit 3) +- Does not create a separate team preview on the home page ``` ### Product → public site @@ -733,26 +739,12 @@ Sets external_url (e.g. twizrr.com) Record saved to products table ↓ Within 1 hour: -- Appears on /products list -- Appears on home page Products section (if is_featured = true) -- Has its own page at /products/[slug] +- Product-related public communication appears through published blog posts +- Navbar, hero, and footer Twizrr actions link to the external product website +- Product records do not create or appear on an internal product listing, detail page, or home-page spotlight ``` -### Contact form → admin -``` -Visitor submits /contact form -POST /api/contact validates → saves to contact_submissions -Sends email via Resend to CONTACT_NOTIFICATION_EMAIL -Admin reads in /admin/messages, marks as read -``` -### Career application → admin -``` -Visitor applies on /careers -POST /api/careers/apply validates → verifies role is open -Saves to career_applications → sends email notification -Admin reviews in /admin/applications, updates status -``` --- @@ -760,13 +752,22 @@ Admin reviews in /admin/applications, updates status | Section | URL | What it controls | |---|---|---| -| Dashboard | /admin/dashboard | Overview stats, recent messages, recent applications | -| Team | /admin/team | Team member profiles on /team and TeamSection on home | -| Products | /admin/products | Products on /products and home page | +| Dashboard | /admin/dashboard | Overview stats for team members, products, and blog posts | +| Team | /admin/team | Team member profiles on /team | +| Products | /admin/products | Stored product records for internal content management; not currently rendered as a public spotlight | | Blog | /admin/blog | All posts — /blog, Latest Releases, Recognition | -| Careers | /admin/careers | Job listings on /careers | -| Applications | /admin/applications | Career applications | -| Messages | /admin/messages | Contact form submissions | + +### Admin UI system + +- Use shadcn/ui for standard admin controls: forms, fields, selects, switches, checkboxes, dialogs, alert dialogs, dropdown menus, tabs, tables, pagination, tooltips, toasts, skeletons, and empty states. +- shadcn is an admin implementation system, not the visual design language of the public website. +- Generate shadcn components into `src/components/admin/ui/`; never overwrite the custom public primitives in `src/components/ui/`. +- Configure the shadcn `ui` alias as `@/components/admin/ui` in `components.json`. +- Use the existing CodedDevs semantic colors and font variables when styling admin components. Do not replace the brand tokens in `src/app/globals.css` with shadcn defaults. +- Add components selectively through the shadcn CLI. Do not install every registry component upfront. +- Prefer accessible shadcn primitives over hand-rolled admin dialogs, selects, dropdowns, switches, and confirmation prompts. +- Existing custom admin components may be migrated incrementally. Do not rewrite the entire dashboard in one uncontrolled pass. +- Public components must not import from `@/components/admin/ui`. ### Blog admin — controls three public areas simultaneously - `/blog` list — all published posts @@ -885,10 +886,12 @@ export async function GET() { --- -## 21. Responsive Design Rules +## 21. Desktop-Led Responsive Design Rules ### Core principle -**Mobile-first always.** Every component is designed for mobile (375px) first, then enhanced for larger screens using Tailwind breakpoints. Never write desktop styles first and try to patch mobile after. +**Desktop composition first for the current redesign.** Establish visual hierarchy, width usage, section rhythm, and spatial balance at 1280px and 1440px first. Then adapt the approved system to tablet and mobile without changing its underlying hierarchy. + +Tailwind may still use mobile-first utilities technically. The design-review order is desktop first, followed by tablet and mobile refinement. Mobile must remain usable during the desktop pass even when final mobile polish is deferred. ### Breakpoints ``` @@ -896,7 +899,8 @@ base → 0px+ mobile phones (375px target) sm → 640px+ large phones / small tablets (use sparingly) md → 768px+ tablets lg → 1024px+ desktop (most layout changes happen here) -xl → 1280px+ large desktop (use sparingly) +xl → 1280px+ primary desktop composition target +2xl → 1536px+ wide desktop; preserve the 1440px maximum composition width ``` ### Layout rules per section @@ -904,34 +908,31 @@ xl → 1280px+ large desktop (use sparingly) **Navbar:** ``` mobile: hamburger menu, logo left, menu button right -lg: full nav links visible, logo left, CTA button right +lg: full nav links visible, logo left, CTA button right, max-w-7xl inner container ``` **Hero section:** ``` -mobile: single column, text stacked, Kody mascot hidden -lg: two columns — text left (flex-1), Kody right (w-80) +mobile: single column, text stacked, hero visual below text when present +lg: spacious editorial composition — text left, optional visual/media right, max-w-7xl or up to 1440px ``` -**Products section:** +Hero visuals are optional and may be a mascot, illustration, real media, product image, interactive visual, or background composition. Kody is not mandatory in the hero. + +**Featured Story:** ``` -mobile: single column, full width cards -lg: max-w-xl cards, left-aligned — do not stretch to full width +mobile: single-column editorial story with media above or below the copy +lg: wide editorial split layout with lead-story copy and cover image ``` **Latest Releases & Recognition:** ``` mobile: grid-cols-1 (single column) md: grid-cols-2 -lg: grid-cols-3 -gap: gap-6 at all breakpoints +lg: grid-cols-3 or an asymmetric lead-plus-supporting composition +gap: gap-6 minimum; use larger desktop gaps when the layout benefits ``` -**About page — two-column sections:** -``` -mobile: stacked — heading above, body below -lg: flex-row — heading left (w-1/3), body right (flex-1) -``` **Team section (home page):** ``` @@ -946,29 +947,25 @@ md: grid-cols-2 lg: grid-cols-3 ``` -**Contact page:** -``` -mobile: stacked — info above, form below -lg: two columns — info left (w-1/3), form right (flex-1) -``` **Footer:** ``` -mobile: stacked — logo+tagline, then nav columns, then bottom bar -lg: logo+tagline left, nav columns right, bottom bar as row +mobile: stacked — medium wordmark, two-column navigation groups, then ownership/social details +lg: navy full-width band; medium wordmark and bottom-aligned ownership/socials on the left, Product, Highlights, Company, and Connect link groups on the right ``` ### Typography scaling ``` -H1 hero: text-4xl md:text-5xl lg:text-7xl -H2 section: text-2xl md:text-3xl lg:text-[40px] -H3: text-xl md:text-2xl +H1 hero: text-4xl md:text-5xl lg:text-6xl xl:text-7xl +H1 page: text-4xl md:text-5xl lg:text-[56px] +H2 section: text-2xl md:text-3xl lg:text-[40px] xl:text-5xl when appropriate +H3: text-xl md:text-2xl lg:text-[28px] Body: text-base (16px) — never scale down on mobile ``` ### What hides or shows at different breakpoints ``` -Kody mascot in Hero: hidden on mobile, block on lg +Hero visual/media: optional; stack below text on mobile, place beside text on lg when used Full nav links: hidden on mobile, flex on lg Hamburger menu: flex on mobile, hidden on lg Two-column layouts: stack on mobile, side-by-side on lg @@ -976,15 +973,15 @@ Two-column layouts: stack on mobile, side-by-side on lg ### Testing checklist Before committing any visual design work, test at these widths: -- 375px — iPhone SE (smallest target) -- 390px — iPhone 14 +- 1440px — primary large-desktop design target +- 1280px — standard desktop design target +- 1024px — small desktop / iPad landscape - 768px — iPad portrait -- 1024px — iPad landscape / small desktop -- 1280px — standard desktop -- 1440px — large desktop +- 390px — iPhone 14 +- 375px — smallest supported mobile target -Use browser DevTools responsive mode. Never ship a change that breaks any of these widths. +Use browser DevTools responsive mode. Desktop approval comes first in this redesign, but never ship a change that breaks any supported width. --- -*Last updated: May 2026* +*Last updated: June 2026* diff --git a/README.md b/README.md index 71e1d0d..0430eab 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,21 @@ Official company website and internal CMS for **CODEDDEVS TECHNOLOGY LTD**. -- **Live:** codeddevs.com (pending) -- **Framework:** Next.js 15, App Router, TypeScript -- **Runtime:** React 19 -- **Tech:** Tailwind, Drizzle ORM, Neon PostgreSQL -- **Audience:** Investors, press, and partners -- This site presents CODEDDEVS as a product-driven technology company building AI-first software for African markets. The public site is aimed at investors, press, and partners. The admin dashboard is used to manage products, updates, team members, careers, messages, applications, and uploaded media. - - **Live URL:** https://codeddevs.com - **Company:** CODEDDEVS TECHNOLOGY LTD - **RC Number:** 9426867 - **Location:** Lagos, Nigeria -- **Contact:** codeddevs.team@gmail.com +- **Email:** codeddevs.team@gmail.com +- **Framework:** Next.js 15, App Router, TypeScript +- **Runtime:** React 19 +- **Tech:** Tailwind, Drizzle ORM, Neon PostgreSQL +- **Audience:** Investors, press, partners, collaborators, and people who want to understand what CodedDevs is building + +This site presents CODEDDEVS as a product-driven Nigerian technology company building software, payment, and AI products for African markets. The public site is intentionally lean: home, blog, blog posts, and team. The admin dashboard manages team members, products, blog posts, and uploaded media. ## Tech Stack -- **Framework:** Next.js 14, App Router, TypeScript +- **Framework:** Next.js 15, App Router, TypeScript - **Styling:** Tailwind CSS - **Database:** Neon PostgreSQL - **ORM:** Drizzle ORM @@ -25,7 +24,7 @@ Official company website and internal CMS for **CODEDDEVS TECHNOLOGY LTD**. - **Editor:** TipTap rich text editor - **Images:** Cloudinary - **Image cropping:** react-image-crop, admin only -- **Email:** Resend +- **Icons:** lucide-react - **Fonts:** JetBrains Mono and IBM Plex Sans via `next/font/google` - **Package manager:** pnpm only @@ -37,7 +36,6 @@ Official company website and internal CMS for **CODEDDEVS TECHNOLOGY LTD**. - pnpm - Neon PostgreSQL database - Cloudinary account -- Resend account ### Install @@ -64,8 +62,6 @@ NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME= NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET= CLOUDINARY_API_KEY= CLOUDINARY_API_SECRET= -RESEND_API_KEY= -CONTACT_NOTIFICATION_EMAIL= ``` Use: @@ -73,7 +69,6 @@ Use: - `DATABASE_URL` for app queries. - `DATABASE_URL_UNPOOLED` for Drizzle migrations. - `NEXTAUTH_SECRET` from a secure random value. -- `CONTACT_NOTIFICATION_EMAIL` for contact and application notifications. ### Database @@ -122,14 +117,11 @@ pnpm tsc --noEmit ## Public Pages - `/` - Home -- `/about` - Company mission and approach -- `/products` - Product list -- `/products/[slug]` - Individual product page -- `/blog` - User-facing label is "Updates" -- `/blog/[slug]` - Editorial update page +- `/blog` - Blog list +- `/blog/[slug]` - Editorial blog post page - `/team` - Team page -- `/careers` - Careers page with application form -- `/contact` - Contact page and form + +The public website is intentionally focused around the home page, company stories, and the team. Products are introduced through company blog updates and link to their external product websites. Twizrr is available at [twizrr.com](https://twizrr.com). ## Admin Dashboard @@ -140,21 +132,15 @@ Protected routes live under `/admin`. - `/admin/team` - `/admin/products` - `/admin/blog` -- `/admin/careers` -- `/admin/applications` -- `/admin/messages` Admin API routes live under `/api/admin/*` and require an authenticated admin session. ## Core Features -- Product CMS with featured products for the home page. -- Updates CMS backed by TipTap JSON content. -- Recognition section controlled by `show_in_recognition` and `placement` fields on blog posts. +- Product CMS for internal product records and external product links. +- Blog CMS backed by TipTap JSON content. +- Recognition metadata controlled by `show_in_recognition` and `placement` fields on blog posts. - Team member CMS. -- Careers CMS with public application form. -- Contact form with Resend notification. -- Career application notification emails. - Cloudinary uploads with route-based folders: - `codeddevs-website/team` - `codeddevs-website/products` @@ -182,8 +168,6 @@ src/ components/ admin/ blog/ - careers/ - contact/ layout/ sections/ ui/ @@ -195,7 +179,6 @@ src/ lib/ auth.ts cloudinary.ts - email.ts utils.ts types/ index.ts @@ -213,11 +196,10 @@ Important rules: - Use Zod validation on API routes that accept input. - Check authentication first on every admin API route. - Use Cloudinary for content images. -- Use shared inline SVG icons from `src/components/ui/icons.tsx`. -- Do not install icon libraries. -- Do not use dark mode, gradients, or animations. +- Use lucide-react as the only icon library. +- Do not use dark mode. - Do not use "Projects"; the correct term is "Products". -- The `/blog` route must be labeled as "Updates" in user-facing UI. +- The `/blog` route must be labeled as "Blog" in user-facing UI. - Never commit secrets. `.env.local` must stay untracked. ## CI diff --git a/components.json b/components.json new file mode 100644 index 0000000..c92a88e --- /dev/null +++ b/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "base-nova", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/admin/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/design-qa.md b/design-qa.md new file mode 100644 index 0000000..8e54b50 --- /dev/null +++ b/design-qa.md @@ -0,0 +1,26 @@ +# Design QA + +## Footer redesign + +- Reference: `C:\Users\HP\AppData\Local\Temp\codex-clipboard-17c41149-c52a-43bf-a577-0af846de2616.png` +- Implementation capture: in-app browser at `http://localhost:3000/#footer` +- Desktop viewport: 1515 x 1252 +- Responsive check: two-column navigation below the desktop breakpoint, with ownership metadata moved beneath the links + +### Comparison + +- Layout: passed. The implementation follows the reference's left ownership rail and right navigation matrix while using fewer columns because CodedDevs currently has fewer real destinations. +- Typography: passed. Brand fonts are retained; compact uppercase group labels create the same scanning hierarchy without copying Anthropic's type system. +- Spacing: passed. The wordmark is medium-sized, navigation columns have even gutters, and company metadata remains bottom-aligned on desktop. +- Color: passed. The reference's black footer is intentionally translated to CodedDevs navy `#121F38`, with white headings and muted light-blue secondary text. +- Copy and links: passed. All visible links point to existing pages, homepage anchors, or verified external destinations; no placeholder policy links were introduced. +- Responsive behavior: passed. No horizontal overflow was detected, and the navigation collapses to two columns on smaller screens. +- Accessibility: passed. Navigation groups have headings, icon-only social links have accessible labels, and external links identify their destination through link text or labels. + +### Patches after comparison + +- Reduced the wordmark from an oversized treatment to a 175-190px responsive width. +- Corrected an invalid fixed-height utility so the logo preserves its intrinsic aspect ratio. +- Forced footer navigation headings to white to prevent the global heading color from reducing contrast. + +Final result: passed diff --git a/eslint.config.mjs b/eslint.config.mjs index de9a3d6..60ef6ba 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,7 @@ import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; -import { fixupConfigRules } from "@eslint/compat"; import { FlatCompat } from "@eslint/eslintrc"; +import nextPlugin from "@next/eslint-plugin-next"; import { defineConfig, globalIgnores } from "eslint/config"; const __filename = fileURLToPath(import.meta.url); @@ -12,12 +12,31 @@ const compat = new FlatCompat({ }); const eslintConfig = defineConfig([ - ...fixupConfigRules( - compat.extends("next/core-web-vitals", "next/typescript"), + ...compat.extends( + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:jsx-a11y/recommended", + "plugin:@typescript-eslint/recommended", ), - // Override default ignores of eslint-config-next. + { + files: ["**/*.{js,mjs,cjs,ts,tsx}"], + plugins: { + "@next/next": nextPlugin, + }, + rules: { + ...nextPlugin.configs["core-web-vitals"].rules, + "react/react-in-jsx-scope": "off", + "react/prop-types": "off", + "@typescript-eslint/no-unused-vars": "warn", + "@typescript-eslint/no-unused-expressions": "warn", + }, + settings: { + react: { + version: "detect", + }, + }, + }, globalIgnores([ - // Default ignores of eslint-config-next: ".next/**", "out/**", "build/**", diff --git a/package.json b/package.json index fc7e6a0..4074b0f 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "lint": "eslint" }, "dependencies": { + "@base-ui/react": "^1.6.0", "@neondatabase/serverless": "^1.1.0", - "@react-email/components": "^1.0.12", "@tiptap/extension-image": "^3.22.5", "@tiptap/extension-link": "^3.22.5", "@tiptap/extension-placeholder": "^3.22.5", @@ -18,24 +18,25 @@ "@tiptap/react": "^3.22.5", "@tiptap/starter-kit": "^3.22.5", "bcryptjs": "^3.0.3", + "class-variance-authority": "^0.7.1", "cloudinary": "^2.10.0", "clsx": "^2.1.1", "drizzle-orm": "^0.45.2", + "lucide-react": "^1.21.0", "next": "^15.5.15", "next-auth": "5.0.0-beta.31", "react": "19.2.5", "react-dom": "19.2.5", - "react-email": "^6.0.5", "react-image-crop": "^11.0.10", - "resend": "^6.12.2", + "shadcn": "^4.11.0", "tailwind-merge": "^3.5.0", + "tw-animate-css": "^1.4.0", "zod": "^4.4.1" }, "devDependencies": { - "@eslint/compat": "^2.0.5", "@eslint/eslintrc": "3.3.5", + "@next/eslint-plugin-next": "15.5.15", "@tailwindcss/postcss": "^4", - "@types/bcryptjs": "^3.0.0", "@types/node": "^20", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5dcb064..34f8e37 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,12 @@ importers: .: dependencies: + '@base-ui/react': + specifier: ^1.6.0 + version: 1.6.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@neondatabase/serverless': specifier: ^1.1.0 version: 1.1.0 - '@react-email/components': - specifier: ^1.0.12 - version: 1.0.12(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@tiptap/extension-image': specifier: ^3.22.5 version: 3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5)) @@ -35,6 +35,9 @@ importers: bcryptjs: specifier: ^3.0.3 version: 3.0.3 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 cloudinary: specifier: ^2.10.0 version: 2.10.0 @@ -44,46 +47,46 @@ importers: drizzle-orm: specifier: ^0.45.2 version: 0.45.2(@neondatabase/serverless@1.1.0) + lucide-react: + specifier: ^1.21.0 + version: 1.21.0(react@19.2.5) next: specifier: ^15.5.15 - version: 15.5.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 15.5.15(@babel/core@7.29.7)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) next-auth: specifier: 5.0.0-beta.31 - version: 5.0.0-beta.31(next@15.5.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) + version: 5.0.0-beta.31(next@15.5.15(@babel/core@7.29.7)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) react: specifier: 19.2.5 version: 19.2.5 react-dom: specifier: 19.2.5 version: 19.2.5(react@19.2.5) - react-email: - specifier: ^6.0.5 - version: 6.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-image-crop: specifier: ^11.0.10 version: 11.0.10(react@19.2.5) - resend: - specifier: ^6.12.2 - version: 6.12.2(@react-email/render@2.0.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) + shadcn: + specifier: ^4.11.0 + version: 4.11.0(typescript@5.9.3) tailwind-merge: specifier: ^3.5.0 version: 3.5.0 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 zod: specifier: ^4.4.1 version: 4.4.1 devDependencies: - '@eslint/compat': - specifier: ^2.0.5 - version: 2.0.5(eslint@9.39.4(jiti@2.6.1)) '@eslint/eslintrc': specifier: 3.3.5 version: 3.3.5 + '@next/eslint-plugin-next': + specifier: 15.5.15 + version: 15.5.15 '@tailwindcss/postcss': specifier: ^4 version: 4.2.4 - '@types/bcryptjs': - specifier: ^3.0.0 - version: 3.0.0 '@types/node': specifier: ^20 version: 20.19.39 @@ -133,51 +136,201 @@ packages: resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.29.7': + resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.29.7': + resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.29.7': + resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.29.7': + resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.27.0': - resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} '@babel/parser@7.29.3': resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.29.7': + resolution: {integrity: sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.29.7': + resolution: {integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.29.7': + resolution: {integrity: sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.27.0': - resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} engines: {node: '>=6.9.0'} '@babel/types@7.29.0': resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@base-ui/react@1.6.0': + resolution: {integrity: sha512-/jzjTWJYXhRFO45Bev9lc3cHbmjzCMpUqbMZ2AgKy/z25mY9B6shGSNcXcjQar9n5doM0KYW1W8fcFv2jZBuMw==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@date-fns/tz': ^1.2.0 + '@types/react': ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@date-fns/tz': + optional: true + '@types/react': + optional: true + date-fns: + optional: true + + '@base-ui/utils@0.3.1': + resolution: {integrity: sha512-gFFiltORVmW/N6IILTGxizP3PBpVpysqML1ALY5Vk0mH+7faVkCknOU31goYHN5Aoek2dkjxva1XOD2Ce9WuIg==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@dotenvx/dotenvx@1.75.1': + resolution: {integrity: sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==} + hasBin: true + + '@dotenvx/primitives@0.8.0': + resolution: {integrity: sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==} + '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/core@1.11.2': + resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==} '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} @@ -199,12 +352,6 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.28.0': - resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/android-arm64@0.18.20': resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -223,12 +370,6 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.28.0': - resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm@0.18.20': resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} @@ -247,12 +388,6 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.28.0': - resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-x64@0.18.20': resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} @@ -271,12 +406,6 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.28.0': - resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/darwin-arm64@0.18.20': resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} @@ -295,12 +424,6 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.28.0': - resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-x64@0.18.20': resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} @@ -319,12 +442,6 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.28.0': - resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/freebsd-arm64@0.18.20': resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} @@ -343,12 +460,6 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.28.0': - resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-x64@0.18.20': resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} @@ -367,12 +478,6 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.28.0': - resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/linux-arm64@0.18.20': resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} @@ -391,12 +496,6 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.28.0': - resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm@0.18.20': resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} @@ -415,12 +514,6 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.28.0': - resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-ia32@0.18.20': resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} @@ -439,12 +532,6 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.28.0': - resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-loong64@0.18.20': resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} @@ -463,12 +550,6 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.28.0': - resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-mips64el@0.18.20': resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} @@ -487,12 +568,6 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.28.0': - resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-ppc64@0.18.20': resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} @@ -511,12 +586,6 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.28.0': - resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-riscv64@0.18.20': resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} @@ -535,12 +604,6 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.28.0': - resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-s390x@0.18.20': resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} @@ -559,12 +622,6 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.28.0': - resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-x64@0.18.20': resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} @@ -583,12 +640,6 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.28.0': - resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} @@ -601,12 +652,6 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.28.0': - resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-x64@0.18.20': resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} @@ -625,12 +670,6 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.28.0': - resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} @@ -643,12 +682,6 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.28.0': - resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-x64@0.18.20': resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} @@ -667,12 +700,6 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.28.0': - resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} @@ -685,12 +712,6 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.28.0': - resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/sunos-x64@0.18.20': resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} @@ -709,12 +730,6 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.28.0': - resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/win32-arm64@0.18.20': resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} @@ -733,12 +748,6 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.28.0': - resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-ia32@0.18.20': resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} @@ -757,12 +766,6 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.28.0': - resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-x64@0.18.20': resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} @@ -781,12 +784,6 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.28.0': - resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -797,15 +794,6 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@2.0.5': - resolution: {integrity: sha512-IbHDbHJfkVNv6xjlET8AIVo/K1NQt7YT4Rp6ok/clyBGcpRx1l6gv0Rq3vBvYfPJIZt6ODf66Zq08FJNDpnzgg==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - peerDependencies: - eslint: ^8.40 || 9 || 10 - peerDependenciesMeta: - eslint: - optional: true - '@eslint/config-array@0.21.2': resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -818,10 +806,6 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@1.2.1': - resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/eslintrc@3.3.5': resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -844,9 +828,21 @@ packages: '@floating-ui/dom@1.7.6': resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -1036,6 +1032,16 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1120,249 +1126,61 @@ packages: '@panva/hkdf@1.2.1': resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} - '@react-email/body@0.3.0': - resolution: {integrity: sha512-uGo0BOOzjbMUo3lu+BIDWayvn5o6Xyfmnlla5VGf05n8gHMvO1ll7U4FtzWe3hxMLwt53pmc4iE0M+B5slG+Ug==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/button@0.2.1': - resolution: {integrity: sha512-qXyj7RZLE7POy9BMKSoqQ00tOXThjOZSUnI2Yu9i29IHngPlmrNayIWBoVKtElES7OWwypUcpiajwi1mUWx6/A==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/code-block@0.2.1': - resolution: {integrity: sha512-M3B7JpVH4ytgn83/ujRR1k1DQHvTeABiDM61OvAbjLRPhC/5KLHU5KkzIbbuGIrjWwxAbL1kSQzU8MhLEtSxyw==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@react-email/code-inline@0.0.6': - resolution: {integrity: sha512-jfhebvv3dVsp3OdPgKXnk8+e2pBiDVZejDOBFzBa/IblrAJ9cQDkN6rBD5IyEg8hTOxwbw3iaI/yZFmDmIguIA==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@rushstack/eslint-patch@1.16.1': + resolution: {integrity: sha512-TvZbIpeKqGQQ7X0zSCvPH9riMSFQFSggnfBjFZ1mEoILW+UuXCKwOoPcgjMwiUtRqFZ8jWhPJc4um14vC6I4ag==} - '@react-email/column@0.0.14': - resolution: {integrity: sha512-f+W+Bk2AjNO77zynE33rHuQhyqVICx4RYtGX9NKsGUg0wWjdGP0qAuIkhx9Rnmk4/hFMo1fUrtYNqca9fwJdHg==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@react-email/components@1.0.12': - resolution: {integrity: sha512-tH18JhPDWgE+3jnYkzyB6ZrZdfNnEsFe4PwmuXmlOw4NGIysP8wPY5aXZg++pTG9qUabXg1nzX/FGHGkObH8xQ==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} - '@react-email/container@0.0.16': - resolution: {integrity: sha512-QWBB56RkkU0AJ9h+qy33gfT5iuZknPC7Un/IjZv9B0QmMIK+WWacc0cH6y2SV5Cv/b99hU94fjEMOOO4enpkbQ==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@react-email/font@0.0.10': - resolution: {integrity: sha512-0urVSgCmQIfx5r7Xc586miBnQUVnGp3OTYUm8m5pwtQRdTRO5XrTtEfNJ3JhYhSOruV0nD8fd+dXtKXobum6tA==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@tailwindcss/node@4.2.4': + resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} - '@react-email/head@0.0.13': - resolution: {integrity: sha512-AJg6le/08Gz4tm+6MtKXqtNNyKHzmooOCdmtqmWxD7FxoAdU1eVcizhtQ0gcnVaY6ethEyE/hnEzQxt1zu5Kog==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@tailwindcss/oxide-android-arm64@4.2.4': + resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] - '@react-email/heading@0.0.16': - resolution: {integrity: sha512-jmsKnQm1ykpBzw4hCYHwBkt5pW2jScXffPeEH5ZRF5tZeF5b1pvlFTO9han7C0pCkZYo1kEvWiRtx69yfCIwuw==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@tailwindcss/oxide-darwin-arm64@4.2.4': + resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] - '@react-email/hr@0.0.12': - resolution: {integrity: sha512-TwmOmBDibavUQpXBxpmZYi2Iks/yeZOzFYh+di9EltMSnEabH8dMZXrl+pxNXzCgZ2XE8HY7VmUL65Lenfu5PA==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@tailwindcss/oxide-darwin-x64@4.2.4': + resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] - '@react-email/html@0.0.12': - resolution: {integrity: sha512-KTShZesan+UsreU7PDUV90afrZwU5TLwYlALuCSU0OT+/U8lULNNbAUekg+tGwCnOfIKYtpDPKkAMRdYlqUznw==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@tailwindcss/oxide-freebsd-x64@4.2.4': + resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] - '@react-email/img@0.0.12': - resolution: {integrity: sha512-sRCpEARNVTf3FQhZOC+JTvu5r6ubiYWkT0ucYXg8ctkyi4G8QG+jgYPiNUqVeTLA2STOfmPM/nrk1nb84y6CPQ==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': + resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] - '@react-email/link@0.0.13': - resolution: {integrity: sha512-lkWc/NjOcefRZMkQoSDDbuKBEBDES9aXnFEOuPH845wD3TxPwh+QTf0fStuzjoRLUZWpHnio4z7qGGRYusn/sw==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/markdown@0.0.18': - resolution: {integrity: sha512-gSuYK5fsMbGk87jDebqQ6fa2fKcWlkf2Dkva8kMONqLgGCq8/0d+ZQYMEJsdidIeBo3kmsnHZPrwdFB4HgjUXg==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/preview@0.0.14': - resolution: {integrity: sha512-aYK8q0IPkBXyMsbpMXgxazwHxYJxTrXrV95GFuu2HbEiIToMwSyUgb8HDFYwPqqfV03/jbwqlsXmFxsOd+VNaw==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/render@2.0.6': - resolution: {integrity: sha512-xOzaYkH3jLZKqN5MqrTXYnmqBYUnZSVbkxdb5PGGmDcK6sKDVMliaDiSwfXajRC9JtSHTcGc2tmGLHWuCgVpog==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/render@2.0.8': - resolution: {integrity: sha512-5udvVr3U/WuGJZfLdLBOhkzrqRWd2Q5ZYmF7ppcy7FzWcwgshdqLMNqJOXcVzAXJXg/2bm7D+WGJzTtZOZMQnQ==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/row@0.0.13': - resolution: {integrity: sha512-bYnOac40vIKCId7IkwuLAAsa3fKfSfqCvv6epJKmPE0JBuu5qI4FHFCl9o9dVpIIS08s/ub+Y/txoMt0dYziGw==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/section@0.0.17': - resolution: {integrity: sha512-qNl65ye3W0Rd5udhdORzTV9ezjb+GFqQQSae03NDzXtmJq6sqVXNWNiVolAjvJNypim+zGXmv6J9TcV5aNtE/w==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/tailwind@2.0.7': - resolution: {integrity: sha512-kGw80weVFXikcnCXbigTGXGWQ0MRCSYNCudcdkWxebkWYd0FG6/NPoN3V1p/u68/4+NxZwYPVi2fhnp0x23HdA==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - '@react-email/body': '>=0' - '@react-email/button': '>=0' - '@react-email/code-block': '>=0' - '@react-email/code-inline': '>=0' - '@react-email/container': '>=0' - '@react-email/heading': '>=0' - '@react-email/hr': '>=0' - '@react-email/img': '>=0' - '@react-email/link': '>=0' - '@react-email/preview': '>=0' - '@react-email/text': '>=0' - react: ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@react-email/body': - optional: true - '@react-email/button': - optional: true - '@react-email/code-block': - optional: true - '@react-email/code-inline': - optional: true - '@react-email/container': - optional: true - '@react-email/heading': - optional: true - '@react-email/hr': - optional: true - '@react-email/img': - optional: true - '@react-email/link': - optional: true - '@react-email/preview': - optional: true - - '@react-email/text@0.1.6': - resolution: {integrity: sha512-TYqkioRS45wTR5il3dYk/SbUjjEdhSwh9BtRNB99qNH1pXAwA45H7rAuxehiu8iJQJH0IyIr+6n62gBz9ezmsw==} - engines: {node: '>=20.0.0'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@rushstack/eslint-patch@1.16.1': - resolution: {integrity: sha512-TvZbIpeKqGQQ7X0zSCvPH9riMSFQFSggnfBjFZ1mEoILW+UuXCKwOoPcgjMwiUtRqFZ8jWhPJc4um14vC6I4ag==} - - '@selderee/plugin-htmlparser2@0.11.0': - resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} - - '@socket.io/component-emitter@3.1.2': - resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - - '@stablelib/base64@1.0.1': - resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} - - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - - '@tailwindcss/node@4.2.4': - resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} - - '@tailwindcss/oxide-android-arm64@4.2.4': - resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.2.4': - resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.2.4': - resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.2.4': - resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': - resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': - resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [glibc] + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': + resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.2.4': resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==} @@ -1575,15 +1393,11 @@ packages: '@tiptap/starter-kit@3.22.5': resolution: {integrity: sha512-LZ/LYbwH6rnDi5DnRyagkuNsYAVyhM+yJvvz+ZuYA0JkPiTXJV86J5PWSKew8M0gVfMHcNVtKjfQCvViFCeIgw==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - - '@types/bcryptjs@3.0.0': - resolution: {integrity: sha512-WRZOuCuaz8UcZZE4R5HXTco2goQSI2XxjGY3hbM/xDvwmqFWd4ivooImsMx65OKM6CtNKbnZ5YL+YwAwK7c1dg==} - deprecated: This is a stub types definition. bcryptjs provides its own type definitions, so you do not need this installed. + '@ts-morph/common@0.27.0': + resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} - '@types/cors@2.8.19': - resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -1608,8 +1422,8 @@ packages: '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@types/validate-npm-package-name@4.0.2': + resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} '@typescript-eslint/eslint-plugin@8.59.1': resolution: {integrity: sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag==} @@ -1773,8 +1587,8 @@ packages: cpu: [x64] os: [win32] - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} acorn-jsx@5.3.2: @@ -1787,6 +1601,18 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -1801,6 +1627,18 @@ packages: ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -1847,12 +1685,17 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} - atomically@2.1.1: - resolution: {integrity: sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==} + atomically@1.7.0: + resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==} + engines: {node: '>=10.12.0'} available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} @@ -1873,14 +1716,19 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - base64id@2.0.0: - resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} - engines: {node: ^4.5.0 || >= 5.9} + baseline-browser-mapping@2.10.38: + resolution: {integrity: sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==} + engines: {node: '>=6.0.0'} + hasBin: true bcryptjs@3.0.3: resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==} hasBin: true + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + brace-expansion@1.1.14: resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} @@ -1892,9 +1740,22 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1918,12 +1779,20 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} - citty@0.2.2: - resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} @@ -1936,6 +1805,9 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + code-block-writer@13.0.3: + resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1943,16 +1815,39 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - commander@13.1.0: - resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} - engines: {node: '>=18'} + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - conf@15.1.0: - resolution: {integrity: sha512-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og==} - engines: {node: '>=20'} + conf@10.2.0: + resolution: {integrity: sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==} + engines: {node: '>=12'} + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} @@ -1962,13 +1857,23 @@ packages: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} + cosmiconfig@9.0.2: + resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-tree@3.2.1: - resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -1976,6 +1881,10 @@ packages: damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -1988,13 +1897,9 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - debounce-fn@6.0.0: - resolution: {integrity: sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==} - engines: {node: '>=18'} - - debounce@2.2.0: - resolution: {integrity: sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==} - engines: {node: '>=18'} + debounce-fn@4.0.0: + resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==} + engines: {node: '>=10'} debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} @@ -2013,6 +1918,14 @@ packages: supports-color: optional: true + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -2020,38 +1933,53 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-prop@6.0.1: + resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} + engines: {node: '>=10'} - dot-prop@10.1.0: - resolution: {integrity: sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==} - engines: {node: '>=20'} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} drizzle-kit@0.31.10: resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} @@ -2153,28 +2081,36 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.376: + resolution: {integrity: sha512-cUVA7/RvbFTEuw/i3obUwDTRIXojaxkResf+ibByPFxjc6XK3VNtcQXV0NSbAlJ0FMjcJGgftVVB4Qo184EXvA==} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - engine.io-parser@5.2.3: - resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} - engines: {node: '>=10.0.0'} - - engine.io@6.6.7: - resolution: {integrity: sha512-DgOngfDKM2EviOH3Mr9m7ks1q8roetLy/IMmYthAYzbpInMbYc/GS+fWFA3rl1gvwKVsQrVV61fo5emD1y3OJQ==} - engines: {node: '>=10.2.0'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} enhanced-resolve@5.21.0: resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==} engines: {node: '>=10.13.0'} - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} - env-paths@3.0.0: - resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} es-abstract@1.24.2: resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} @@ -2223,10 +2159,12 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.28.0: - resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} - engines: {node: '>=18'} - hasBin: true + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} @@ -2336,6 +2274,11 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -2352,6 +2295,36 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.1.0: + resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} + engines: {node: ^18.19.0 || >=20.5.0} + + express-rate-limit@8.5.2: + resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -2363,15 +2336,16 @@ packages: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-sha256@1.3.0: - resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} - fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} @@ -2387,6 +2361,14 @@ packages: picomatch: optional: true + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2395,6 +2377,14 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -2410,6 +2400,22 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs-extra@11.3.5: + resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} + engines: {node: '>=14.14'} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2425,18 +2431,41 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + fuzzysort@3.1.0: + resolution: {integrity: sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==} + generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-own-enumerable-keys@1.0.0: + resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} + engines: {node: '>=14.16'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} @@ -2452,14 +2481,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@13.0.6: - resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} - engines: {node: 18 || 20 || >=22} - - globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -2502,12 +2523,29 @@ packages: resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} - html-to-text@9.0.5: - resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} - engines: {node: '>=14'} + hono@4.12.26: + resolution: {integrity: sha512-uyZtpnYxM9CmQ7QsQknM4zN8EftNqhON1qYeIKM0Se67CCEe2c44xyGURwB0axX2fBDu1dqHrHAc1hmNT8ITkw==} + engines: {node: '>=16.9.0'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} + engines: {node: '>=18.18.0'} - htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} @@ -2525,14 +2563,28 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + ip-address@10.2.0: + resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -2564,6 +2616,16 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2580,6 +2642,19 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -2596,10 +2671,29 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-obj@3.0.0: + resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==} + engines: {node: '>=12'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} + is-regexp@3.1.0: + resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} + engines: {node: '>=12'} + is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} @@ -2608,6 +2702,14 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -2620,6 +2722,10 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + is-unicode-supported@2.1.0: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} @@ -2636,20 +2742,28 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} + iterator.prototype@1.1.5: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} - jiti@2.4.2: - resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} - hasBin: true - jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -2672,12 +2786,18 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@7.0.3: + resolution: {integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==} + json-schema-typed@8.0.2: resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} @@ -2693,6 +2813,9 @@ packages: engines: {node: '>=6'} hasBin: true + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -2704,6 +2827,10 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -2711,9 +2838,6 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} - leac@0.6.0: - resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} - levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -2792,9 +2916,16 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + linkifyjs@4.3.2: resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -2805,32 +2936,39 @@ packages: lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - log-symbols@7.0.1: - resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lru-cache@11.3.5: - resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} - engines: {node: 20 || >=22} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@1.21.0: + resolution: {integrity: sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - marked@15.0.12: - resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} - engines: {node: '>= 18'} - hasBin: true - math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - mdn-data@2.27.1: - resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} @@ -2840,22 +2978,22 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - mime-db@1.54.0: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - mime-types@3.0.2: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-fn@3.1.0: + resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} + engines: {node: '>=8'} + mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -2870,10 +3008,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2890,8 +3024,8 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} next-auth@5.0.0-beta.31: @@ -2931,18 +3065,30 @@ packages: sass: optional: true + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-exports-info@1.6.0: resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} engines: {node: '>= 0.4'} - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - nypm@0.6.6: - resolution: {integrity: sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q==} + node-releases@2.0.48: + resolution: {integrity: sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==} + engines: {node: '>=18'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} - hasBin: true oauth4webapi@3.8.6: resolution: {integrity: sha512-iwemM91xz8nryHti2yTmg5fhyEMVOkOXwHNqbvcATjyajb5oQxCQzrNOA6uElRHuMhQQTKUyFKV9y/CNyg25BQ==} @@ -2959,6 +3105,10 @@ packages: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + object-treeify@1.1.33: + resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} + engines: {node: '>= 10'} + object.assign@4.1.7: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} @@ -2979,10 +3129,37 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + orderedmap@2.1.1: resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} @@ -2990,20 +3167,48 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parseley@0.12.1: - resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -3013,18 +3218,15 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@2.0.2: - resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} - engines: {node: 18 || 20 || >=22} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - peberminta@0.9.0: - resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3037,16 +3239,21 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - picospinner@3.0.0: - resolution: {integrity: sha512-lGA1TNsmy2bxvRsTI2cV01kfTwKzZjnZSDmF9llYNyMHMrU4sP87lQ5taiIKm88L3cbswjl008nwyGc3WpNvzg==} - engines: {node: '>=18.0.0'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + pkg-up@3.1.0: + resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} + engines: {node: '>=8'} possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postal-mime@2.7.4: - resolution: {integrity: sha512-0WdnFQYUrPGGTFu1uOqD2s7omwua8xaeYGdO6rb88oD5yJ/4pPHDA4sdWqfD8wQVfCny563n/HQS7zTFft+f/g==} + postcss-selector-parser@7.1.4: + resolution: {integrity: sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==} + engines: {node: '>=4'} postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} @@ -3056,6 +3263,10 @@ packages: resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} engines: {node: ^10 || ^12 || >=14} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + preact-render-to-string@6.5.11: resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==} peerDependencies: @@ -3068,14 +3279,9 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.3: - resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} - engines: {node: '>=14'} - hasBin: true - - prismjs@1.30.0: - resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} - engines: {node: '>=6'} + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} @@ -3120,26 +3326,34 @@ packages: prosemirror-view@1.41.8: resolution: {integrity: sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} + engines: {node: '>=0.6'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + react-dom@19.2.5: resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} peerDependencies: react: ^19.2.5 - react-email@6.0.5: - resolution: {integrity: sha512-uQRqBcd9buZ7tbjvxprVrz1BclNWPXHtGeveZJjV1qtTczZjdWp3KddmanD5nlH1UbqHx32pC0Nh93PoMRbVGw==} - engines: {node: '>=20.0.0'} - hasBin: true - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - react-image-crop@11.0.10: resolution: {integrity: sha512-+5FfDXUgYLLqBh1Y/uQhIycpHCbXkI50a+nbfkB1C0xXXUTwkisHDo2QCB1SQJyHCqIuia4FeyReqXuMDKWQTQ==} peerDependencies: @@ -3152,9 +3366,9 @@ packages: resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} @@ -3168,14 +3382,8 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - resend@6.12.2: - resolution: {integrity: sha512-xwgmU4b0OqoabJsIoK/x0Whk0Fcs3bpbK4i/DEWPiE5hYJHyHl0TbB6QbI3gIr+bLdLUJ1GYm/fe41aVFuHXgw==} - engines: {node: '>=20'} - peerDependencies: - '@react-email/render': '*' - peerDependenciesMeta: - '@react-email/render': - optional: true + reselect@5.2.0: + resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} @@ -3189,6 +3397,10 @@ packages: engines: {node: '>= 0.4'} hasBin: true + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -3196,6 +3408,14 @@ packages: rope-sequence@1.3.4: resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -3211,12 +3431,12 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - selderee@0.11.0: - resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -3226,6 +3446,14 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3238,6 +3466,13 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shadcn@4.11.0: + resolution: {integrity: sha512-UV0cchFea9hO7poV1CuEP0wvmYjpAqcxCKdy23bndl2Du2ARtDs8A4xdzfhUjDBeOW1nNpJ6lXmsEpsply2SfQ==} + hasBin: true + sharp@0.34.5: resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -3266,19 +3501,15 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - socket.io-adapter@2.5.6: - resolution: {integrity: sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - socket.io-parser@4.2.6: - resolution: {integrity: sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==} - engines: {node: '>=10.0.0'} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} - socket.io@4.8.3: - resolution: {integrity: sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==} - engines: {node: '>=10.2.0'} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} @@ -3294,13 +3525,22 @@ packages: stable-hash@0.0.5: resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} - standardwebhooks@1.0.0: - resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + string.prototype.includes@2.0.1: resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} engines: {node: '>= 0.4'} @@ -3324,20 +3564,34 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + stringify-object@5.0.0: + resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} + engines: {node: '>=14.16'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - stubborn-fs@2.0.0: - resolution: {integrity: sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==} - - stubborn-utils@1.0.2: - resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} - styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} @@ -3359,12 +3613,11 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svix@1.90.0: - resolution: {integrity: sha512-ljkZuyy2+IBEoESkIpn8sLM+sxJHQcPxlZFxU+nVDhltNfUMisMBzWX/UR8SjEnzoI28ZjCzMbmYAPwSTucoMw==} - - tagged-tag@1.0.0: - resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} - engines: {node: '>=20'} + systeminformation@5.31.7: + resolution: {integrity: sha512-/8NC53e5nP9nmhn42/ncdOkyJnOoue/Vy+tJOyUGd1Yv66G069wK4rrziwhrqDETgk78CudTQupw5z19S5uoZw==} + engines: {node: '>=8.0.0'} + os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] + hasBin: true tailwind-merge@3.5.0: resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} @@ -3376,9 +3629,8 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tinyexec@1.1.2: - resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} - engines: {node: '>=18'} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} @@ -3388,12 +3640,19 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' + ts-morph@26.0.0: + resolution: {integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==} + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -3409,13 +3668,16 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@5.6.0: - resolution: {integrity: sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==} - engines: {node: '>=20'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} @@ -3438,10 +3700,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - uint8array-extras@1.5.0: - resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} - engines: {node: '>=18'} - unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -3449,9 +3707,31 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@7.28.0: + resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} + engines: {node: '>=20.18.1'} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -3460,10 +3740,12 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - uuid@10.0.0: - resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} - deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). - hasBin: true + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + validate-npm-package-name@7.0.2: + resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} + engines: {node: ^20.17.0 || >=22.9.0} vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} @@ -3472,8 +3754,9 @@ packages: w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - when-exit@2.1.5: - resolution: {integrity: sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} @@ -3496,30 +3779,45 @@ packages: engines: {node: '>= 8'} hasBin: true + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-spinner@1.2.0: + resolution: {integrity: sha512-Yw0hUB6UA3o4YUgKy3oSe9a4cxoaZ9sBfYDw+JSxo6Id0KoJGoxzPA24qqUXYKBWABs/zDSGTz9kww7t3F0XGw==} + engines: {node: '>=18.19'} + yoctocolors@2.1.2: resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} engines: {node: '>=18'} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.4.1: resolution: {integrity: sha512-a6ENMBBGZBsnlSebQ/eKCguSBeGKSf4O7BPnqVPmYGtpBYI7VSqoVqw+QcB7kPRjbqPwhYTpFbVj/RqNz/CT0Q==} @@ -3541,54 +3839,256 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/generator@7.29.1': + '@babel/code-frame@7.29.7': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.7 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-member-expression-to-functions@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.27.0': + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 '@babel/parser@7.29.3': dependencies: '@babel/types': 7.29.0 - '@babel/template@7.28.6': + '@babel/parser@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/traverse@7.27.0': + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/runtime@7.29.7': {} + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 debug: 4.4.3 - globals: 11.12.0 transitivePeerDependencies: - supports-color '@babel/types@7.29.0': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@base-ui/react@1.6.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.7 + '@base-ui/utils': 0.3.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@floating-ui/utils': 0.2.11 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + use-sync-external-store: 1.6.0(react@19.2.5) + optionalDependencies: + '@types/react': 19.2.14 + + '@base-ui/utils@0.3.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@babel/runtime': 7.29.7 + '@floating-ui/utils': 0.2.11 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + reselect: 5.2.0 + use-sync-external-store: 1.6.0(react@19.2.5) + optionalDependencies: + '@types/react': 19.2.14 + + '@dotenvx/dotenvx@1.75.1': + dependencies: + '@dotenvx/primitives': 0.8.0 + commander: 11.1.0 + conf: 10.2.0 + dotenv: 17.4.2 + enquirer: 2.4.1 + env-paths: 2.2.1 + execa: 5.1.1 + fdir: 6.5.0(picomatch@4.0.4) + ignore: 5.3.2 + object-treeify: 1.1.33 + open: 8.4.2 + picomatch: 4.0.4 + systeminformation: 5.31.7 + undici: 7.28.0 + which: 4.0.0 + yocto-spinner: 1.2.0 + + '@dotenvx/primitives@0.8.0': {} '@drizzle-team/brocli@0.10.2': {} - '@emnapi/core@1.10.0': + '@emnapi/core@1.11.2': dependencies: - '@emnapi/wasi-threads': 1.2.1 + '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 optional: true @@ -3597,7 +4097,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.1': + '@emnapi/wasi-threads@1.2.2': dependencies: tslib: 2.8.1 optional: true @@ -3618,9 +4118,6 @@ snapshots: '@esbuild/aix-ppc64@0.27.7': optional: true - '@esbuild/aix-ppc64@0.28.0': - optional: true - '@esbuild/android-arm64@0.18.20': optional: true @@ -3630,9 +4127,6 @@ snapshots: '@esbuild/android-arm64@0.27.7': optional: true - '@esbuild/android-arm64@0.28.0': - optional: true - '@esbuild/android-arm@0.18.20': optional: true @@ -3642,9 +4136,6 @@ snapshots: '@esbuild/android-arm@0.27.7': optional: true - '@esbuild/android-arm@0.28.0': - optional: true - '@esbuild/android-x64@0.18.20': optional: true @@ -3654,9 +4145,6 @@ snapshots: '@esbuild/android-x64@0.27.7': optional: true - '@esbuild/android-x64@0.28.0': - optional: true - '@esbuild/darwin-arm64@0.18.20': optional: true @@ -3666,9 +4154,6 @@ snapshots: '@esbuild/darwin-arm64@0.27.7': optional: true - '@esbuild/darwin-arm64@0.28.0': - optional: true - '@esbuild/darwin-x64@0.18.20': optional: true @@ -3678,9 +4163,6 @@ snapshots: '@esbuild/darwin-x64@0.27.7': optional: true - '@esbuild/darwin-x64@0.28.0': - optional: true - '@esbuild/freebsd-arm64@0.18.20': optional: true @@ -3690,9 +4172,6 @@ snapshots: '@esbuild/freebsd-arm64@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.28.0': - optional: true - '@esbuild/freebsd-x64@0.18.20': optional: true @@ -3702,9 +4181,6 @@ snapshots: '@esbuild/freebsd-x64@0.27.7': optional: true - '@esbuild/freebsd-x64@0.28.0': - optional: true - '@esbuild/linux-arm64@0.18.20': optional: true @@ -3714,9 +4190,6 @@ snapshots: '@esbuild/linux-arm64@0.27.7': optional: true - '@esbuild/linux-arm64@0.28.0': - optional: true - '@esbuild/linux-arm@0.18.20': optional: true @@ -3726,9 +4199,6 @@ snapshots: '@esbuild/linux-arm@0.27.7': optional: true - '@esbuild/linux-arm@0.28.0': - optional: true - '@esbuild/linux-ia32@0.18.20': optional: true @@ -3738,9 +4208,6 @@ snapshots: '@esbuild/linux-ia32@0.27.7': optional: true - '@esbuild/linux-ia32@0.28.0': - optional: true - '@esbuild/linux-loong64@0.18.20': optional: true @@ -3750,9 +4217,6 @@ snapshots: '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/linux-loong64@0.28.0': - optional: true - '@esbuild/linux-mips64el@0.18.20': optional: true @@ -3762,9 +4226,6 @@ snapshots: '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/linux-mips64el@0.28.0': - optional: true - '@esbuild/linux-ppc64@0.18.20': optional: true @@ -3774,9 +4235,6 @@ snapshots: '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/linux-ppc64@0.28.0': - optional: true - '@esbuild/linux-riscv64@0.18.20': optional: true @@ -3786,9 +4244,6 @@ snapshots: '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/linux-riscv64@0.28.0': - optional: true - '@esbuild/linux-s390x@0.18.20': optional: true @@ -3798,9 +4253,6 @@ snapshots: '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/linux-s390x@0.28.0': - optional: true - '@esbuild/linux-x64@0.18.20': optional: true @@ -3810,18 +4262,12 @@ snapshots: '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/linux-x64@0.28.0': - optional: true - '@esbuild/netbsd-arm64@0.25.12': optional: true '@esbuild/netbsd-arm64@0.27.7': optional: true - '@esbuild/netbsd-arm64@0.28.0': - optional: true - '@esbuild/netbsd-x64@0.18.20': optional: true @@ -3831,18 +4277,12 @@ snapshots: '@esbuild/netbsd-x64@0.27.7': optional: true - '@esbuild/netbsd-x64@0.28.0': - optional: true - '@esbuild/openbsd-arm64@0.25.12': optional: true '@esbuild/openbsd-arm64@0.27.7': optional: true - '@esbuild/openbsd-arm64@0.28.0': - optional: true - '@esbuild/openbsd-x64@0.18.20': optional: true @@ -3852,18 +4292,12 @@ snapshots: '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.28.0': - optional: true - '@esbuild/openharmony-arm64@0.25.12': optional: true '@esbuild/openharmony-arm64@0.27.7': optional: true - '@esbuild/openharmony-arm64@0.28.0': - optional: true - '@esbuild/sunos-x64@0.18.20': optional: true @@ -3873,9 +4307,6 @@ snapshots: '@esbuild/sunos-x64@0.27.7': optional: true - '@esbuild/sunos-x64@0.28.0': - optional: true - '@esbuild/win32-arm64@0.18.20': optional: true @@ -3885,9 +4316,6 @@ snapshots: '@esbuild/win32-arm64@0.27.7': optional: true - '@esbuild/win32-arm64@0.28.0': - optional: true - '@esbuild/win32-ia32@0.18.20': optional: true @@ -3897,9 +4325,6 @@ snapshots: '@esbuild/win32-ia32@0.27.7': optional: true - '@esbuild/win32-ia32@0.28.0': - optional: true - '@esbuild/win32-x64@0.18.20': optional: true @@ -3909,9 +4334,6 @@ snapshots: '@esbuild/win32-x64@0.27.7': optional: true - '@esbuild/win32-x64@0.28.0': - optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1))': dependencies: eslint: 9.39.4(jiti@2.6.1) @@ -3919,12 +4341,6 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@2.0.5(eslint@9.39.4(jiti@2.6.1))': - dependencies: - '@eslint/core': 1.2.1 - optionalDependencies: - eslint: 9.39.4(jiti@2.6.1) - '@eslint/config-array@0.21.2': dependencies: '@eslint/object-schema': 2.1.7 @@ -3941,10 +4357,6 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/core@1.2.1': - dependencies: - '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.5': dependencies: ajv: 6.15.0 @@ -3971,16 +4383,23 @@ snapshots: '@floating-ui/core@1.7.5': dependencies: '@floating-ui/utils': 0.2.11 - optional: true '@floating-ui/dom@1.7.6': dependencies: '@floating-ui/core': 1.7.5 '@floating-ui/utils': 0.2.11 - optional: true - '@floating-ui/utils@0.2.11': - optional: true + '@floating-ui/react-dom@2.1.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + + '@floating-ui/utils@0.2.11': {} + + '@hono/node-server@1.19.14(hono@4.12.26)': + dependencies: + hono: 4.12.26 '@humanfs/core@0.19.2': dependencies: @@ -4114,11 +4533,33 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.26) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.5.2(express@5.2.1) + hono: 4.12.26 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.10.0 + '@emnapi/core': 1.11.2 '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.3 optional: true '@neondatabase/serverless@1.1.0': {} @@ -4169,149 +4610,13 @@ snapshots: '@panva/hkdf@1.2.1': {} - '@react-email/body@0.3.0(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/button@0.2.1(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/code-block@0.2.1(react@19.2.5)': - dependencies: - prismjs: 1.30.0 - react: 19.2.5 - - '@react-email/code-inline@0.0.6(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/column@0.0.14(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/components@1.0.12(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - '@react-email/body': 0.3.0(react@19.2.5) - '@react-email/button': 0.2.1(react@19.2.5) - '@react-email/code-block': 0.2.1(react@19.2.5) - '@react-email/code-inline': 0.0.6(react@19.2.5) - '@react-email/column': 0.0.14(react@19.2.5) - '@react-email/container': 0.0.16(react@19.2.5) - '@react-email/font': 0.0.10(react@19.2.5) - '@react-email/head': 0.0.13(react@19.2.5) - '@react-email/heading': 0.0.16(react@19.2.5) - '@react-email/hr': 0.0.12(react@19.2.5) - '@react-email/html': 0.0.12(react@19.2.5) - '@react-email/img': 0.0.12(react@19.2.5) - '@react-email/link': 0.0.13(react@19.2.5) - '@react-email/markdown': 0.0.18(react@19.2.5) - '@react-email/preview': 0.0.14(react@19.2.5) - '@react-email/render': 2.0.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@react-email/row': 0.0.13(react@19.2.5) - '@react-email/section': 0.0.17(react@19.2.5) - '@react-email/tailwind': 2.0.7(@react-email/body@0.3.0(react@19.2.5))(@react-email/button@0.2.1(react@19.2.5))(@react-email/code-block@0.2.1(react@19.2.5))(@react-email/code-inline@0.0.6(react@19.2.5))(@react-email/container@0.0.16(react@19.2.5))(@react-email/heading@0.0.16(react@19.2.5))(@react-email/hr@0.0.12(react@19.2.5))(@react-email/img@0.0.12(react@19.2.5))(@react-email/link@0.0.13(react@19.2.5))(@react-email/preview@0.0.14(react@19.2.5))(@react-email/text@0.1.6(react@19.2.5))(react@19.2.5) - '@react-email/text': 0.1.6(react@19.2.5) - react: 19.2.5 - transitivePeerDependencies: - - react-dom - - '@react-email/container@0.0.16(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/font@0.0.10(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/head@0.0.13(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/heading@0.0.16(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/hr@0.0.12(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/html@0.0.12(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/img@0.0.12(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/link@0.0.13(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/markdown@0.0.18(react@19.2.5)': - dependencies: - marked: 15.0.12 - react: 19.2.5 - - '@react-email/preview@0.0.14(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/render@2.0.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - html-to-text: 9.0.5 - prettier: 3.8.3 - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - - '@react-email/render@2.0.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': - dependencies: - html-to-text: 9.0.5 - prettier: 3.8.3 - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - - '@react-email/row@0.0.13(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/section@0.0.17(react@19.2.5)': - dependencies: - react: 19.2.5 - - '@react-email/tailwind@2.0.7(@react-email/body@0.3.0(react@19.2.5))(@react-email/button@0.2.1(react@19.2.5))(@react-email/code-block@0.2.1(react@19.2.5))(@react-email/code-inline@0.0.6(react@19.2.5))(@react-email/container@0.0.16(react@19.2.5))(@react-email/heading@0.0.16(react@19.2.5))(@react-email/hr@0.0.12(react@19.2.5))(@react-email/img@0.0.12(react@19.2.5))(@react-email/link@0.0.13(react@19.2.5))(@react-email/preview@0.0.14(react@19.2.5))(@react-email/text@0.1.6(react@19.2.5))(react@19.2.5)': - dependencies: - '@react-email/text': 0.1.6(react@19.2.5) - react: 19.2.5 - tailwindcss: 4.2.4 - optionalDependencies: - '@react-email/body': 0.3.0(react@19.2.5) - '@react-email/button': 0.2.1(react@19.2.5) - '@react-email/code-block': 0.2.1(react@19.2.5) - '@react-email/code-inline': 0.0.6(react@19.2.5) - '@react-email/container': 0.0.16(react@19.2.5) - '@react-email/heading': 0.0.16(react@19.2.5) - '@react-email/hr': 0.0.12(react@19.2.5) - '@react-email/img': 0.0.12(react@19.2.5) - '@react-email/link': 0.0.13(react@19.2.5) - '@react-email/preview': 0.0.14(react@19.2.5) - - '@react-email/text@0.1.6(react@19.2.5)': - dependencies: - react: 19.2.5 - '@rtsao/scc@1.1.0': {} '@rushstack/eslint-patch@1.16.1': {} - '@selderee/plugin-htmlparser2@0.11.0': - dependencies: - domhandler: 5.0.3 - selderee: 0.11.0 - - '@socket.io/component-emitter@3.1.2': {} + '@sec-ant/readable-stream@0.4.1': {} - '@stablelib/base64@1.0.1': {} + '@sindresorhus/merge-streams@4.0.0': {} '@swc/helpers@0.5.15': dependencies: @@ -4565,18 +4870,16 @@ snapshots: '@tiptap/extensions': 3.22.5(@tiptap/core@3.22.5(@tiptap/pm@3.22.5))(@tiptap/pm@3.22.5) '@tiptap/pm': 3.22.5 - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/bcryptjs@3.0.0': + '@ts-morph/common@0.27.0': dependencies: - bcryptjs: 3.0.3 + fast-glob: 3.3.3 + minimatch: 10.2.5 + path-browserify: 1.0.1 - '@types/cors@2.8.19': + '@tybys/wasm-util@0.10.3': dependencies: - '@types/node': 20.19.39 + tslib: 2.8.1 + optional: true '@types/estree@1.0.8': {} @@ -4598,9 +4901,7 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} - '@types/ws@8.18.1': - dependencies: - '@types/node': 20.19.39 + '@types/validate-npm-package-name@4.0.2': {} '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: @@ -4752,10 +5053,10 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - accepts@1.3.8: + accepts@2.0.0: dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 + mime-types: 3.0.2 + negotiator: 1.0.0 acorn-jsx@5.3.2(acorn@8.16.0): dependencies: @@ -4763,6 +5064,12 @@ snapshots: acorn@8.16.0: {} + agent-base@7.1.4: {} + + ajv-formats@2.1.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: ajv: 8.20.0 @@ -4781,6 +5088,12 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -4858,12 +5171,13 @@ snapshots: ast-types-flow@0.0.8: {} + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + async-function@1.0.0: {} - atomically@2.1.1: - dependencies: - stubborn-fs: 2.0.0 - when-exit: 2.1.5 + atomically@1.7.0: {} available-typed-arrays@1.0.7: dependencies: @@ -4877,10 +5191,24 @@ snapshots: balanced-match@4.0.4: {} - base64id@2.0.0: {} + baseline-browser-mapping@2.10.38: {} bcryptjs@3.0.3: {} + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.2 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 @@ -4894,8 +5222,22 @@ snapshots: dependencies: fill-range: 7.1.1 + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.38 + caniuse-lite: 1.0.30001791 + electron-to-chromium: 1.5.376 + node-releases: 2.0.48 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + buffer-from@1.1.2: {} + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + bytes@3.1.2: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -4922,11 +5264,17 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - chokidar@4.0.3: + chalk@5.6.2: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + cli-cursor@5.0.0: dependencies: - readdirp: 4.1.2 + restore-cursor: 5.1.0 - citty@0.2.2: {} + cli-spinners@2.9.2: {} client-only@0.0.1: {} @@ -4936,27 +5284,42 @@ snapshots: clsx@2.1.1: {} + code-block-writer@13.0.3: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} - commander@13.1.0: {} + commander@11.1.0: {} + + commander@14.0.3: {} concat-map@0.0.1: {} - conf@15.1.0: + conf@10.2.0: dependencies: ajv: 8.20.0 - ajv-formats: 3.0.1(ajv@8.20.0) - atomically: 2.1.1 - debounce-fn: 6.0.0 - dot-prop: 10.1.0 - env-paths: 3.0.0 - json-schema-typed: 8.0.2 + ajv-formats: 2.1.1(ajv@8.20.0) + atomically: 1.7.0 + debounce-fn: 4.0.0 + dot-prop: 6.0.1 + env-paths: 2.2.1 + json-schema-typed: 7.0.3 + onetime: 5.1.2 + pkg-up: 3.1.0 semver: 7.7.4 - uint8array-extras: 1.5.0 + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.2.2: {} cookie@0.7.2: {} @@ -4965,21 +5328,29 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cosmiconfig@9.0.2(typescript@5.9.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.9.3 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - css-tree@3.2.1: - dependencies: - mdn-data: 2.27.1 - source-map-js: 1.2.1 + cssesc@3.0.0: {} csstype@3.2.3: {} damerau-levenshtein@1.0.8: {} + data-uri-to-buffer@4.0.1: {} + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -4998,11 +5369,9 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - debounce-fn@6.0.0: + debounce-fn@4.0.0: dependencies: - mimic-function: 5.0.1 - - debounce@2.2.0: {} + mimic-fn: 3.1.0 debug@3.2.7: dependencies: @@ -5012,49 +5381,50 @@ snapshots: dependencies: ms: 2.1.3 + dedent@1.7.2: {} + deep-is@0.1.4: {} deepmerge@4.3.1: {} + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + define-lazy-prop@2.0.0: {} + + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 + depd@2.0.0: {} + detect-libc@2.1.2: {} + diff@8.0.4: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - domutils@3.2.2: + dot-prop@6.0.1: dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 + is-obj: 2.0.0 - dot-prop@10.1.0: - dependencies: - type-fest: 5.6.0 + dotenv@17.4.2: {} drizzle-kit@0.31.10: dependencies: @@ -5073,35 +5443,31 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - emoji-regex@9.2.2: {} + ee-first@1.1.1: {} - engine.io-parser@5.2.3: {} + electron-to-chromium@1.5.376: {} - engine.io@6.6.7: - dependencies: - '@types/cors': 2.8.19 - '@types/node': 20.19.39 - '@types/ws': 8.18.1 - accepts: 1.3.8 - base64id: 2.0.0 - cookie: 0.7.2 - cors: 2.8.6 - debug: 4.4.3 - engine.io-parser: 5.2.3 - ws: 8.18.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate + emoji-regex@10.6.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} enhanced-resolve@5.21.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 - entities@4.5.0: {} + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + + env-paths@2.2.1: {} - env-paths@3.0.0: {} + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 es-abstract@1.24.2: dependencies: @@ -5287,34 +5653,9 @@ snapshots: '@esbuild/win32-ia32': 0.27.7 '@esbuild/win32-x64': 0.27.7 - esbuild@0.28.0: - optionalDependencies: - '@esbuild/aix-ppc64': 0.28.0 - '@esbuild/android-arm': 0.28.0 - '@esbuild/android-arm64': 0.28.0 - '@esbuild/android-x64': 0.28.0 - '@esbuild/darwin-arm64': 0.28.0 - '@esbuild/darwin-x64': 0.28.0 - '@esbuild/freebsd-arm64': 0.28.0 - '@esbuild/freebsd-x64': 0.28.0 - '@esbuild/linux-arm': 0.28.0 - '@esbuild/linux-arm64': 0.28.0 - '@esbuild/linux-ia32': 0.28.0 - '@esbuild/linux-loong64': 0.28.0 - '@esbuild/linux-mips64el': 0.28.0 - '@esbuild/linux-ppc64': 0.28.0 - '@esbuild/linux-riscv64': 0.28.0 - '@esbuild/linux-s390x': 0.28.0 - '@esbuild/linux-x64': 0.28.0 - '@esbuild/netbsd-arm64': 0.28.0 - '@esbuild/netbsd-x64': 0.28.0 - '@esbuild/openbsd-arm64': 0.28.0 - '@esbuild/openbsd-x64': 0.28.0 - '@esbuild/openharmony-arm64': 0.28.0 - '@esbuild/sunos-x64': 0.28.0 - '@esbuild/win32-arm64': 0.28.0 - '@esbuild/win32-ia32': 0.28.0 - '@esbuild/win32-x64': 0.28.0 + escalade@3.2.0: {} + + escape-html@1.0.3: {} escape-string-regexp@4.0.0: {} @@ -5504,6 +5845,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 + esprima@4.0.1: {} + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -5516,6 +5859,79 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + + eventsource-parser@3.1.0: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.0 + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + execa@9.6.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.2 + + express-rate-limit@8.5.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.2.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.2 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + fast-deep-equal@3.1.3: {} fast-equals@5.4.0: {} @@ -5528,12 +5944,18 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fast-sha256@1.3.0: {} - fast-uri@3.1.0: {} fastq@1.20.1: @@ -5544,6 +5966,15 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -5552,6 +5983,21 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -5568,6 +6014,20 @@ snapshots: dependencies: is-callable: 1.2.7 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fs-extra@11.3.5: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + fsevents@2.3.3: optional: true @@ -5584,8 +6044,14 @@ snapshots: functions-have-names@1.2.3: {} + fuzzysort@3.1.0: {} + generator-function@2.0.1: {} + gensync@1.0.0-beta.2: {} + + get-east-asian-width@1.6.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -5599,11 +6065,20 @@ snapshots: hasown: 2.0.3 math-intrinsics: 1.1.0 + get-own-enumerable-keys@1.0.0: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@6.0.1: {} + + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 @@ -5622,14 +6097,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@13.0.6: - dependencies: - minimatch: 10.2.5 - minipass: 7.1.3 - path-scurry: 2.0.2 - - globals@11.12.0: {} - globals@14.0.0: {} globalthis@1.0.4: @@ -5663,20 +6130,30 @@ snapshots: dependencies: function-bind: 1.1.2 - html-to-text@9.0.5: + hono@4.12.26: {} + + http-errors@2.0.1: dependencies: - '@selderee/plugin-htmlparser2': 0.11.0 - deepmerge: 4.3.1 - dom-serializer: 2.0.0 - htmlparser2: 8.0.2 - selderee: 0.11.0 + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} - htmlparser2@8.0.2: + human-signals@8.0.1: {} + + iconv-lite@0.7.2: dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 4.5.0 + safer-buffer: 2.1.2 ignore@5.3.2: {} @@ -5689,18 +6166,26 @@ snapshots: imurmurhash@0.1.4: {} + inherits@2.0.4: {} + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.3 side-channel: 1.1.0 + ip-address@10.2.0: {} + + ipaddr.js@1.9.1: {} + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-arrayish@0.2.1: {} + is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -5739,6 +6224,10 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-docker@2.2.1: {} + + is-docker@3.0.0: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -5757,6 +6246,14 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-interactive@2.0.0: {} + is-map@2.0.3: {} is-negative-zero@2.0.3: {} @@ -5768,6 +6265,14 @@ snapshots: is-number@7.0.0: {} + is-obj@2.0.0: {} + + is-obj@3.0.0: {} + + is-plain-obj@4.1.0: {} + + is-promise@4.0.0: {} + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -5775,12 +6280,18 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.3 + is-regexp@3.1.0: {} + is-set@2.0.3: {} is-shared-array-buffer@1.0.4: dependencies: call-bound: 1.0.4 + is-stream@2.0.1: {} + + is-stream@4.0.1: {} + is-string@1.1.1: dependencies: call-bound: 1.0.4 @@ -5796,6 +6307,8 @@ snapshots: dependencies: which-typed-array: 1.1.20 + is-unicode-supported@1.3.0: {} + is-unicode-supported@2.1.0: {} is-weakmap@2.0.2: {} @@ -5809,10 +6322,20 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + isarray@2.0.5: {} isexe@2.0.0: {} + isexe@3.1.5: {} + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 @@ -5822,8 +6345,6 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 - jiti@2.4.2: {} - jiti@2.6.1: {} jose@6.2.3: {} @@ -5838,10 +6359,14 @@ snapshots: json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} + json-schema-typed@7.0.3: {} + json-schema-typed@8.0.2: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -5852,6 +6377,12 @@ snapshots: json5@2.2.3: {} + jsonfile@6.2.1: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 @@ -5865,14 +6396,14 @@ snapshots: kleur@3.0.3: {} + kleur@4.1.5: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: dependencies: language-subtag-registry: 0.3.23 - leac@0.6.0: {} - levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -5927,8 +6458,15 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + lines-and-columns@1.2.4: {} + linkifyjs@4.3.2: {} + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -5937,26 +6475,34 @@ snapshots: lodash@4.18.1: {} - log-symbols@7.0.1: + log-symbols@6.0.0: dependencies: - is-unicode-supported: 2.1.0 - yoctocolors: 2.1.2 + chalk: 5.6.2 + is-unicode-supported: 1.3.0 loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - lru-cache@11.3.5: {} + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@1.21.0(react@19.2.5): + dependencies: + react: 19.2.5 magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - marked@15.0.12: {} - math-intrinsics@1.1.0: {} - mdn-data@2.27.1: {} + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -5965,18 +6511,16 @@ snapshots: braces: 3.0.3 picomatch: 2.3.2 - mime-db@1.52.0: {} - mime-db@1.54.0: {} - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - mime-types@3.0.2: dependencies: mime-db: 1.54.0 + mimic-fn@2.1.0: {} + + mimic-fn@3.1.0: {} + mimic-function@5.0.1: {} minimatch@10.2.5: @@ -5989,8 +6533,6 @@ snapshots: minimist@1.2.8: {} - minipass@7.1.3: {} - ms@2.1.3: {} nanoid@3.3.12: {} @@ -5999,15 +6541,15 @@ snapshots: natural-compare@1.4.0: {} - negotiator@0.6.3: {} + negotiator@1.0.0: {} - next-auth@5.0.0-beta.31(next@15.5.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5): + next-auth@5.0.0-beta.31(next@15.5.15(@babel/core@7.29.7)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5): dependencies: '@auth/core': 0.41.2 - next: 15.5.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 15.5.15(@babel/core@7.29.7)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 - next@15.5.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + next@15.5.15(@babel/core@7.29.7)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@next/env': 15.5.15 '@swc/helpers': 0.5.15 @@ -6015,7 +6557,7 @@ snapshots: postcss: 8.4.31 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - styled-jsx: 5.1.6(react@19.2.5) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.5) optionalDependencies: '@next/swc-darwin-arm64': 15.5.15 '@next/swc-darwin-x64': 15.5.15 @@ -6030,6 +6572,8 @@ snapshots: - '@babel/core' - babel-plugin-macros + node-domexception@1.0.0: {} + node-exports-info@1.6.0: dependencies: array.prototype.flatmap: 1.3.3 @@ -6037,13 +6581,22 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 - normalize-path@3.0.0: {} + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + node-releases@2.0.48: {} - nypm@0.6.6: + npm-run-path@4.0.1: dependencies: - citty: 0.2.2 - pathe: 2.0.3 - tinyexec: 1.1.2 + path-key: 3.1.1 + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 oauth4webapi@3.8.6: {} @@ -6053,6 +6606,8 @@ snapshots: object-keys@1.1.1: {} + object-treeify@1.1.33: {} + object.assign@4.1.7: dependencies: call-bind: 1.0.9 @@ -6089,6 +6644,37 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + open@11.0.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -6098,6 +6684,18 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + ora@8.2.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.2.0 + orderedmap@2.1.1: {} own-keys@1.0.1: @@ -6106,37 +6704,52 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-try@2.2.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 - parseley@0.12.1: + parse-json@5.2.0: dependencies: - leac: 0.6.0 - peberminta: 0.9.0 + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-ms@4.0.0: {} + + parseurl@1.3.3: {} + + path-browserify@1.0.1: {} + + path-exists@3.0.0: {} path-exists@4.0.0: {} path-key@3.1.1: {} - path-parse@1.0.7: {} - - path-scurry@2.0.2: - dependencies: - lru-cache: 11.3.5 - minipass: 7.1.3 + path-key@4.0.0: {} - pathe@2.0.3: {} + path-parse@1.0.7: {} - peberminta@0.9.0: {} + path-to-regexp@8.4.2: {} picocolors@1.1.1: {} @@ -6144,11 +6757,18 @@ snapshots: picomatch@4.0.4: {} - picospinner@3.0.0: {} + pkce-challenge@5.0.1: {} + + pkg-up@3.1.0: + dependencies: + find-up: 3.0.0 possible-typed-array-names@1.1.0: {} - postal-mime@2.7.4: {} + postcss-selector-parser@7.1.4: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 postcss@8.4.31: dependencies: @@ -6162,6 +6782,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + powershell-utils@0.1.0: {} + preact-render-to-string@6.5.11(preact@10.24.3): dependencies: preact: 10.24.3 @@ -6170,9 +6792,9 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.8.3: {} - - prismjs@1.30.0: {} + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 prompts@2.4.2: dependencies: @@ -6254,46 +6876,33 @@ snapshots: prosemirror-state: 1.4.4 prosemirror-transform: 1.12.0 + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + punycode@2.3.1: {} + qs@6.15.2: + dependencies: + side-channel: 1.1.0 + queue-microtask@1.2.3: {} + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + react-dom@19.2.5(react@19.2.5): dependencies: react: 19.2.5 scheduler: 0.27.0 - react-email@6.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5): - dependencies: - '@babel/parser': 7.27.0 - '@babel/traverse': 7.27.0 - '@react-email/render': 2.0.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - chokidar: 4.0.3 - commander: 13.1.0 - conf: 15.1.0 - css-tree: 3.2.1 - debounce: 2.2.0 - esbuild: 0.28.0 - glob: 13.0.6 - jiti: 2.4.2 - log-symbols: 7.0.1 - marked: 15.0.12 - mime-types: 3.0.2 - normalize-path: 3.0.0 - nypm: 0.6.6 - picospinner: 3.0.0 - prismjs: 1.30.0 - prompts: 2.4.2 - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - socket.io: 4.8.3 - tailwindcss: 4.2.4 - tsconfig-paths: 4.2.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - react-image-crop@11.0.10(react@19.2.5): dependencies: react: 19.2.5 @@ -6302,7 +6911,13 @@ snapshots: react@19.2.5: {} - readdirp@4.1.2: {} + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 reflect.getprototypeof@1.0.10: dependencies: @@ -6326,12 +6941,7 @@ snapshots: require-from-string@2.0.2: {} - resend@6.12.2(@react-email/render@2.0.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)): - dependencies: - postal-mime: 2.7.4 - svix: 1.90.0 - optionalDependencies: - '@react-email/render': 2.0.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + reselect@5.2.0: {} resolve-from@4.0.0: {} @@ -6346,10 +6956,27 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + reusify@1.1.0: {} rope-sequence@1.3.4: {} + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + run-applescript@7.1.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -6373,16 +7000,39 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 - scheduler@0.27.0: {} + safer-buffer@2.1.2: {} - selderee@0.11.0: - dependencies: - parseley: 0.12.1 + scheduler@0.27.0: {} semver@6.3.1: {} semver@7.7.4: {} + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -6405,6 +7055,49 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 + setprototypeof@1.2.0: {} + + shadcn@4.11.0(typescript@5.9.3): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.3 + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) + '@dotenvx/dotenvx': 1.75.1 + '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) + '@types/validate-npm-package-name': 4.0.2 + browserslist: 4.28.2 + commander: 14.0.3 + cosmiconfig: 9.0.2(typescript@5.9.3) + dedent: 1.7.2 + deepmerge: 4.3.1 + diff: 8.0.4 + execa: 9.6.1 + fast-glob: 3.3.3 + fs-extra: 11.3.5 + fuzzysort: 3.1.0 + https-proxy-agent: 7.0.6 + kleur: 4.1.5 + node-fetch: 3.3.2 + open: 11.0.0 + ora: 8.2.0 + postcss: 8.5.13 + postcss-selector-parser: 7.1.4 + prompts: 2.4.2 + recast: 0.23.11 + stringify-object: 5.0.0 + tailwind-merge: 3.5.0 + ts-morph: 26.0.0 + tsconfig-paths: 4.2.0 + validate-npm-package-name: 7.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - '@cfworker/json-schema' + - babel-plugin-macros + - supports-color + - typescript + sharp@0.34.5: dependencies: '@img/colour': 1.1.0 @@ -6471,37 +7164,11 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 - sisteransi@1.0.5: {} - - socket.io-adapter@2.5.6: - dependencies: - debug: 4.4.3 - ws: 8.18.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate + signal-exit@3.0.7: {} - socket.io-parser@4.2.6: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color + signal-exit@4.1.0: {} - socket.io@4.8.3: - dependencies: - accepts: 1.3.8 - base64id: 2.0.0 - cors: 2.8.6 - debug: 4.4.3 - engine.io: 6.6.7 - socket.io-adapter: 2.5.6 - socket.io-parser: 4.2.6 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate + sisteransi@1.0.5: {} source-map-js@1.2.1: {} @@ -6514,16 +7181,21 @@ snapshots: stable-hash@0.0.5: {} - standardwebhooks@1.0.0: - dependencies: - '@stablelib/base64': 1.0.1 - fast-sha256: 1.3.0 + statuses@2.0.2: {} + + stdin-discarder@0.2.2: {} stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 internal-slot: 1.1.0 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + string.prototype.includes@2.0.1: dependencies: call-bind: 1.0.9 @@ -6574,20 +7246,34 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - strip-bom@3.0.0: {} + stringify-object@5.0.0: + dependencies: + get-own-enumerable-keys: 1.0.0 + is-obj: 3.0.0 + is-regexp: 3.1.0 - strip-json-comments@3.1.1: {} + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 - stubborn-fs@2.0.0: + strip-ansi@7.2.0: dependencies: - stubborn-utils: 1.0.2 + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-final-newline@2.0.0: {} - stubborn-utils@1.0.2: {} + strip-final-newline@4.0.0: {} + + strip-json-comments@3.1.1: {} - styled-jsx@5.1.6(react@19.2.5): + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.5): dependencies: client-only: 0.0.1 react: 19.2.5 + optionalDependencies: + '@babel/core': 7.29.7 supports-color@7.2.0: dependencies: @@ -6595,12 +7281,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svix@1.90.0: - dependencies: - standardwebhooks: 1.0.0 - uuid: 10.0.0 - - tagged-tag@1.0.0: {} + systeminformation@5.31.7: {} tailwind-merge@3.5.0: {} @@ -6608,7 +7289,7 @@ snapshots: tapable@2.3.3: {} - tinyexec@1.1.2: {} + tiny-invariant@1.3.3: {} tinyglobby@0.2.16: dependencies: @@ -6619,10 +7300,17 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 + ts-morph@26.0.0: + dependencies: + '@ts-morph/common': 0.27.0 + code-block-writer: 13.0.3 + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -6645,13 +7333,17 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tw-animate-css@1.4.0: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - type-fest@5.6.0: + type-is@2.1.0: dependencies: - tagged-tag: 1.0.0 + content-type: 2.0.0 + media-typer: 1.1.0 + mime-types: 3.0.2 typed-array-buffer@1.0.3: dependencies: @@ -6688,8 +7380,6 @@ snapshots: typescript@5.9.3: {} - uint8array-extras@1.5.0: {} - unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -6699,6 +7389,14 @@ snapshots: undici-types@6.21.0: {} + undici@7.28.0: {} + + unicorn-magic@0.3.0: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -6723,6 +7421,12 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -6731,13 +7435,15 @@ snapshots: dependencies: react: 19.2.5 - uuid@10.0.0: {} + util-deprecate@1.0.2: {} + + validate-npm-package-name@7.0.2: {} vary@1.1.2: {} w3c-keyname@2.2.8: {} - when-exit@2.1.5: {} + web-streams-polyfill@3.3.3: {} which-boxed-primitive@1.1.1: dependencies: @@ -6784,12 +7490,33 @@ snapshots: dependencies: isexe: 2.0.0 + which@4.0.0: + dependencies: + isexe: 3.1.5 + word-wrap@1.2.5: {} - ws@8.18.3: {} + wrappy@1.0.2: {} + + wsl-utils@0.3.1: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.1.0 + + yallist@3.1.1: {} yocto-queue@0.1.0: {} + yocto-spinner@1.2.0: + dependencies: + yoctocolors: 2.1.2 + yoctocolors@2.1.2: {} + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} + zod@4.4.1: {} diff --git a/public/mascot/kodyfigma.svg b/public/mascot/kody.svg similarity index 100% rename from public/mascot/kodyfigma.svg rename to public/mascot/kody.svg diff --git a/public/mascot/kody-smilefigma.svg b/public/mascot/kodysmile.svg similarity index 100% rename from public/mascot/kody-smilefigma.svg rename to public/mascot/kodysmile.svg diff --git a/src/app/(public)/about/page.tsx b/src/app/(public)/about/page.tsx deleted file mode 100644 index 8da89b9..0000000 --- a/src/app/(public)/about/page.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import type { Metadata } from "next"; -import Link from "next/link"; -import Button from "@/components/ui/Button"; - -export const revalidate = 3600; - -const title = "About — CodedDevs Technology LTD"; -const description = - "We build AI-first software products for African markets. Learn about our mission and approach."; - -export const metadata: Metadata = { - title, - description, - openGraph: { - title, - description, - url: "https://codeddevs.com/about", - siteName: "CodedDevs Technology LTD", - type: "website", - }, - twitter: { - card: "summary_large_image", - title, - description, - }, -}; - -const companyFacts = [ - { label: "Founded", value: "March 2026" }, - { label: "Registered", value: "RC 9426867, Nigeria" }, - { label: "Location", value: "Lagos, Nigeria" }, - { label: "Team", value: "3 founders, all full-stack engineers" }, -]; - -export default function AboutPage() { - return ( -
-
-
-
-

- About CodedDevs -

-

- We build AI-first software products for African markets — from - first principles. -

-
-
-
- -
-
-

- What We're Building -

-
-

- CodedDevs Technology LTD is an African startup building AI - products and open-source tools that help businesses grow, scale, - and operate more efficiently. -

-

- We develop a portfolio of products across social commerce, - e-commerce, and AI-driven tools — designed to enable seamless - transactions, stronger digital presence, and smarter business - growth. -

-
-
-
- -
-
-

- How We Build -

-
-

- Our approach is AI-first and deeply focused on the African - market. We solve real-world challenges unique to the region — not - by adapting tools built elsewhere, but by engineering from first - principles. -

-

- We build in the open. Our products are open-source because we - believe the best software for Africa should be built with Africa. -

-
-
-
- -
-
-
- {companyFacts.map((fact) => ( -
-

- {fact.label} -

-

- {fact.value} -

-
- ))} -
-
-
- -
-
-

- Meet the team behind CodedDevs -

- -
-
-
- ); -} diff --git a/src/app/(public)/blog/[slug]/page.tsx b/src/app/(public)/blog/[slug]/page.tsx index 4aafef4..e5d3dec 100644 --- a/src/app/(public)/blog/[slug]/page.tsx +++ b/src/app/(public)/blog/[slug]/page.tsx @@ -1,16 +1,19 @@ import type { Metadata } from "next"; import Image from "next/image"; +import Link from "next/link"; import { notFound } from "next/navigation"; import { cache } from "react"; +import { ArrowLeft, ArrowRight } from "lucide-react"; import { desc, eq } from "drizzle-orm"; import PostContent, { type TiptapJson, } from "@/components/blog/PostContent"; import Badge from "@/components/ui/Badge"; +import Button from "@/components/ui/Button"; import { blogPosts, db } from "@/db"; -import { getPostBySlug } from "@/db/queries"; -import { getBlogCoverUrl } from "@/lib/cloudinary"; -import { getReadingTime } from "@/lib/utils"; +import { getLatestPosts, getPostBySlug } from "@/db/queries"; +import { getBlogCoverUrl, getBlogThumbnailUrl } from "@/lib/cloudinary"; +import { getReadingTime, slugify } from "@/lib/utils"; export const revalidate = 3600; @@ -38,6 +41,41 @@ function isTiptapJson(value: unknown): value is TiptapJson { return typeof value === "object" && value !== null && !Array.isArray(value); } +function getNodeText(node: TiptapJson): string { + const ownText = typeof node.text === "string" ? node.text : ""; + const childText = Array.isArray(node.content) + ? node.content.map(getNodeText).join(" ") + : ""; + + return `${ownText} ${childText}`.trim(); +} + +function getTableOfContents(content: TiptapJson) { + const headings: Array<{ id: string; text: string; level: number }> = []; + + function walk(node: TiptapJson) { + if (node.type === "heading") { + const text = getNodeText(node); + const level = + typeof node.attrs?.level === "number" ? node.attrs.level : 2; + + if (text) { + headings.push({ + id: slugify(text), + text, + level, + }); + } + } + + node.content?.forEach(walk); + } + + walk(content); + + return headings; +} + export async function generateStaticParams() { if (process.env.CI === "true") { return []; @@ -64,11 +102,11 @@ export async function generateMetadata({ if (!post) { return { - title: "Update - CodedDevs Updates", + title: "Blog Post - CodedDevs Blog", }; } - const title = `${post.title} - CodedDevs Updates`; + const title = `${post.title} - CodedDevs Blog`; const description = post.excerpt; const url = `https://codeddevs.com/blog/${post.slug}`; const images = post.cover_url ? [post.cover_url] : undefined; @@ -95,7 +133,10 @@ export async function generateMetadata({ export default async function UpdatePage({ params }: UpdatePageProps) { const { slug } = await params; - const post = await getCachedPostBySlug(slug); + const [post, latestPosts] = await Promise.all([ + getCachedPostBySlug(slug), + getLatestPosts(4), + ]); if (!post) { notFound(); @@ -105,40 +146,170 @@ export default async function UpdatePage({ params }: UpdatePageProps) { ? post.content : { type: "doc", content: [] }; const readingTime = getReadingTime(post.content); + const tableOfContents = getTableOfContents(content); + const relatedPosts = latestPosts + .filter((relatedPost) => relatedPost.slug !== post.slug) + .slice(0, 3); return (
- {post.cover_url ? ( -
- {post.title} +
+
+ + +
+
+ {post.category} +

+ {post.title} +

+
+ By {post.author} + + {formatDate(post.published_at)} + + {readingTime} +
+
+ + {post.cover_url ? ( +
+ {post.title} +
+ ) : null} + +
+ +
+
- ) : null} - -
-
- {post.category} -

- {post.title} -

-

- By {post.author} · {formatDate(post.published_at)}{" "} - · {readingTime} -

-
- -
- -
+ + {relatedPosts.length > 0 ? ( +
+
+
+
+

+ Keep reading +

+

+ More notes from the CodedDevs team. +

+
+ +
+ +
+ {relatedPosts.map((relatedPost) => ( +
+ {relatedPost.cover_url ? ( +
+ {relatedPost.title} +
+ ) : null} +
+ {relatedPost.category} + + {formatDate(relatedPost.published_at)} + +
+

+ + {relatedPost.title} + +

+

+ {relatedPost.excerpt} +

+ + Read post +
+ ))} +
+
+
+ ) : null}
); } diff --git a/src/app/(public)/blog/page.tsx b/src/app/(public)/blog/page.tsx index 743098b..ab671d6 100644 --- a/src/app/(public)/blog/page.tsx +++ b/src/app/(public)/blog/page.tsx @@ -1,15 +1,15 @@ import type { Metadata } from "next"; import { desc, eq } from "drizzle-orm"; -import UpdatesList, { - type UpdateListPost, +import BlogList, { + type BlogListPost, } from "@/components/blog/UpdatesList"; import { blogPosts, db } from "@/db"; export const revalidate = 3600; -const title = "Updates — CodedDevs Technology LTD"; +const title = "Blog - CodedDevs Technology LTD"; const description = - "Product updates, announcements, and stories from the CodedDevs team."; + "Blog posts, announcements, and stories from the CodedDevs team."; export const metadata: Metadata = { title, @@ -28,7 +28,7 @@ export const metadata: Metadata = { }, }; -async function getPublishedPosts(): Promise { +async function getPublishedPosts(): Promise { try { const posts = await db .select({ @@ -54,28 +54,28 @@ async function getPublishedPosts(): Promise { } } -export default async function UpdatesPage() { +export default async function BlogPage() { const posts = await getPublishedPosts(); return (
-
+
-
-

- Updates +
+

+ CodedDevs Blog

-

- Product updates, announcements, and stories from the CodedDevs - team. +

+ Engineering notes, product announcements, and company stories + from the team building software for African markets.

-
+
- +
diff --git a/src/app/(public)/careers/page.tsx b/src/app/(public)/careers/page.tsx deleted file mode 100644 index d10e51d..0000000 --- a/src/app/(public)/careers/page.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import type { Metadata } from "next"; -import Link from "next/link"; -import { desc, eq } from "drizzle-orm"; -import ApplicationForm from "@/components/careers/ApplicationForm"; -import Badge from "@/components/ui/Badge"; -import Button from "@/components/ui/Button"; -import Card from "@/components/ui/Card"; -import { ArrowRightIcon } from "@/components/ui/icons"; -import { careers, db } from "@/db"; -import type { Career } from "@/types"; - -export const revalidate = 3600; - -const title = "Careers — CodedDevs Technology LTD"; -const description = - "Work with CodedDevs. We are a small team building software for African markets."; - -type OpenRole = Pick< - Career, - "id" | "title" | "type" | "location" | "description" ->; - -export const metadata: Metadata = { - title, - description, - openGraph: { - title, - description, - url: "https://codeddevs.com/careers", - siteName: "CodedDevs Technology LTD", - type: "website", - }, - twitter: { - card: "summary_large_image", - title, - description, - }, -}; - -function formatType(type: Career["type"]) { - return type - .split("-") - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join("-"); -} - -async function getOpenRoles() { - try { - return await db - .select({ - id: careers.id, - title: careers.title, - type: careers.type, - location: careers.location, - description: careers.description, - }) - .from(careers) - .where(eq(careers.is_open, true)) - .orderBy(desc(careers.created_at)); - } catch { - return []; - } -} - -function RoleCard({ role }: { role: OpenRole }) { - return ( - -
-
-
-

- {role.title} -

- {formatType(role.type)} -
- -

- {role.location} -

- -

- {role.description} -

-
- -
- - Apply - - -
-
-
- ); -} - -export default async function CareersPage() { - const openRoles = await getOpenRoles(); - - return ( -
-
-
-
-

- Work With Us -

-

- We're a small team building products for African markets. If - you care about what we're building, we want to hear from you. -

-
-
-
- -
-
-

- We are remote-friendly, early stage, and practical about how strong - contributors create value. Equity may be considered for people who - bring exceptional ownership and long-term commitment. -

-
-
- -
-
- {openRoles.length > 0 ? ( -
- {openRoles.map((role) => ( - - ))} -
- ) : ( -
-

- No open roles right now. -

- -
- )} -
-
-
- ); -} diff --git a/src/app/(public)/contact/page.tsx b/src/app/(public)/contact/page.tsx deleted file mode 100644 index f3286a8..0000000 --- a/src/app/(public)/contact/page.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import type { Metadata } from "next"; -import ContactForm from "@/components/contact/ContactForm"; - -export const revalidate = 3600; - -const title = "Contact — CodedDevs Technology LTD"; -const description = - "Get in touch with the CodedDevs team. Partnerships, press, investment, and general enquiries."; - -export const metadata: Metadata = { - title, - description, - openGraph: { - title, - description, - url: "https://codeddevs.com/contact", - siteName: "CodedDevs Technology LTD", - type: "website", - }, - twitter: { - card: "summary_large_image", - title, - description, - }, -}; - -const socialLinks = [ - { - label: "GitHub", - text: "github.com/coded-devs", - href: "https://github.com/coded-devs", - }, - { - label: "X", - text: "@CodedDevs", - href: "https://x.com/CodedDevs", - }, - { - label: "TikTok", - text: "@CodedDevs", - href: "https://www.tiktok.com/@CodedDevs", - }, - { - label: "YouTube", - text: "@CodedDevs", - href: "https://www.youtube.com/@CodedDevs", - }, - { - label: "Instagram", - text: "@codeddevs_", - href: "https://www.instagram.com/codeddevs_", - }, -]; - -export default function ContactPage() { - return ( -
-
-
-
-

- Get in Touch -

-

- Whether you want to partner, invest, or just say hello — - we'd love to hear from you. -

-
-
-
- -
-
-
- - -
-

- Location -

-

- Lagos, Nigeria -

-
- -
-

- Social -

-
- {socialLinks.map((link) => ( - - - {link.label} - - - {link.text} - - - ))} -
-
-
- - -
-
-
- ); -} diff --git a/src/app/(public)/page.tsx b/src/app/(public)/page.tsx index 0b94c5c..4fdae48 100644 --- a/src/app/(public)/page.tsx +++ b/src/app/(public)/page.tsx @@ -1,13 +1,8 @@ import type { Metadata } from "next"; -import { eq } from "drizzle-orm"; import HeroSection from "@/components/sections/HeroSection"; -import AboutTeaser from "@/components/sections/AboutTeaser"; +import GoalsSection from "@/components/sections/GoalsSection"; import LatestReleasesSection from "@/components/sections/LatestReleasesSection"; -import ProductsSection from "@/components/sections/ProductsSection"; -import RecognitionSection from "@/components/sections/RecognitionSection"; -import TeamSection from "@/components/sections/TeamSection"; -import { db, products } from "@/db"; -import { getLatestPosts, getRecognitionPosts } from "@/db/queries"; +import { getLatestPosts } from "@/db/queries"; export const revalidate = 3600; @@ -32,42 +27,14 @@ export const metadata: Metadata = { }, }; -async function getFeaturedProducts() { - try { - return await db - .select({ - id: products.id, - name: products.name, - slug: products.slug, - tagline: products.tagline, - cover_url: products.cover_url, - external_url: products.external_url, - status: products.status, - is_featured: products.is_featured, - }) - .from(products) - .where(eq(products.is_featured, true)) - .orderBy(products.order_index); - } catch { - return []; - } -} - export default async function HomePage() { - const [featuredProducts, latestPosts, recognitionPosts] = await Promise.all([ - getFeaturedProducts(), - getLatestPosts(3), - getRecognitionPosts(3), - ]); + const latestPosts = await getLatestPosts(3); return (
- + - - -
); } diff --git a/src/app/(public)/products/[slug]/page.tsx b/src/app/(public)/products/[slug]/page.tsx deleted file mode 100644 index fa75a5e..0000000 --- a/src/app/(public)/products/[slug]/page.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import type { Metadata } from "next"; -import Image from "next/image"; -import { notFound } from "next/navigation"; -import { cache } from "react"; -import { eq } from "drizzle-orm"; -import Badge from "@/components/ui/Badge"; -import Button from "@/components/ui/Button"; -import { ExternalLinkIcon, GithubIcon } from "@/components/ui/icons"; -import { db, products } from "@/db"; -import { getProductCoverUrl } from "@/lib/cloudinary"; -import type { ProductSelect } from "@/types"; - -export const revalidate = 3600; - -type ProductPageProps = { - params: Promise<{ - slug: string; - }>; -}; - -function formatStatus(status: ProductSelect["status"]) { - return status - .split("-") - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(" "); -} - -function statusVariant(status: ProductSelect["status"]) { - if (status === "live") { - return "success"; - } - - if (status === "development") { - return "warning"; - } - - return "muted"; -} - -const getProductBySlug = cache(async (slug: string) => { - try { - const [product] = await db - .select() - .from(products) - .where(eq(products.slug, slug)) - .limit(1); - - return product ?? null; - } catch { - return null; - } -}); - -export async function generateStaticParams() { - if (process.env.CI === "true") { - return []; - } - - try { - const productSlugs = await db - .select({ slug: products.slug }) - .from(products) - .orderBy(products.order_index); - - return productSlugs; - } catch { - return []; - } -} - -export async function generateMetadata({ - params, -}: ProductPageProps): Promise { - const { slug } = await params; - const product = await getProductBySlug(slug); - - if (!product) { - return { - title: "Product — CodedDevs", - }; - } - - const title = `${product.name} — CodedDevs`; - const description = product.tagline; - const url = `https://codeddevs.com/products/${product.slug}`; - const images = product.cover_url - ? [{ url: getProductCoverUrl(product.cover_url), alt: product.name }] - : undefined; - - return { - title, - description, - openGraph: { - title, - description, - url, - siteName: "CodedDevs Technology LTD", - type: "website", - images, - }, - twitter: { - card: "summary_large_image", - title, - description, - images: images?.map((image) => image.url), - }, - }; -} - -export default async function ProductPage({ params }: ProductPageProps) { - const { slug } = await params; - const product = await getProductBySlug(slug); - - if (!product) { - notFound(); - } - - return ( -
-
-
-
-
-
-

- {product.name} -

- - {formatStatus(product.status)} - -
-

- {product.tagline} -

-
- -
- {product.external_url ? ( - - ) : null} - {product.github_url ? ( - - ) : null} -
-
-
-
- - {product.cover_url ? ( -
-
-
- {product.name} -
-
-
- ) : null} - -
-
-
- {product.description.split(/\n{2,}/).map((paragraph, index) => ( -

{paragraph}

- ))} -
-
-
-
- ); -} diff --git a/src/app/(public)/products/page.tsx b/src/app/(public)/products/page.tsx deleted file mode 100644 index 2bd2008..0000000 --- a/src/app/(public)/products/page.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import type { Metadata } from "next"; -import Link from "next/link"; -import Badge from "@/components/ui/Badge"; -import Card from "@/components/ui/Card"; -import { ArrowRightIcon, ExternalLinkIcon } from "@/components/ui/icons"; -import { db, products } from "@/db"; -import type { ProductSelect } from "@/types"; - -export const revalidate = 3600; - -const title = "Products — CodedDevs Technology LTD"; -const description = - "Software built for African markets. See what CodedDevs is building."; - -export const metadata: Metadata = { - title, - description, - openGraph: { - title, - description, - url: "https://codeddevs.com/products", - siteName: "CodedDevs Technology LTD", - type: "website", - }, - twitter: { - card: "summary_large_image", - title, - description, - }, -}; - -function formatStatus(status: ProductSelect["status"]) { - return status - .split("-") - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(" "); -} - -function statusVariant(status: ProductSelect["status"]) { - if (status === "live") { - return "success"; - } - - if (status === "development") { - return "warning"; - } - - return "muted"; -} - -async function getProducts() { - try { - return await db - .select({ - id: products.id, - name: products.name, - slug: products.slug, - tagline: products.tagline, - status: products.status, - cover_url: products.cover_url, - external_url: products.external_url, - is_featured: products.is_featured, - }) - .from(products) - .orderBy(products.order_index); - } catch { - return []; - } -} - -export default async function ProductsPage() { - const allProducts = await getProducts(); - - return ( -
-
-
-
-

- Our Products -

-

- Software built for African markets. -

-
-
-
- -
-
- {allProducts.length > 0 ? ( -
- {allProducts.map((product) => ( - -
-
-
-

- {product.name} -

- - {formatStatus(product.status)} - -
-

- {product.tagline} -

-
- -
- - Learn more - - - {product.external_url ? ( - - Visit product - - - ) : null} -
-
-
- ))} -
- ) : ( -

- We're working on something. Check back soon. -

- )} -
-
-
- ); -} diff --git a/src/app/(public)/team/page.tsx b/src/app/(public)/team/page.tsx index c2dcede..afa5f88 100644 --- a/src/app/(public)/team/page.tsx +++ b/src/app/(public)/team/page.tsx @@ -173,7 +173,7 @@ export default async function TeamPage() { The Team

- Three founders. All engineers. Building from Lagos. + Three founders, supported by a growing team of designers, developers, and creators building from Lagos.

diff --git a/src/app/admin/(protected)/applications/page.tsx b/src/app/admin/(protected)/applications/page.tsx deleted file mode 100644 index 9f5c9a9..0000000 --- a/src/app/admin/(protected)/applications/page.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { desc, eq } from "drizzle-orm"; -import ApplicationsManager, { - type AdminApplication, -} from "@/components/admin/ApplicationsManager"; -import { careerApplications, careers, db } from "@/db"; -import { requireAdminSession } from "@/lib/admin-auth"; - -export default async function AdminApplicationsPage() { - await requireAdminSession(); - - const applications = await db - .select({ - id: careerApplications.id, - career_title: careers.title, - full_name: careerApplications.full_name, - email: careerApplications.email, - portfolio_url: careerApplications.portfolio_url, - github_url: careerApplications.github_url, - cover_letter: careerApplications.cover_letter, - status: careerApplications.status, - created_at: careerApplications.created_at, - }) - .from(careerApplications) - .leftJoin(careers, eq(careerApplications.career_id, careers.id)) - .orderBy(desc(careerApplications.created_at)); - - const serializedApplications: AdminApplication[] = applications.map( - (application) => ({ - ...application, - created_at: application.created_at.toISOString(), - }), - ); - - return ( -
-
-

- Applications -

-

- Review career applications and update status. -

-
- - -
- ); -} diff --git a/src/app/admin/(protected)/blog/[id]/page.tsx b/src/app/admin/(protected)/blog/[id]/page.tsx index 13a280a..614a503 100644 --- a/src/app/admin/(protected)/blog/[id]/page.tsx +++ b/src/app/admin/(protected)/blog/[id]/page.tsx @@ -1,7 +1,7 @@ import { notFound } from "next/navigation"; import { eq } from "drizzle-orm"; -import { BlogPostForm } from "@/components/admin/ResourceForms"; -import type { TiptapJson } from "@/components/admin/RichTextEditor"; +import { BlogPostForm } from "@/components/admin/forms/ResourceForms"; +import type { TiptapJson } from "@/components/admin/editors/RichTextEditor"; import { blogPosts, db } from "@/db"; import { requireAdminSession } from "@/lib/admin-auth"; diff --git a/src/app/admin/(protected)/blog/new/page.tsx b/src/app/admin/(protected)/blog/new/page.tsx index 1e68b9e..e863908 100644 --- a/src/app/admin/(protected)/blog/new/page.tsx +++ b/src/app/admin/(protected)/blog/new/page.tsx @@ -1,4 +1,4 @@ -import { BlogPostForm } from "@/components/admin/ResourceForms"; +import { BlogPostForm } from "@/components/admin/forms/ResourceForms"; export default function NewBlogPostPage() { return ( diff --git a/src/app/admin/(protected)/blog/page.tsx b/src/app/admin/(protected)/blog/page.tsx index d5c8e38..6b8507c 100644 --- a/src/app/admin/(protected)/blog/page.tsx +++ b/src/app/admin/(protected)/blog/page.tsx @@ -1,6 +1,6 @@ import Link from "next/link"; import { desc } from "drizzle-orm"; -import AdminDeleteButton from "@/components/admin/AdminDeleteButton"; +import AdminDeleteButton from "@/components/admin/actions/AdminDeleteButton"; import Badge from "@/components/ui/Badge"; import Button from "@/components/ui/Button"; import { blogPosts, db } from "@/db"; @@ -40,7 +40,7 @@ export default async function AdminBlogPage() {

Blog

- Manage public updates and announcements. + Manage blog posts and announcements.

- - -
- - - - - - - - - - - - {careerList.map((career) => ( - - - - - - - - ))} - -
TitleTypeLocationOpenActions
{career.title}{career.type}{career.location}{career.is_open ? "Yes" : "No"} -
- - -
-
-
- - ); -} diff --git a/src/app/admin/(protected)/dashboard/page.tsx b/src/app/admin/(protected)/dashboard/page.tsx index 62f9f3c..19ebee5 100644 --- a/src/app/admin/(protected)/dashboard/page.tsx +++ b/src/app/admin/(protected)/dashboard/page.tsx @@ -1,74 +1,12 @@ -import { count, desc, eq } from "drizzle-orm"; -import { - blogPosts, - careerApplications, - careers, - contactSubmissions, - db, - products, - teamMembers, -} from "@/db"; +import { count } from "drizzle-orm"; +import { blogPosts, db, products, teamMembers } from "@/db"; import { requireAdminSession } from "@/lib/admin-auth"; -function formatDate(date: Date) { - return new Intl.DateTimeFormat("en", { - month: "short", - day: "numeric", - year: "numeric", - }).format(date); -} - async function getDashboardData() { - const [ - [teamCount], - [productCount], - [postCount], - [openCareerCount], - [unreadMessageCount], - [pendingApplicationCount], - unreadMessages, - pendingApplications, - ] = await Promise.all([ + const [[teamCount], [productCount], [postCount]] = await Promise.all([ db.select({ value: count() }).from(teamMembers), db.select({ value: count() }).from(products), db.select({ value: count() }).from(blogPosts), - db - .select({ value: count() }) - .from(careers) - .where(eq(careers.is_open, true)), - db - .select({ value: count() }) - .from(contactSubmissions) - .where(eq(contactSubmissions.is_read, false)), - db - .select({ value: count() }) - .from(careerApplications) - .where(eq(careerApplications.status, "pending")), - db - .select({ - id: contactSubmissions.id, - full_name: contactSubmissions.full_name, - email: contactSubmissions.email, - subject: contactSubmissions.subject, - created_at: contactSubmissions.created_at, - }) - .from(contactSubmissions) - .where(eq(contactSubmissions.is_read, false)) - .orderBy(desc(contactSubmissions.created_at)) - .limit(5), - db - .select({ - id: careerApplications.id, - full_name: careerApplications.full_name, - email: careerApplications.email, - created_at: careerApplications.created_at, - career_title: careers.title, - }) - .from(careerApplications) - .leftJoin(careers, eq(careerApplications.career_id, careers.id)) - .where(eq(careerApplications.status, "pending")) - .orderBy(desc(careerApplications.created_at)) - .limit(5), ]); return { @@ -76,20 +14,14 @@ async function getDashboardData() { { label: "Team Members", value: teamCount.value }, { label: "Products", value: productCount.value }, { label: "Blog Posts", value: postCount.value }, - { label: "Open Careers", value: openCareerCount.value }, - { label: "Unread Messages", value: unreadMessageCount.value }, - { label: "Pending Applications", value: pendingApplicationCount.value }, ], - unreadMessages, - pendingApplications, }; } export default async function AdminDashboardPage() { await requireAdminSession(); - const { stats, unreadMessages, pendingApplications } = - await getDashboardData(); + const { stats } = await getDashboardData(); return (
@@ -98,7 +30,7 @@ export default async function AdminDashboardPage() { Dashboard

- Overview of website content and inbound activity. + Overview of website content.

@@ -115,57 +47,6 @@ export default async function AdminDashboardPage() { ))} - -
-
-

- Recent Unread Messages -

-
- {unreadMessages.length > 0 ? ( - unreadMessages.map((message) => ( -
-

- {message.full_name} - {message.subject} -

-

- {message.email} - {formatDate(message.created_at)} -

-
- )) - ) : ( -

- No unread messages. -

- )} -
-
- -
-

- Recent Pending Applications -

-
- {pendingApplications.length > 0 ? ( - pendingApplications.map((application) => ( -
-

- {application.full_name} -

-

- {application.career_title ?? "Unknown role"} -{" "} - {application.email} - {formatDate(application.created_at)} -

-
- )) - ) : ( -

- No pending applications. -

- )} -
-
-
); -} +} \ No newline at end of file diff --git a/src/app/admin/(protected)/messages/page.tsx b/src/app/admin/(protected)/messages/page.tsx deleted file mode 100644 index 0b92d23..0000000 --- a/src/app/admin/(protected)/messages/page.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { desc } from "drizzle-orm"; -import MessagesManager, { - type AdminMessage, -} from "@/components/admin/MessagesManager"; -import { contactSubmissions, db } from "@/db"; -import { requireAdminSession } from "@/lib/admin-auth"; - -export default async function AdminMessagesPage() { - await requireAdminSession(); - - const messages = await db - .select() - .from(contactSubmissions) - .orderBy(desc(contactSubmissions.created_at)); - - const serializedMessages: AdminMessage[] = messages.map((message) => ({ - ...message, - created_at: message.created_at.toISOString(), - })); - - return ( -
-
-

- Messages -

-

- Read contact submissions and clear the inbox. -

-
- - -
- ); -} diff --git a/src/app/admin/(protected)/products/[id]/page.tsx b/src/app/admin/(protected)/products/[id]/page.tsx index 0d38f7d..cda1d09 100644 --- a/src/app/admin/(protected)/products/[id]/page.tsx +++ b/src/app/admin/(protected)/products/[id]/page.tsx @@ -1,6 +1,6 @@ import { notFound } from "next/navigation"; import { eq } from "drizzle-orm"; -import { ProductForm } from "@/components/admin/ResourceForms"; +import { ProductForm } from "@/components/admin/forms/ResourceForms"; import { db, products } from "@/db"; import { requireAdminSession } from "@/lib/admin-auth"; diff --git a/src/app/admin/(protected)/products/new/page.tsx b/src/app/admin/(protected)/products/new/page.tsx index 79abff9..56a6e09 100644 --- a/src/app/admin/(protected)/products/new/page.tsx +++ b/src/app/admin/(protected)/products/new/page.tsx @@ -1,4 +1,4 @@ -import { ProductForm } from "@/components/admin/ResourceForms"; +import { ProductForm } from "@/components/admin/forms/ResourceForms"; export default function NewProductPage() { return ( diff --git a/src/app/admin/(protected)/products/page.tsx b/src/app/admin/(protected)/products/page.tsx index e45caff..42ef636 100644 --- a/src/app/admin/(protected)/products/page.tsx +++ b/src/app/admin/(protected)/products/page.tsx @@ -1,6 +1,6 @@ import Link from "next/link"; import { asc } from "drizzle-orm"; -import AdminDeleteButton from "@/components/admin/AdminDeleteButton"; +import AdminDeleteButton from "@/components/admin/actions/AdminDeleteButton"; import Button from "@/components/ui/Button"; import { db, products } from "@/db"; import { requireAdminSession } from "@/lib/admin-auth"; diff --git a/src/app/admin/(protected)/team/[id]/page.tsx b/src/app/admin/(protected)/team/[id]/page.tsx index 69f9e85..791a2d5 100644 --- a/src/app/admin/(protected)/team/[id]/page.tsx +++ b/src/app/admin/(protected)/team/[id]/page.tsx @@ -1,6 +1,6 @@ import { notFound } from "next/navigation"; import { eq } from "drizzle-orm"; -import { TeamMemberForm } from "@/components/admin/ResourceForms"; +import { TeamMemberForm } from "@/components/admin/forms/ResourceForms"; import { db, teamMembers } from "@/db"; import { requireAdminSession } from "@/lib/admin-auth"; diff --git a/src/app/admin/(protected)/team/new/page.tsx b/src/app/admin/(protected)/team/new/page.tsx index 584eca3..eb1d3f3 100644 --- a/src/app/admin/(protected)/team/new/page.tsx +++ b/src/app/admin/(protected)/team/new/page.tsx @@ -1,4 +1,4 @@ -import { TeamMemberForm } from "@/components/admin/ResourceForms"; +import { TeamMemberForm } from "@/components/admin/forms/ResourceForms"; export default function NewTeamMemberPage() { return ( diff --git a/src/app/admin/(protected)/team/page.tsx b/src/app/admin/(protected)/team/page.tsx index 340f4dd..a07f827 100644 --- a/src/app/admin/(protected)/team/page.tsx +++ b/src/app/admin/(protected)/team/page.tsx @@ -1,6 +1,6 @@ import Link from "next/link"; import { asc } from "drizzle-orm"; -import AdminDeleteButton from "@/components/admin/AdminDeleteButton"; +import AdminDeleteButton from "@/components/admin/actions/AdminDeleteButton"; import Button from "@/components/ui/Button"; import { db, teamMembers } from "@/db"; import { requireAdminSession } from "@/lib/admin-auth"; diff --git a/src/app/api/admin/applications/[id]/route.ts b/src/app/api/admin/applications/[id]/route.ts deleted file mode 100644 index fc283b9..0000000 --- a/src/app/api/admin/applications/[id]/route.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { NextResponse } from "next/server"; -import { eq } from "drizzle-orm"; -import { z } from "zod"; -import { auth } from "@/lib/auth"; -import { careerApplications, db } from "@/db"; - -const idSchema = z.string().uuid(); -const applicationStatusSchema = z.object({ - status: z.enum(["pending", "reviewed", "rejected"]), -}); - -type RouteContext = { - params: Promise<{ - id: string; - }>; -}; - -export async function PUT(request: Request, context: RouteContext) { - const params = await context.params; - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - try { - const parsedId = idSchema.safeParse(params.id); - const parsedBody = applicationStatusSchema.safeParse(await request.json()); - - if (!parsedId.success || !parsedBody.success) { - return NextResponse.json( - { - error: "Invalid input", - details: parsedBody.success ? undefined : parsedBody.error.flatten(), - }, - { status: 400 }, - ); - } - - const [application] = await db - .update(careerApplications) - .set({ status: parsedBody.data.status }) - .where(eq(careerApplications.id, parsedId.data)) - .returning(); - - if (!application) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - return NextResponse.json(application, { status: 200 }); - } catch (error) { - console.error("Failed to update application:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} diff --git a/src/app/api/admin/applications/route.ts b/src/app/api/admin/applications/route.ts deleted file mode 100644 index 36f1ac1..0000000 --- a/src/app/api/admin/applications/route.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { NextResponse } from "next/server"; -import { desc, eq } from "drizzle-orm"; -import { z } from "zod"; -import { auth } from "@/lib/auth"; -import { careerApplications, careers, db } from "@/db"; - -const statusSchema = z.enum(["pending", "reviewed", "rejected"]).optional(); - -export async function GET(request: Request) { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - try { - const { searchParams } = new URL(request.url); - const parsedStatus = statusSchema.safeParse( - searchParams.get("status") ?? undefined, - ); - - if (!parsedStatus.success) { - return NextResponse.json( - { error: "Invalid input", details: parsedStatus.error.flatten() }, - { status: 400 }, - ); - } - - const whereClause = parsedStatus.data - ? eq(careerApplications.status, parsedStatus.data) - : undefined; - - const applications = await db - .select({ - id: careerApplications.id, - career_id: careerApplications.career_id, - career_title: careers.title, - full_name: careerApplications.full_name, - email: careerApplications.email, - portfolio_url: careerApplications.portfolio_url, - github_url: careerApplications.github_url, - cover_letter: careerApplications.cover_letter, - status: careerApplications.status, - created_at: careerApplications.created_at, - }) - .from(careerApplications) - .leftJoin(careers, eq(careerApplications.career_id, careers.id)) - .where(whereClause) - .orderBy(desc(careerApplications.created_at)); - - return NextResponse.json(applications, { status: 200 }); - } catch (error) { - console.error("Failed to fetch applications:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} diff --git a/src/app/api/admin/careers/[id]/route.ts b/src/app/api/admin/careers/[id]/route.ts deleted file mode 100644 index ffea4ed..0000000 --- a/src/app/api/admin/careers/[id]/route.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { NextResponse } from "next/server"; -import { eq } from "drizzle-orm"; -import { z } from "zod"; -import { auth } from "@/lib/auth"; -import { careers, db } from "@/db"; - -const idSchema = z.string().uuid(); -const careerUpdateSchema = z.object({ - title: z.string().min(1).optional(), - type: z.enum(["full-time", "contract", "volunteer"]).optional(), - location: z.string().min(1).optional(), - description: z.string().min(1).optional(), - requirements: z.string().min(1).optional(), - is_open: z.boolean().optional(), -}); - -type RouteContext = { - params: Promise<{ - id: string; - }>; -}; - -export async function GET(_request: Request, context: RouteContext) { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - const params = await context.params; - - try { - const parsedId = idSchema.safeParse(params.id); - - if (!parsedId.success) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - const [career] = await db - .select() - .from(careers) - .where(eq(careers.id, parsedId.data)) - .limit(1); - - if (!career) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - return NextResponse.json(career, { status: 200 }); - } catch (error) { - console.error("Failed to fetch career:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} - -export async function PUT(request: Request, context: RouteContext) { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - const params = await context.params; - - try { - const parsedId = idSchema.safeParse(params.id); - const parsedBody = careerUpdateSchema.safeParse(await request.json()); - - if (!parsedId.success || !parsedBody.success) { - return NextResponse.json( - { - error: "Invalid input", - details: parsedBody.success ? undefined : parsedBody.error.flatten(), - }, - { status: 400 }, - ); - } - - const [career] = await db - .update(careers) - .set({ ...parsedBody.data, updated_at: new Date() }) - .where(eq(careers.id, parsedId.data)) - .returning(); - - if (!career) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - return NextResponse.json(career, { status: 200 }); - } catch (error) { - console.error("Failed to update career:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} - -export async function DELETE(_request: Request, context: RouteContext) { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - const params = await context.params; - - try { - const parsedId = idSchema.safeParse(params.id); - - if (!parsedId.success) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - const [career] = await db - .delete(careers) - .where(eq(careers.id, parsedId.data)) - .returning({ id: careers.id }); - - if (!career) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - return NextResponse.json({ success: true }, { status: 200 }); - } catch (error) { - console.error("Failed to delete career:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} diff --git a/src/app/api/admin/careers/route.ts b/src/app/api/admin/careers/route.ts deleted file mode 100644 index 4eb5808..0000000 --- a/src/app/api/admin/careers/route.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { NextResponse } from "next/server"; -import { desc } from "drizzle-orm"; -import { z } from "zod"; -import { auth } from "@/lib/auth"; -import { careers, db } from "@/db"; - -const careerCreateSchema = z.object({ - title: z.string().min(1), - type: z.enum(["full-time", "contract", "volunteer"]), - location: z.string().min(1).optional(), - description: z.string().min(1), - requirements: z.string().min(1), - is_open: z.boolean().optional(), -}); - -export async function GET() { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - try { - const careerList = await db - .select() - .from(careers) - .orderBy(desc(careers.created_at)); - - return NextResponse.json(careerList, { status: 200 }); - } catch (error) { - console.error("Failed to fetch careers:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} - -export async function POST(request: Request) { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - try { - const parsed = careerCreateSchema.safeParse(await request.json()); - - if (!parsed.success) { - return NextResponse.json( - { error: "Invalid input", details: parsed.error.flatten() }, - { status: 400 }, - ); - } - - const [career] = await db.insert(careers).values(parsed.data).returning(); - - return NextResponse.json(career, { status: 201 }); - } catch (error) { - console.error("Failed to create career:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} diff --git a/src/app/api/admin/messages/[id]/route.ts b/src/app/api/admin/messages/[id]/route.ts deleted file mode 100644 index 1fb6fce..0000000 --- a/src/app/api/admin/messages/[id]/route.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { NextResponse } from "next/server"; -import { eq } from "drizzle-orm"; -import { z } from "zod"; -import { auth } from "@/lib/auth"; -import { contactSubmissions, db } from "@/db"; - -const idSchema = z.string().uuid(); -const messageUpdateSchema = z.object({ - is_read: z.boolean(), -}); - -type RouteContext = { - params: Promise<{ - id: string; - }>; -}; - -export async function PUT(request: Request, context: RouteContext) { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - const params = await context.params; - - try { - const parsedId = idSchema.safeParse(params.id); - const parsedBody = messageUpdateSchema.safeParse(await request.json()); - - if (!parsedId.success || !parsedBody.success) { - return NextResponse.json( - { - error: "Invalid input", - details: parsedBody.success ? undefined : parsedBody.error.flatten(), - }, - { status: 400 }, - ); - } - - const [message] = await db - .update(contactSubmissions) - .set({ is_read: parsedBody.data.is_read }) - .where(eq(contactSubmissions.id, parsedId.data)) - .returning(); - - if (!message) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - return NextResponse.json(message, { status: 200 }); - } catch (error) { - console.error("Failed to update message:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} - -export async function DELETE(_request: Request, context: RouteContext) { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - const params = await context.params; - - try { - const parsedId = idSchema.safeParse(params.id); - - if (!parsedId.success) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - const [message] = await db - .delete(contactSubmissions) - .where(eq(contactSubmissions.id, parsedId.data)) - .returning({ id: contactSubmissions.id }); - - if (!message) { - return NextResponse.json({ error: "Not found" }, { status: 404 }); - } - - return NextResponse.json({ success: true }, { status: 200 }); - } catch (error) { - console.error("Failed to delete message:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} diff --git a/src/app/api/admin/messages/route.ts b/src/app/api/admin/messages/route.ts deleted file mode 100644 index 776cca8..0000000 --- a/src/app/api/admin/messages/route.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { NextResponse } from "next/server"; -import { desc, eq } from "drizzle-orm"; -import { z } from "zod"; -import { auth } from "@/lib/auth"; -import { contactSubmissions, db } from "@/db"; - -const isReadSchema = z - .enum(["true", "false"]) - .transform((value) => value === "true") - .optional(); - -export async function GET(request: Request) { - const session = await auth(); - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - try { - const { searchParams } = new URL(request.url); - const parsedIsRead = isReadSchema.safeParse( - searchParams.get("is_read") ?? undefined, - ); - - if (!parsedIsRead.success) { - return NextResponse.json( - { error: "Invalid input", details: parsedIsRead.error.flatten() }, - { status: 400 }, - ); - } - - const whereClause = - typeof parsedIsRead.data === "boolean" - ? eq(contactSubmissions.is_read, parsedIsRead.data) - : undefined; - - const messages = await db - .select() - .from(contactSubmissions) - .where(whereClause) - .orderBy(desc(contactSubmissions.created_at)); - - return NextResponse.json(messages, { status: 200 }); - } catch (error) { - console.error("Failed to fetch messages:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} diff --git a/src/app/api/careers/apply/route.ts b/src/app/api/careers/apply/route.ts deleted file mode 100644 index 3997d16..0000000 --- a/src/app/api/careers/apply/route.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { NextResponse } from "next/server"; -import { and, eq } from "drizzle-orm"; -import { z, ZodError } from "zod"; -import { careerApplications, careers } from "@/db/schema"; -import { sendApplicationNotification } from "@/lib/email"; - -const applicationSchema = z.object({ - career_id: z.string().uuid(), - full_name: z.string().min(2), - email: z.string().email(), - cover_letter: z.string().min(50), - portfolio_url: z.string().url().optional(), - github_url: z.string().url().optional(), -}); - -export async function POST(request: Request) { - try { - const body: unknown = await request.json(); - const data = applicationSchema.parse(body); - const { db } = await import("@/db"); - - const [career] = await db - .select() - .from(careers) - .where(and(eq(careers.id, data.career_id), eq(careers.is_open, true))) - .limit(1); - - if (!career) { - return NextResponse.json( - { error: "This position is no longer accepting applications" }, - { status: 404 }, - ); - } - - await db.insert(careerApplications).values(data); - - await sendApplicationNotification({ - ...data, - career_title: career.title, - }); - - return NextResponse.json({ success: true }, { status: 200 }); - } catch (error) { - if (error instanceof ZodError) { - return NextResponse.json( - { - error: "Invalid input", - details: error.flatten(), - }, - { status: 400 }, - ); - } - - console.error("Failed to process career application:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} diff --git a/src/app/api/contact/route.ts b/src/app/api/contact/route.ts deleted file mode 100644 index 219341c..0000000 --- a/src/app/api/contact/route.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { NextResponse } from "next/server"; -import { z, ZodError } from "zod"; -import { contactSubmissions } from "@/db/schema"; -import { sendContactNotification } from "@/lib/email"; - -const contactSchema = z.object({ - full_name: z.string().min(2), - email: z.string().email(), - subject: z.enum([ - "General Inquiry", - "Partnership", - "Press", - "Investment", - "Other", - ]), - message: z.string().min(10), -}); - -export async function POST(request: Request) { - try { - const body: unknown = await request.json(); - const data = contactSchema.parse(body); - const { db } = await import("@/db"); - - await db.insert(contactSubmissions).values(data); - - try { - await sendContactNotification(data); - } catch (error) { - console.error("Failed to send contact notification email:", error); - } - - return NextResponse.json({ success: true }, { status: 200 }); - } catch (error) { - if (error instanceof ZodError) { - return NextResponse.json( - { - error: "Invalid input", - details: error.flatten(), - }, - { status: 400 }, - ); - } - - console.error("Failed to process contact submission:", error); - return NextResponse.json( - { error: "Something went wrong" }, - { status: 500 }, - ); - } -} diff --git a/src/app/globals.css b/src/app/globals.css index 2ce3019..d102ec7 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,4 +1,6 @@ @import "tailwindcss"; +@import "tw-animate-css"; +@import "shadcn/tailwind.css"; :root { --color-bg: #FFFFFF; @@ -10,8 +12,44 @@ --color-text-muted: #6B7896; --color-accent: #121F38; --color-accent-hover: #1A2D4F; + --color-accent-amber: #C98A3A; + --color-accent-green: #2F6F4E; + --color-accent-clay: #A85D3A; + --color-accent-blue: #3B82F6; --color-success: #16A34A; --color-error: #DC2626; + --background: #FFFFFF; + --foreground: #2C3A52; + --card: #FFFFFF; + --card-foreground: #2C3A52; + --popover: #FFFFFF; + --popover-foreground: #2C3A52; + --primary: #121F38; + --primary-foreground: #FFFFFF; + --secondary: #D1D6E0; + --secondary-foreground: #121F38; + --muted: #F4F5F8; + --muted-foreground: #6B7896; + --accent: #F4F5F8; + --accent-foreground: #121F38; + --destructive: #DC2626; + --border: #C4CAD6; + --input: #C4CAD6; + --ring: #121F38; + --chart-1: #121F38; + --chart-2: #C98A3A; + --chart-3: #2F6F4E; + --chart-4: #3B82F6; + --chart-5: #A85D3A; + --radius: 0.5rem; + --sidebar: #F4F5F8; + --sidebar-foreground: #121F38; + --sidebar-primary: #121F38; + --sidebar-primary-foreground: #FFFFFF; + --sidebar-accent: #D1D6E0; + --sidebar-accent-foreground: #121F38; + --sidebar-border: #C4CAD6; + --sidebar-ring: #121F38; } body { @@ -27,3 +65,158 @@ h4 { font-family: var(--font-jetbrains-mono); color: var(--color-text-primary); } + +.hero-enter { + animation: hero-enter 700ms ease-out both; +} + +.hero-enter-delay { + animation-delay: 160ms; +} + +.hero-mascot-wrap { + animation: hero-enter 800ms ease-out 220ms both; +} + +.hero-visual-enter { + animation: hero-enter 850ms ease-out 180ms both; +} + +.hero-route { + animation: hero-route-flow 2600ms ease-in-out infinite; + stroke-dasharray: 10 12; +} + +.hero-route-delay { + animation-delay: 520ms; +} + +.hero-node { + animation: hero-node-pulse 2300ms ease-in-out infinite; + transform-box: fill-box; + transform-origin: center; +} + +.hero-cta { + transform: translateY(0); + transition: transform 180ms ease, box-shadow 180ms ease; +} + +.hero-cta:hover { + transform: translateY(-2px); +} + +@keyframes hero-enter { + from { + opacity: 0; + transform: translateY(18px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes hero-route-flow { + 0%, + 100% { + opacity: 0.78; + stroke-dashoffset: 0; + } + + 50% { + opacity: 1; + stroke-dashoffset: -24; + } +} + +@keyframes hero-node-pulse { + 0%, + 100% { + opacity: 0.16; + transform: scale(0.85); + } + + 50% { + opacity: 0.32; + transform: scale(1.35); + } +} + +@media (prefers-reduced-motion: reduce) { + .hero-enter, + .hero-mascot-wrap, + .hero-visual-enter, + .hero-route, + .hero-node { + animation: none; + } + + .hero-cta { + transition: none; + } + + .hero-cta:hover { + transform: none; + } +} + +@theme inline { + --font-heading: var(--font-jetbrains-mono); + --font-sans: var(--font-ibm-plex-sans); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-accent-blue: var(--color-accent-blue); + --color-accent-clay: var(--color-accent-clay); + --color-accent-green: var(--color-accent-green); + --color-accent-amber: var(--color-accent-amber); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --color-foreground: var(--foreground); + --color-background: var(--background); + --radius-sm: calc(var(--radius) * 0.6); + --radius-md: calc(var(--radius) * 0.8); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) * 1.4); + --radius-2xl: calc(var(--radius) * 1.8); + --radius-3xl: calc(var(--radius) * 2.2); + --radius-4xl: calc(var(--radius) * 2.6); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + html { + @apply font-sans; + } +} diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts index 6d864a1..94e2411 100644 --- a/src/app/sitemap.ts +++ b/src/app/sitemap.ts @@ -1,6 +1,6 @@ import type { MetadataRoute } from "next"; import { desc, eq } from "drizzle-orm"; -import { blogPosts, db, products } from "@/db"; +import { blogPosts, db } from "@/db"; export const revalidate = 3600; @@ -8,12 +8,8 @@ const baseUrl = "https://codeddevs.com"; const staticRoutes = [ "", - "/about", - "/products", "/blog", "/team", - "/careers", - "/contact", ]; export default async function sitemap(): Promise { @@ -24,30 +20,17 @@ export default async function sitemap(): Promise { })); try { - const [productEntries, postEntries] = await Promise.all([ - db - .select({ - slug: products.slug, - updated_at: products.updated_at, - }) - .from(products) - .orderBy(products.order_index), - db - .select({ - slug: blogPosts.slug, - updated_at: blogPosts.updated_at, - }) - .from(blogPosts) - .where(eq(blogPosts.is_published, true)) - .orderBy(desc(blogPosts.published_at)), - ]); + const postEntries = await db + .select({ + slug: blogPosts.slug, + updated_at: blogPosts.updated_at, + }) + .from(blogPosts) + .where(eq(blogPosts.is_published, true)) + .orderBy(desc(blogPosts.published_at)); return [ ...staticEntries, - ...productEntries.map((product) => ({ - url: `${baseUrl}/products/${product.slug}`, - lastModified: product.updated_at, - })), ...postEntries.map((post) => ({ url: `${baseUrl}/blog/${post.slug}`, lastModified: post.updated_at, diff --git a/src/components/admin/ApplicationsManager.tsx b/src/components/admin/ApplicationsManager.tsx deleted file mode 100644 index bcc4137..0000000 --- a/src/components/admin/ApplicationsManager.tsx +++ /dev/null @@ -1,214 +0,0 @@ -"use client"; - -import { useMemo, useState } from "react"; -import Badge from "@/components/ui/Badge"; -import { cn } from "@/lib/utils"; - -export type AdminApplication = { - id: string; - career_title: string | null; - full_name: string; - email: string; - portfolio_url: string | null; - github_url: string | null; - cover_letter: string; - status: "pending" | "reviewed" | "rejected"; - created_at: string; -}; - -type ApplicationFilter = "all" | AdminApplication["status"]; - -type ApplicationsManagerProps = { - applications: AdminApplication[]; -}; - -const filters: Array<{ label: string; value: ApplicationFilter }> = [ - { label: "All", value: "all" }, - { label: "Pending", value: "pending" }, - { label: "Reviewed", value: "reviewed" }, - { label: "Rejected", value: "rejected" }, -]; - -function formatDate(date: string) { - return new Intl.DateTimeFormat("en", { - month: "short", - day: "numeric", - year: "numeric", - }).format(new Date(date)); -} - -function statusVariant(status: AdminApplication["status"]) { - if (status === "reviewed") { - return "success"; - } - - if (status === "rejected") { - return "warning"; - } - - return "default"; -} - -export default function ApplicationsManager({ - applications, -}: ApplicationsManagerProps) { - const [filter, setFilter] = useState("all"); - const [openId, setOpenId] = useState(null); - const [items, setItems] = useState(applications); - - const filteredItems = useMemo(() => { - if (filter === "all") { - return items; - } - - return items.filter((item) => item.status === filter); - }, [filter, items]); - - async function updateStatus( - id: string, - status: AdminApplication["status"], - ) { - try { - const response = await fetch(`/api/admin/applications/${id}`, { - method: "PUT", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ status }), - }); - - if (!response.ok) { - window.alert("Status update failed."); - return; - } - } catch { - window.alert("Status update failed."); - return; - } - - setItems((current) => - current.map((item) => (item.id === id ? { ...item, status } : item)), - ); - } - - return ( -
-
- {filters.map((item) => ( - - ))} -
- -
- - - - - - - - - - - - {filteredItems.map((application) => { - const isOpen = openId === application.id; - const detailsId = `application-${application.id}-details`; - - return ( - - - - - - - - ); - })} - -
ApplicantRoleStatusDateDetails
-

- {application.full_name} -

-

- {application.email} -

- {isOpen ? ( -
-

{application.cover_letter}

- {application.portfolio_url ? ( - - Portfolio - - ) : null} - {application.github_url ? ( - - GitHub - - ) : null} -
- ) : null} -
- {application.career_title ?? "Unknown role"} - -
- - {application.status} - - -
-
- {formatDate(application.created_at)} - - -
-
-
- ); -} diff --git a/src/components/admin/MessagesManager.tsx b/src/components/admin/MessagesManager.tsx deleted file mode 100644 index 212f2ac..0000000 --- a/src/components/admin/MessagesManager.tsx +++ /dev/null @@ -1,161 +0,0 @@ -"use client"; - -import { useState } from "react"; -import Button from "@/components/ui/Button"; - -export type AdminMessage = { - id: string; - full_name: string; - email: string; - subject: string; - message: string; - is_read: boolean; - created_at: string; -}; - -type MessagesManagerProps = { - messages: AdminMessage[]; -}; - -function formatDate(date: string) { - return new Intl.DateTimeFormat("en", { - month: "short", - day: "numeric", - year: "numeric", - }).format(new Date(date)); -} - -export default function MessagesManager({ messages }: MessagesManagerProps) { - const [items, setItems] = useState(messages); - const [openId, setOpenId] = useState(null); - - async function markAsRead(id: string) { - try { - const response = await fetch(`/api/admin/messages/${id}`, { - method: "PUT", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ is_read: true }), - }); - - if (!response.ok) { - window.alert("Update failed."); - return; - } - } catch { - window.alert("Update failed."); - return; - } - - setItems((current) => - current.map((item) => (item.id === id ? { ...item, is_read: true } : item)), - ); - } - - async function deleteMessage(id: string) { - if (!window.confirm("Delete this message?")) { - return; - } - - try { - const response = await fetch(`/api/admin/messages/${id}`, { - method: "DELETE", - }); - - if (!response.ok) { - window.alert("Delete failed."); - return; - } - } catch { - window.alert("Delete failed."); - return; - } - - setItems((current) => current.filter((item) => item.id !== id)); - } - - return ( -
- - - - - - - - - - - {items.map((message) => { - const isOpen = openId === message.id; - const detailsId = `message-${message.id}-details`; - - return ( - - - - - - - ); - })} - -
SenderSubjectDateActions
-
- {!message.is_read ? ( - - ) : null} -
-

- {message.full_name} -

-

{message.email}

- {isOpen ? ( -

- {message.message} -

- ) : null} -
-
-
{message.subject} - {formatDate(message.created_at)} - -
- - {!message.is_read ? ( - - ) : null} - -
-
-
- ); -} diff --git a/src/components/admin/AdminDeleteButton.tsx b/src/components/admin/actions/AdminDeleteButton.tsx similarity index 100% rename from src/components/admin/AdminDeleteButton.tsx rename to src/components/admin/actions/AdminDeleteButton.tsx diff --git a/src/components/admin/RichTextEditor.tsx b/src/components/admin/editors/RichTextEditor.tsx similarity index 98% rename from src/components/admin/RichTextEditor.tsx rename to src/components/admin/editors/RichTextEditor.tsx index eee94b1..a6b16a7 100644 --- a/src/components/admin/RichTextEditor.tsx +++ b/src/components/admin/editors/RichTextEditor.tsx @@ -4,7 +4,7 @@ import ImageExtension from "@tiptap/extension-image"; import TiptapLink from "@tiptap/extension-link"; import { EditorContent, useEditor } from "@tiptap/react"; import StarterKit from "@tiptap/starter-kit"; -import ImageUpload from "@/components/admin/ImageUpload"; +import ImageUpload from "@/components/admin/media/ImageUpload"; import Button from "@/components/ui/Button"; import { cn } from "@/lib/utils"; diff --git a/src/components/admin/ResourceForms.tsx b/src/components/admin/forms/ResourceForms.tsx similarity index 81% rename from src/components/admin/ResourceForms.tsx rename to src/components/admin/forms/ResourceForms.tsx index 32074c5..95f002a 100644 --- a/src/components/admin/ResourceForms.tsx +++ b/src/components/admin/forms/ResourceForms.tsx @@ -5,10 +5,10 @@ import { useMemo, useState, type FormEvent } from "react"; import Button from "@/components/ui/Button"; import Input from "@/components/ui/Input"; import Textarea from "@/components/ui/Textarea"; -import ImageUpload from "@/components/admin/ImageUpload"; +import ImageUpload from "@/components/admin/media/ImageUpload"; import RichTextEditor, { type TiptapJson, -} from "@/components/admin/RichTextEditor"; +} from "@/components/admin/editors/RichTextEditor"; import { slugify } from "@/lib/utils"; type FormMode = "create" | "edit"; @@ -52,14 +52,6 @@ type BlogFormValues = { placement: "1st" | "2nd" | "3rd" | "winner" | ""; }; -type CareerFormValues = { - title: string; - type: "full-time" | "contract" | "volunteer"; - location: string; - description: string; - requirements: string; - is_open: boolean; -}; type TeamFormProps = { mode: FormMode; @@ -79,11 +71,6 @@ type BlogFormProps = { endpoint: string; }; -type CareerFormProps = { - mode: FormMode; - initialValues?: Partial; - endpoint: string; -}; const emptyDocument: TiptapJson = { type: "doc", @@ -353,10 +340,12 @@ export function BlogPostForm({ mode, initialValues, endpoint }: BlogFormProps) { setValues({ ...values, is_published: event.target.checked })} /> Published -