diff --git a/apps/web/src/app/(main)/dashboard/newsletter/[id]/page.tsx b/apps/web/src/app/(main)/dashboard/newsletter/[id]/page.tsx
new file mode 100644
index 0000000..61e60d9
--- /dev/null
+++ b/apps/web/src/app/(main)/dashboard/newsletter/[id]/page.tsx
@@ -0,0 +1,314 @@
+import { Button } from "@/components/ui/button";
+import { getNewsletterById } from "@/lib/newsletters";
+import { ChevronLeft } from "lucide-react";
+import Link from "next/link";
+
+type params = {
+ params: { id: string };
+};
+
+function renderInline(text: string) {
+ // inline tags with backticks like `good first issue`, bold **text** and links [text](url)
+ const parts = text.split(/(`[^`]+`)/g).filter(Boolean);
+ return parts.flatMap((part, idx) => {
+ // backtick tag -> render as pill/tag
+ if (/^`[^`]+`$/.test(part)) {
+ const inner = part.slice(1, -1);
+ return (
+
+ {inner}
+
+ );
+ }
+
+ // handle links inside non-backtick segments
+ const boldParts = part.split(/(\*\*[^*]+\*\*)/g).filter(Boolean);
+ return boldParts.map((bp, j) => {
+ if (/^\*\*/.test(bp)) {
+ const inner = bp.replace(/\*\*/g, "");
+ return (
+
+ {inner}
+
+ );
+ }
+
+ // handle multiple links in the segment
+ const nodes: any[] = [];
+ const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
+ let lastIndex = 0;
+ let m: RegExpExecArray | null;
+ while ((m = linkRegex.exec(bp)) !== null) {
+ const [matchText, t, url] = m;
+ const index = m.index;
+ if (index > lastIndex) nodes.push(bp.slice(lastIndex, index));
+ nodes.push(
+
+ {t}
+
+ );
+ lastIndex = index + matchText.length;
+ }
+ if (lastIndex < bp.length) nodes.push(bp.slice(lastIndex));
+
+ return (
+
+ {nodes.map((n, k) =>
+ typeof n === "string" ? {n} : n
+ )}
+
+ );
+ });
+ });
+}
+
+function renderMarkdown(md: string) {
+ const lines = md.split("\n");
+ const nodes: any[] = [];
+ let listBuffer: string[] = [];
+ let blockquoteBuffer: string[] = [];
+
+ function flushList() {
+ if (listBuffer.length) {
+ nodes.push(
+
+ {listBuffer.map((li, i) => (
+ {renderInline(li.replace(/^-\s*/, ""))}
+ ))}
+
+ );
+ listBuffer = [];
+ }
+ }
+
+ lines.forEach((raw, idx) => {
+ if (raw === "__CONSUMED__") return;
+ const line = raw.trim();
+ // handle code blocks
+ if (line.startsWith("```")) {
+ flushList();
+ const lang = line.slice(3).trim();
+ const codeLines: string[] = [];
+ let j = idx + 1;
+ while (j < lines.length && !lines[j].trim().startsWith("```")) {
+ codeLines.push(lines[j]);
+ j++;
+ }
+ const codeContent = codeLines.join("\n");
+ if (lang === "embed") {
+ // embed block expects a URL in the content
+ const src = codeContent.trim();
+ try {
+ const url = new URL(src);
+ if (!["http:", "https:"].includes(url.protocol)) {
+ console.warn("Invalid embed URL protocol:", src);
+ return; // skip this embed
+ }
+ } catch {
+ console.warn("Invalid embed URL:", src);
+ }
+ nodes.push(
+
+ );
+ } else {
+ nodes.push(
+
+ {codeContent}
+
+ );
+ }
+ // replace consumed lines with empties so outer loop sees them as blank and skips
+ for (let k = idx; k <= j; k++) {
+ lines[k] = "__CONSUMED__";
+ }
+ return;
+ }
+ if (!line) {
+ flushList();
+ if (blockquoteBuffer.length) {
+ nodes.push(
+
+ {blockquoteBuffer.map((l, i) => (
+
+ {renderInline(l.replace(/^>\s?/, ""))}
+
+ ))}
+
+ );
+ blockquoteBuffer = [];
+ }
+ return nodes.push(
);
+ }
+ // heading 1
+ if (line.startsWith("# ")) {
+ flushList();
+ nodes.push(
+
+ {renderInline(line.replace(/^#\s+/, ""))}
+
+ );
+ return;
+ }
+ // heading 2
+ if (line.startsWith("## ")) {
+ flushList();
+ nodes.push(
+
+ {renderInline(line.replace(/^##\s+/, ""))}
+
+ );
+ return;
+ }
+ // heading 3
+ if (line.startsWith("### ")) {
+ flushList();
+ nodes.push(
+
+ {renderInline(line.replace(/^###\s+/, ""))}
+
+ );
+ return;
+ }
+ // blockquote
+ if (line.startsWith("> ") || line === ">") {
+ blockquoteBuffer.push(raw);
+ return;
+ }
+
+ // image
+ const imgMatch = line.match(/!\[([^\]]*)\]\(([^)]+)\)/);
+ if (imgMatch) {
+ flushList();
+ if (blockquoteBuffer.length) {
+ nodes.push(
+
+ {blockquoteBuffer.map((l, i) => (
+
+ {renderInline(l.replace(/^>\s?/, ""))}
+
+ ))}
+
+ );
+ blockquoteBuffer = [];
+ }
+ const [, alt, url] = imgMatch;
+ try {
+ const imgUrl = new URL(url);
+ if (!["http:", "https:", "data:"].includes(imgUrl.protocol)) {
+ console.warn("Invalid image URL protocol:", url);
+ return; // Skip this image
+ }
+ } catch (error) {
+ // Relative URLs are OK, will throw but we can allow them
+ if (!url.startsWith("/") && !url.startsWith("./")) {
+ console.warn("Invalid image URL:", url);
+ return;
+ }
+ }
+ nodes.push(
+
+
+
+ );
+ return;
+ }
+ // list
+ if (line.startsWith("- ")) {
+ listBuffer.push(line);
+ return;
+ }
+
+ // paragraph
+ flushList();
+ if (blockquoteBuffer.length) {
+ nodes.push(
+
+ {blockquoteBuffer.map((l, i) => (
+
+ {renderInline(l.replace(/^>\s?/, ""))}
+
+ ))}
+
+ );
+ blockquoteBuffer = [];
+ }
+ nodes.push(
+
+ {renderInline(line)}
+
+ );
+ });
+
+ flushList();
+ return nodes;
+}
+
+export default function NewsletterArticle({ params }: params) {
+ const id = params.id;
+ const item = getNewsletterById(id);
+ if (!item) {
+ return newsletter not found
;
+ }
+
+ return (
+
+
+
+ Back
+
+
+ {new Date(item.date).toLocaleDateString()}
+
+
+ {renderMarkdown(item.content)}
+
+
+
+ view all newsletters
+
+
+
+ );
+}
diff --git a/apps/web/src/app/(main)/dashboard/newsletter/page.tsx b/apps/web/src/app/(main)/dashboard/newsletter/page.tsx
new file mode 100644
index 0000000..51ba777
--- /dev/null
+++ b/apps/web/src/app/(main)/dashboard/newsletter/page.tsx
@@ -0,0 +1,103 @@
+"use client";
+import NewsletterList from "@/components/newsletter/newsletter-list";
+import { useSubscription } from "@/hooks/useSubscription";
+import { getAllNewslettersSorted } from "@/lib/newsletters";
+import Link from "next/link";
+import { useMemo, useState } from "react";
+
+export default function NewsletterPage() {
+ const items = getAllNewslettersSorted();
+ const { isPaidUser, isLoading } = useSubscription();
+ const [query, setQuery] = useState("");
+
+ const filtered = useMemo(() => {
+ const q = query.trim();
+ if (!q) return items;
+ return items.filter((it) => {
+ const hay = `${it.title} ${it.excerpt ?? ""} ${it.content}`;
+ return hay.includes(q);
+ });
+ }, [items, query]);
+
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ if (!isPaidUser) {
+ return (
+
+
+
+
+ Premium only
+
+
+ Newsletters are available for premium subscribers only. Upgrade to
+ access exclusive content and weekly insights.
+
+
+
+ Upgrade to Premium
+
+
+ Back to home
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+ Search newsletters
+
+
+ setQuery(e.target.value)}
+ placeholder="Search by title, excerpt or content..."
+ className="w-full bg-[#0b0b0c] border border-[#222] rounded-md px-3 py-2 text-ox-white placeholder:opacity-60 focus:outline-none focus:ring-2 focus:ring-ox-purple"
+ />
+ {query && (
+ setQuery("")}
+ className="absolute right-2 top-1/2 -translate-y-1/2 text-sm text-ox-white/70 hover:text-ox-white"
+ aria-label="Clear search"
+ >
+ β
+
+ )}
+
+
+
+ {filtered.length} result{filtered.length === 1 ? "" : "s"}
+
+
+
+
+
+ );
+}
diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css
index 6ae57e0..cf9de8d 100644
--- a/apps/web/src/app/globals.css
+++ b/apps/web/src/app/globals.css
@@ -73,4 +73,33 @@
html {
scroll-behavior: smooth;
+}
+
+@layer components {
+ /* Markdown / prose adjustments */
+ .prose a {
+ @apply text-ox-purple underline;
+ }
+
+ /* generic inline code fallback - we still render special tags in React,
+ but this makes any other inline code look consistent */
+ .prose code {
+ background-color: rgba(139, 92, 246, 0.08);
+ color: #a78bfa;
+ padding: 0.125rem 0.25rem;
+ border-radius: 0.375rem;
+ font-size: 0.75rem;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", "Helvetica Neue", monospace;
+ }
+
+ /* improve spacing and readable line-height inside articles */
+ .prose p {
+ line-height: 1.7;
+ }
+
+ .prose h1,
+ .prose h2,
+ .prose h3 {
+ color: var(--foreground);
+ }
}
\ No newline at end of file
diff --git a/apps/web/src/components/dashboard/Sidebar.tsx b/apps/web/src/components/dashboard/Sidebar.tsx
index eabb046..daf3376 100644
--- a/apps/web/src/components/dashboard/Sidebar.tsx
+++ b/apps/web/src/components/dashboard/Sidebar.tsx
@@ -23,6 +23,7 @@ import { signOut } from "next-auth/react";
import { Twitter } from "../icons/icons";
import { ProfilePic } from "./ProfilePic";
import { useFilterStore } from "@/store/useFilterStore";
+import { Newspaper } from "lucide-react";
const SIDEBAR_ROUTES = [
{
@@ -35,6 +36,11 @@ const SIDEBAR_ROUTES = [
label: "Projects",
icon: ,
},
+ {
+ path: "/dashboard/newsletter",
+ label: "Newsletter",
+ icon: ,
+ },
];
const getSidebarLinkClassName = (currentPath: string, routePath: string) => {
diff --git a/apps/web/src/components/newsletter/newsletter-card.tsx b/apps/web/src/components/newsletter/newsletter-card.tsx
new file mode 100644
index 0000000..e3811ed
--- /dev/null
+++ b/apps/web/src/components/newsletter/newsletter-card.tsx
@@ -0,0 +1,41 @@
+import Link from "next/link";
+import { Calendar } from "lucide-react";
+
+type props = {
+ id: string;
+ title: string;
+ date: string;
+ excerpt?: string;
+};
+
+export default function NewsletterCard({ id, title, date, excerpt }: props) {
+ const formattedDate = new Date(date).toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ });
+ return (
+
+
+
+ {formattedDate}
+
+
+
+ {title}
+
+
+ {excerpt && (
+
+ {excerpt}
+
+ )}
+
+ );
+}
diff --git a/apps/web/src/components/newsletter/newsletter-list.tsx b/apps/web/src/components/newsletter/newsletter-list.tsx
new file mode 100644
index 0000000..1003b61
--- /dev/null
+++ b/apps/web/src/components/newsletter/newsletter-list.tsx
@@ -0,0 +1,47 @@
+import NewsletterCard from "./newsletter-card";
+import { groupByMonth, type newsletter } from "@/lib/newsletters";
+
+type props = {
+ items: newsletter[];
+};
+
+// function groupByMonth(items: newsletter[]) {
+// const map: Record = {};
+// items.forEach((it) => {
+// const d = new Date(it.date);
+// if (isNaN(d.getTime())) {
+// console.warn(`Invalid date for newsletter fit.id}:`, it.date);
+// return;
+// }
+// const key = d.toLocaleString("default", { month: "long", year: "numeric" });
+// if (!map[key]) map[key] = [];
+// map[key].push(it);
+// });
+// return map;
+// }
+
+export default function NewsletterList({ items }: props) {
+ const grouped = groupByMonth(items);
+ const months = Object.keys(grouped).sort((a, b) => (a > b ? 1 : -1));
+
+ return (
+
+ {months.map((m) => (
+
+ {m}
+
+ {grouped[m].map((n) => (
+
+ ))}
+
+
+ ))}
+
+ );
+}
diff --git a/apps/web/src/lib/newsletters.ts b/apps/web/src/lib/newsletters.ts
new file mode 100644
index 0000000..c9401db
--- /dev/null
+++ b/apps/web/src/lib/newsletters.ts
@@ -0,0 +1,286 @@
+export type newsletter = {
+ id: string;
+ title: string;
+ date: string;
+ excerpt?: string;
+ content: string; // markdown
+};
+
+export const newsletters: newsletter[] = [
+ {
+ id: "2025-10-10-ai-in-open-source",
+ title: "How AI is reshaping open-source development",
+ date: "2025-10-10",
+ excerpt:
+ "From automated reviews to semantic search β how AI is transforming contributor workflows and community growth.",
+ content: `# π€ How AI Is Reshaping Open-Source Development
+
+
+
+AI isn't just assisting developers β it's becoming a core part of how open-source projects scale, collaborate, and maintain quality.
+
+---
+
+## β‘ This Weekβs Highlights
+
+- GitHub rolls out \`ai-powered triage\` for community issues
+- \`semantic search\` added to multiple large OSS repos
+- Bun introduces **AI-accelerated runtime hints**
+- Read more: [AI and OSS β The New Era](https://example.com)
+
+---
+
+## π§ Deep Dive β AI as Your Co-Maintainer
+
+### What AI Can Already Do
+
+- Suggest PR comments using \`contextual review\`
+- Auto-label issues with \`topic detection\`
+- Identify flaky tests
+- Generate documentation from commit history
+
+
+
+### Why Maintainers Love It
+
+AI removes 30β50% of manual workflow overhead:
+
+- Faster backlog cleanup
+- Better contributor onboarding
+- High-quality review signals
+- Reduced time to merge
+
+---
+
+## π Contribute This Week
+
+- \`good first issue\` β Improve AI prompt templates
+- Add retry logic to API calls
+- Write auto-generated schema docs
+- Improve error logs for observability
+- Read: [Scaling OSS with AI](https://example.com/ai)
+
+---
+
+## π Tool of the Week β CodePilot
+
+
+
+CodePilot brings realtime AI code search with unmatched accuracy.
+
+**Features:**
+
+- \`neural indexing\`
+- Instant dependency graphing
+- Natural language queries
+- Works across monorepos
+
+---
+
+## π Final Thoughts
+
+AI isnβt replacing open-source β itβs **amplifying it**.
+Your role as a contributor is more powerful than ever.
+
+See you next week! β¨`,
+ },
+ {
+ id: "2025-11-08-open-source-community-growth",
+ title: "Building strong open-source communities",
+ date: "2025-11-08",
+ excerpt:
+ "How maintainers build inclusive, impactful communities β and the patterns that help projects grow beyond 10k stars.",
+ content: `# π± Building Strong Open-Source Communities
+
+
+
+Behind every great open-source project is a supportive, structured, and welcoming community.
+
+---
+
+## π¬ Quote of the Week
+
+> βthe strength of an open-source project isnβt just its code β
+> itβs the people who choose to build it together.β
+
+---
+
+## π‘ Highlights of the Week
+
+- Discord adds \`dev forums\` for OSS teams
+- GitHub Sponsors hits **$1M/day**
+- New OSS governance templates released
+- Read more: [How Communities Scale](https://example.com)
+
+---
+
+## π Deep Dive β What Makes Great Communities?
+
+### The Three Pillars
+
+- Clear contribution rules
+- Transparent decision-making
+- \`good first issue\` pathways for beginners
+
+
+
+### Maintainers Should Prioritize
+
+- Onboarding callouts
+- Constructive PR reviews
+- Public roadmaps
+- Celebration of contributors
+
+---
+
+## π§ͺ Example Snippet β Auto-Tag New Contributors
+
+Sometimes maintainers automate contributor labeling.
+Hereβs a simple example:
+
+\`\`\`ts
+import { Octokit } from "octokit";
+
+export async function tagNewContributor(repo, username) {
+ const client = new Octokit({ auth: process.env.GITHUB_TOKEN });
+
+ await client.request("POST /repos/{owner}/{repo}/issues/{issue_number}/labels", {
+ owner: "opensox",
+ repo,
+ issue_number: 1,
+ labels: ["new-contributor"]
+ });
+}
+\`\`\`
+
+---
+
+## π― Contribute This Week
+
+- Create onboarding examples
+- Add \`beginner friendly\` labels to issues
+- Improve repo README structure
+- Build a FAQs page
+- Read: [Community Management 101](https://example.com/community)
+
+---
+
+## π§° Tool of the Week β ContribBoard
+
+
+
+This tool helps maintainers organize issues visually.
+
+**Features:**
+
+- Kanban-style boards
+- \`priority tagging\`
+- Weekly contributor highlights
+- Automated cleanup scripts
+
+---
+
+## π Final Thoughts
+
+Communities donβt grow by accident β they grow by intention.
+Keep building, keep supporting, keep contributing.
+
+Until next time! π`,
+ },
+ {
+ id: "2025-11-06-maintainer-survival-kit",
+ title: "The maintainer's survival kit",
+ date: "2025-11-06",
+ excerpt:
+ "Best practices, tooling, automation, and mindset for maintainers handling fast-growing repositories.",
+ content: `# π§° The Maintainerβs Survival Kit
+
+
+
+Maintaining a popular project is exciting β but chaotic. Hereβs what helps maintainers stay sane and scalable.
+
+---
+
+## π¦ Weekly Maintainer Updates
+
+- GitHub adds \`auto cleanup\` for stale issues
+- npm introduces **dependency risk badges**
+- Deno releases streaming test runner
+- Read: [The Future of Maintenance](https://example.com)
+
+---
+
+## π Deep Dive β Scaling Without Burnout
+
+### What Works
+
+- Scheduled \`triage sessions\`
+- Automated PR labeling
+- Clear boundaries for contributions
+- Using bots for repetitive tasks
+
+### Tools That Save Time
+
+- Action bots for CI
+- Semantic release workflows
+- Dependabot
+- Auto-generated changelogs
+
+---
+
+## π§© Contribute This Week
+
+- \`good first issue\` β Document the automation setup
+- Add CI badges
+- Simplify configuration scripts
+- Add missing unit tests
+- Read: [Maintainer Guide](https://example.com)
+
+---
+
+## π Tool of the Week β TaskFlow
+
+
+
+taskflow automates heavy maintainer workflows.
+
+**Best Features:**
+
+- \`workflow templates\`
+- Instant CI insights
+- Issue clustering
+- Scheduled automation
+
+---
+
+## π Final Thoughts
+
+Maintenance should feel manageable β not overwhelming.
+Automation is your best ally.
+
+See you soon! βοΈ`,
+ },
+];
+
+export function getNewsletterById(id: string) {
+ return newsletters.find((n) => n.id === id);
+}
+
+export function getAllNewslettersSorted() {
+ return [...newsletters].sort((a, b) => (a.date < b.date ? 1 : -1));
+}
+
+export function groupByMonth(items: newsletter[]) {
+ const map: Record = {};
+ items.forEach((it) => {
+ const d = new Date(it.date);
+ if (isNaN(d.getTime())) {
+ console.warn(`Invalid date for newsletter fit.id}:`, it.date);
+ return;
+ }
+ const key = d.toLocaleString("default", { month: "long", year: "numeric" });
+ if (!map[key]) map[key] = [];
+ map[key].push(it);
+ });
+ return map;
+}
\ No newline at end of file
diff --git a/docs/NEWSLETTER.md b/docs/NEWSLETTER.md
new file mode 100644
index 0000000..0feb41f
--- /dev/null
+++ b/docs/NEWSLETTER.md
@@ -0,0 +1,62 @@
+# newsletter
+
+This document explains how to add or update a newsletter entry. Keep content concise and focused.
+
+Location
+
+- Source: `apps/web/src/lib/newsletters.ts`
+- Components: `apps/web/src/components/newsletter/newsletter-list.tsx` and `apps/web/src/components/newsletter/newsletter-card.tsx`
+- Pages: `apps/web/src/app/(main)/dashboard/newsletter/page.tsx` and `apps/web/src/app/(main)/dashboard/newsletter/[id]/page.tsx`
+
+Structure
+
+- Type (see `apps/web/src/lib/newsletters.ts`):
+ - `id: string` β unique id, recommended format `yyyy-mm-dd-short-title`.
+ - `title: string` β article title.
+ - `date: string` β ISO date string (`yyyy-mm-dd`).
+ - `excerpt?: string` β short one-line excerpt (optional).
+ - `content: string` β markdown content (see supported features below).
+
+Supported content
+
+- Full markdown is supported in practice (headings, code fences, inline code, bold/italic, links, images, lists). Examples used in the codebase include:
+ - Headings: `#`, `##`, `###`
+ - Bold: `**bold**`
+ - Inline code: `` `example` ``
+ - Code blocks: triple backticks (```)
+ - Links: `[text](url)`
+ - Images: ``
+ - Bullet lists starting with `- `
+ - Emojis and short HTML-like separators (e.g. `---`) are used in current entries.
+
+Helpers
+
+- `getAllNewslettersSorted()` β returns all newsletters sorted newest first (used by the listing page).
+- `getNewsletterById(id)` β returns a single newsletter by `id` (used by the article page).
+
+Adding a newsletter
+
+1. Open `apps/web/src/lib/newsletters.ts`.
+2. Add a new item to the `newsletters` array. Use an `id` like `yyyy-mm-dd-short-title` (must be unique).
+3. Set `date` to the ISO `yyyy-mm-dd` format.
+4. Add an `excerpt` if you want a custom preview text (optional).
+5. Put the article body in `content` using markdown (you may use code fences and images).
+6. Create a PR that describes the newsletter and includes any screenshots or a short screen recording of the flow (optional but helpful).
+
+Notes about the UI and access
+
+- Newsletters are grouped in the UI by month and year, newest first.
+- The listing page includes client-side search (searches title, excerpt, and content).
+- Access: newsletters are shown to premium subscribers in the app. The UI checks subscription state before rendering full content.
+
+Routes / Preview
+
+- List: `/dashboard/newsletter`
+- Article: `/dashboard/newsletter/:id` (example: `/dashboard/newsletter/2025-10-10-ai-in-open-source`)
+
+Tips
+
+- Keep the `excerpt` short and descriptive for listing previews.
+- Use code fences for any multi-line code examples.
+- Prefer externally hosted images (the examples use Unsplash URLs).
+- If your content contains sensitive or private information, do not add it to this file β newsletters are committed to the repo and public in the deployed site for subscribers.
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8b60240..63ad96e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -147,7 +147,7 @@ importers:
version: 1.3.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot':
specifier: ^1.1.0
- version: 1.2.3(@types/react@18.3.23)(react@18.3.1)
+ version: 1.2.4(@types/react@18.3.23)(react@18.3.1)
'@tanstack/react-query':
specifier: ^5.90.2
version: 5.90.2(react@18.3.1)
@@ -1143,6 +1143,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-slot@1.2.4':
+ resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-use-callback-ref@1.1.1':
resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==}
peerDependencies:
@@ -1920,8 +1929,8 @@ packages:
resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==}
engines: {node: '>=4'}
- axios@1.12.2:
- resolution: {integrity: sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==}
+ axios@1.13.2:
+ resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
axobject-query@4.1.0:
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
@@ -4377,6 +4386,9 @@ packages:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
+ tr46@0.0.3:
+ resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+
ts-api-utils@1.4.3:
resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
engines: {node: '>=16'}
@@ -5439,6 +5451,13 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.23
+ '@radix-ui/react-slot@1.2.4(@types/react@18.3.23)(react@18.3.1)':
+ dependencies:
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1)
+ react: 18.3.1
+ optionalDependencies:
+ '@types/react': 18.3.23
+
'@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.23)(react@18.3.1)':
dependencies:
react: 18.3.1
@@ -6312,7 +6331,7 @@ snapshots:
axe-core@4.10.3: {}
- axios@1.12.2:
+ axios@1.13.2:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.4
@@ -6918,7 +6937,7 @@ snapshots:
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1)
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
eslint-plugin-react: 7.37.5(eslint@8.57.1)
eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1)
@@ -6937,8 +6956,8 @@ snapshots:
'@typescript-eslint/parser': 8.34.0(eslint@8.57.1)(typescript@5.9.2)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1)
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
eslint-plugin-react: 7.37.5(eslint@8.57.1)
eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1)
@@ -6971,21 +6990,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1):
- dependencies:
- '@nolyfill/is-core-module': 1.0.39
- debug: 4.4.1
- eslint: 8.57.1
- get-tsconfig: 4.10.1
- is-bun-module: 2.0.0
- stable-hash: 0.0.5
- tinyglobby: 0.2.14
- unrs-resolver: 1.9.0
- optionalDependencies:
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
- transitivePeerDependencies:
- - supports-color
-
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1):
dependencies:
'@nolyfill/is-core-module': 1.0.39
@@ -6997,7 +7001,7 @@ snapshots:
tinyglobby: 0.2.14
unrs-resolver: 1.9.0
optionalDependencies:
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
@@ -7012,7 +7016,7 @@ snapshots:
tinyglobby: 0.2.14
unrs-resolver: 1.9.0
optionalDependencies:
- eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)
+ eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
@@ -7037,14 +7041,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
+ eslint-module-utils@2.12.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.34.0(eslint@8.57.1)(typescript@5.9.2)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1)
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
@@ -7083,7 +7087,7 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
- eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
+ eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.2.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -7112,7 +7116,7 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
- eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
+ eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -7123,7 +7127,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.34.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -8692,7 +8696,7 @@ snapshots:
razorpay@2.9.6:
dependencies:
- axios: 1.12.2
+ axios: 1.13.2
transitivePeerDependencies:
- debug
@@ -9285,6 +9289,8 @@ snapshots:
toidentifier@1.0.1: {}
+ tr46@0.0.3: {}
+
ts-api-utils@1.4.3(typescript@5.9.2):
dependencies:
typescript: 5.9.2