{mainSections[index]}
{section.map((text, index) => (
@@ -57,19 +56,19 @@ export default function About() {
)
} else if (mainSections[index] === t('about.sections.contributions')) {
return (
-
+
{mainSections[index]}
{section.map((text, index) => (
- {text.split(/(ihatenodejs|p0ntus git|aidan)/).map((part, i) => {
+ {text.split(/(ihatenodejs|LibreCloud Git|aidan)/).map((part, i) => {
if (part === 'ihatenodejs') {
- return ihatenodejs
+ return GitHub
}
- if (part === 'p0ntus git') {
- return p0ntus git
+ if (part === 'LibreCloud Git') {
+ return LibreCloud Git
}
if (part === 'aidan') {
- return aidan
+ return aidan
}
return part
})}
@@ -77,19 +76,18 @@ export default function About() {
))}
{!imageError && (
- setImageError(true)}
loading="eager"
priority
unoptimized
- className="max-w-full h-auto"
/>
-
)}
@@ -105,54 +102,31 @@ export default function About() {
)
} else if (mainSections[index] === t('about.sections.devices')) {
return (
-
+
{mainSections[index]}
{Object.entries(section).map(([key, value], index) => (
-
{key}
+
{key}
{(value as unknown as string[]).map((text: string, index: number) => (
- {text.split(/(KernelSU-Next|LineageOS 22.2|Android 16|Xubuntu)/).map((part, i) => {
+ {text.split(/(KernelSU-Next|LineageOS microG)/).map((part, i) => {
if (part === 'KernelSU-Next') {
return KernelSU-Next
}
- if (part === 'LineageOS 22.2') {
- return LineageOS 22.2
- }
- if (part === 'Android 16') {
- return Android 16
- }
- if (part === 'OpenCore') {
- return OpenCore
- }
- if (part === 'Xubuntu') {
- return Xubuntu
+ if (part === 'LineageOS microG') {
+ return LineageOS microG
}
return part
})}
))}
- {key === "Mobile Devices" && (
-
- }
- >
- Pixel 9 Pro XL
-
- }
- >
- Pixel 7 Pro
-
- }
- >
- Pixel 3a XL
-
-
+ {key === "Phone" && (
+
)}
))}
@@ -160,22 +134,16 @@ export default function About() {
)
} else if (mainSections[index] === t('about.sections.hobbies')) {
return (
-
+
{mainSections[index]}
{section.map((text, index) => (
- {text.split(/(my Forgejo server|my phone|AfC|OnlyNano)/).map((part, i) => {
- if (part === 'my Forgejo server') {
- return my Forgejo server
+ {text.split(/(my Gitea instance|my phone)/).map((part, i) => {
+ if (part === 'my Gitea instance') {
+ return my Gitea instance
}
if (part === 'my phone') {
- return my phone
- }
- if (part === 'AfC') {
- return AfC
- }
- if (part === 'OnlyNano') {
- return OnlyNano
+ return my phone
}
return part
})}
@@ -185,25 +153,13 @@ export default function About() {
)
} else if (mainSections[index] === t('about.sections.projects')) {
return (
-
+
{mainSections[index]}
{section.map((text, index) => (
- {text.split(/(p0ntus|PontusHub|ABOCN|Kowalski|@KowalskiNodeBot)/).map((part, i) => {
- if (part === 'p0ntus') {
- return p0ntus
- }
- if (part === 'PontusHub') {
- return PontusHub
- }
- if (part === 'ABOCN') {
- return ABOCN
- }
- if (part === 'Kowalski') {
- return Kowalski
- }
- if (part === '@KowalskiNodeBot') {
- return @KowalskiNodeBot
+ {text.split(/(LibreCloud)/).map((part, i) => {
+ if (part === 'LibreCloud') {
+ return LibreCloud
}
return part
})}
@@ -213,7 +169,7 @@ export default function About() {
)
} else {
return (
-
+
{mainSections[index]}
{section.map((text, index) => (
diff --git a/app/ai/claude/components/Activity.tsx b/app/ai/claude/components/Activity.tsx
deleted file mode 100644
index 1838500..0000000
--- a/app/ai/claude/components/Activity.tsx
+++ /dev/null
@@ -1,172 +0,0 @@
-"use client"
-
-import { useMemo, useState } from 'react'
-import {
- AreaChart,
- Area,
- CartesianGrid,
- XAxis,
- YAxis,
- Tooltip,
- ResponsiveContainer,
-} from 'recharts'
-import { DailyData } from './types'
-import {
- buildDailyTrendData,
- formatCurrency,
- formatTokens,
- getHeatmapColor,
- prepareHeatmapData,
-} from './utils'
-
-export default function Activity({ daily }: { daily: DailyData[] }) {
- const [viewMode, setViewMode] = useState<'heatmap' | 'chart'>('heatmap')
- const [selectedMetric, setSelectedMetric] = useState<'cost' | 'tokens'>('cost')
-
- const dailyTrendData = useMemo(() => buildDailyTrendData(daily), [daily])
- const heatmapWeeks = useMemo(() => prepareHeatmapData(daily), [daily])
- const maxCost = useMemo(
- () => (daily.length ? Math.max(...daily.map(d => d.totalCost)) : 0),
- [daily]
- )
-
- return (
-
-
-
Activity
-
- {viewMode === 'heatmap' ? 'Heatmap' : 'Chart'}
- setViewMode(viewMode === 'heatmap' ? 'chart' : 'heatmap')}
- className="relative inline-flex h-6 w-11 items-center rounded-full bg-gray-700 transition-colors focus:outline-none focus:ring-2 focus:ring-[#c15f3c] focus:ring-offset-2 focus:ring-offset-gray-900"
- >
- Toggle view mode
-
-
-
-
- {viewMode === 'heatmap' ? (
-
-
-
-
-
- {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((day) => (
-
- {day}
-
- ))}
-
-
-
- {(() => {
- const monthLabels: { month: string; position: number }[] = []
- let lastMonth = -1
- heatmapWeeks.forEach((week, weekIndex) => {
- const firstDay = week.find(d => d !== null)
- if (firstDay) {
- const date = new Date(firstDay.date + 'T00:00:00Z')
- const month = date.getUTCMonth()
- if (month !== lastMonth) {
- monthLabels.push({
- month: date.toLocaleDateString('en-US', { month: 'short', timeZone: 'UTC' }),
- position: weekIndex * 20
- })
- lastMonth = month
- }
- }
- })
- return (
-
- {monthLabels.map((label, idx) => (
-
- {label.month}
-
- ))}
-
- )
- })()}
-
-
- {heatmapWeeks.map((week, weekIndex) => (
-
- {week.map((day, dayIndex) => (
-
-
- {day && (
-
-
-
{day.formattedDate}
-
Cost: ${day.cost.toFixed(2)}
-
Tokens: {(day.tokens / 1000000).toFixed(2)}M
-
-
- )}
-
- ))}
-
- ))}
-
-
-
-
-
-
- ) : (
- <>
-
- setSelectedMetric('cost')}
- className={`px-3 py-1 rounded ${selectedMetric === 'cost' ? 'bg-[#c15f3c] text-white' : 'bg-gray-700 text-gray-300'}`}
- >
- Cost
-
- setSelectedMetric('tokens')}
- className={`px-3 py-1 rounded ${selectedMetric === 'tokens' ? 'bg-[#c15f3c] text-white' : 'bg-gray-700 text-gray-300'}`}
- >
- Tokens
-
-
-
-
-
-
-
- selectedMetric === 'cost' ? formatCurrency(value) : formatTokens(value)}
- />
-
-
-
- >
- )}
-
- )
-}
-
diff --git a/app/ai/claude/components/LoadingSkeleton.tsx b/app/ai/claude/components/LoadingSkeleton.tsx
deleted file mode 100644
index 5b5bc01..0000000
--- a/app/ai/claude/components/LoadingSkeleton.tsx
+++ /dev/null
@@ -1,177 +0,0 @@
-"use client"
-
-import PageHeader from './PageHeader'
-
-export default function LoadingSkeleton() {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((day) => (
-
- {day}
-
- ))}
-
-
-
-
- {['Jan', 'Mar', 'May', 'Jul', 'Sep', 'Nov'].map((month) => (
-
- ))}
-
-
-
- {(() => {
- const today = new Date()
- const startOfYear = new Date(Date.UTC(today.getUTCFullYear(), 0, 1))
- const endDate = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()))
-
- const firstDay = startOfYear.getUTCDay()
- const startDate = new Date(startOfYear)
- startDate.setUTCDate(startDate.getUTCDate() - firstDay)
-
- const msPerWeek = 7 * 24 * 60 * 60 * 1000
- const weekCount = Math.ceil((endDate.getTime() - startDate.getTime()) / msPerWeek)
-
- return [...Array(weekCount)].map((_, weekIndex) => (
-
- {[...Array(7)].map((_, dayIndex) => (
-
- ))}
-
- ))
- })()}
-
-
-
-
-
Less
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
-
More
-
-
-
-
-
-
-
-
- Model Usage Distribution
-
-
-
- {[...Array(3)].map((_, i) => (
-
- ))}
-
-
-
-
-
- Token Type Breakdown
-
-
-
-
-
-
-
- Recent Sessions
-
-
-
-
- Date
- Models Used
- Total Tokens
- Cost
-
-
-
- {[...Array(5)].map((_, index) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ))}
-
-
-
-
-
-
- )
-}
-
diff --git a/app/ai/claude/components/ModelUsageCard.tsx b/app/ai/claude/components/ModelUsageCard.tsx
deleted file mode 100644
index 92518d4..0000000
--- a/app/ai/claude/components/ModelUsageCard.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-"use client"
-
-import { ResponsiveContainer, PieChart, Pie, Cell, Tooltip } from 'recharts'
-import { DailyData } from './types'
-import { COLORS, buildModelUsageData, formatCurrency } from './utils'
-
-export default function ModelUsageCard({ daily, totalCost }: { daily: DailyData[]; totalCost: number }) {
- const modelUsageData = buildModelUsageData(daily)
- return (
-
- Model Usage Distribution
-
-
-
-
- {modelUsageData.map((_entry, index) => (
- |
- ))}
-
- formatCurrency(value)}
- labelStyle={{ color: '#fff' }}
- itemStyle={{ color: '#fff' }}
- />
-
-
-
- {modelUsageData.map((model, index) => {
- const percentage = ((model.value / Math.max(totalCost, 1)) * 100).toFixed(1)
- return (
-
-
-
- {percentage}%
- ${model.value.toFixed(2)}
-
-
- )
- })}
-
-
- Total Models Used
- {modelUsageData.length}
-
-
- Most Used
-
- {modelUsageData[0]?.name}
-
-
-
-
-
-
- )
-}
-
diff --git a/app/ai/claude/components/PageHeader.tsx b/app/ai/claude/components/PageHeader.tsx
deleted file mode 100644
index 8b94c94..0000000
--- a/app/ai/claude/components/PageHeader.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-"use client"
-
-import Link from 'next/link'
-import { SiClaude } from 'react-icons/si'
-
-export default function PageHeader() {
- return (
- <>
-
- ← Back to AI
-
-
-
-
-
-
-
Claude Code Usage
-
How much I use Claude Code!
-
- >
- )
-}
-
diff --git a/app/ai/claude/components/RecentSessions.tsx b/app/ai/claude/components/RecentSessions.tsx
deleted file mode 100644
index cc0d991..0000000
--- a/app/ai/claude/components/RecentSessions.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-"use client"
-
-import { DailyData } from './types'
-import { getModelLabel } from './utils'
-
-export default function RecentSessions({ daily }: { daily: DailyData[] }) {
- return (
-
- Recent Sessions
-
-
-
-
- Date
- Models Used
- Total Tokens
- Cost
-
-
-
- {daily.slice(-5).reverse().map((day, index) => (
-
- {new Date(day.date + 'T00:00:00').toLocaleDateString()}
-
- {day.modelsUsed.map(getModelLabel).join(', ')}
-
- {(day.totalTokens / 1000000).toFixed(2)}M
- ${day.totalCost.toFixed(2)}
-
- ))}
-
-
-
-
- )
-}
-
diff --git a/app/ai/claude/components/StatsGrid.tsx b/app/ai/claude/components/StatsGrid.tsx
deleted file mode 100644
index 2ff4298..0000000
--- a/app/ai/claude/components/StatsGrid.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-"use client"
-
-import { CCData, DailyData } from './types'
-import { formatStreakCompact, computeStreak } from './utils'
-
-export default function StatsGrid({ totals, daily }: { totals: CCData['totals']; daily: DailyData[] }) {
- const streak = computeStreak(daily)
- return (
-
-
-
Total Cost
-
${totals.totalCost.toFixed(2)}
-
-
-
Total Tokens
-
{(totals.totalTokens / 1000000).toFixed(1)}M
-
-
-
Days Active
-
- {daily.length}
-
- 🔥 {formatStreakCompact(streak)}
-
-
-
-
-
Avg Daily Cost
-
${(totals.totalCost / Math.max(daily.length, 1)).toFixed(2)}
-
-
- )
-}
-
diff --git a/app/ai/claude/components/TokenComposition.tsx b/app/ai/claude/components/TokenComposition.tsx
deleted file mode 100644
index d3569f0..0000000
--- a/app/ai/claude/components/TokenComposition.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-"use client"
-
-import { ResponsiveContainer, ComposedChart, CartesianGrid, XAxis, YAxis, Tooltip, Legend, Bar, Line } from 'recharts'
-import { DailyData } from './types'
-import { buildDailyTrendData } from './utils'
-
-export default function TokenComposition({ daily }: { daily: DailyData[] }) {
- const dailyTrendData = buildDailyTrendData(daily)
- return (
-
- Token Composition
-
-
-
-
- `${value}K`} />
- `${value.toFixed(1)}K tokens`}
- />
-
-
-
-
-
-
-
- )
-}
-
diff --git a/app/ai/claude/components/TokenTypeBreakdown.tsx b/app/ai/claude/components/TokenTypeBreakdown.tsx
deleted file mode 100644
index c8625d8..0000000
--- a/app/ai/claude/components/TokenTypeBreakdown.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-"use client"
-
-import { ResponsiveContainer, BarChart, CartesianGrid, XAxis, YAxis, Tooltip, Bar } from 'recharts'
-import { CCData } from './types'
-import { buildTokenTypeData } from './utils'
-
-export default function TokenTypeBreakdown({ totals }: { totals: CCData['totals'] }) {
- const tokenTypeData = buildTokenTypeData(totals)
- return (
-
- Token Type Breakdown
-
-
-
-
- `${(value / 1000000).toFixed(0)}M`} />
- `${(value / 1000000).toFixed(2)}M tokens`}
- />
-
-
-
-
- )
-}
-
diff --git a/app/ai/claude/components/types.ts b/app/ai/claude/components/types.ts
deleted file mode 100644
index 7000dca..0000000
--- a/app/ai/claude/components/types.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-export interface ModelBreakdown {
- modelName: string
- inputTokens: number
- outputTokens: number
- cacheCreationTokens: number
- cacheReadTokens: number
- cost: number
-}
-
-export interface DailyData {
- date: string
- inputTokens: number
- outputTokens: number
- cacheCreationTokens: number
- cacheReadTokens: number
- totalTokens: number
- totalCost: number
- modelsUsed: string[]
- modelBreakdowns: ModelBreakdown[]
-}
-
-export interface CCData {
- daily: DailyData[]
- totals: {
- inputTokens: number
- outputTokens: number
- cacheCreationTokens: number
- cacheReadTokens: number
- totalCost: number
- totalTokens: number
- }
-}
-
-export interface HeatmapDay {
- date: string
- value: number
- tokens: number
- cost: number
- day: number
- formattedDate: string
-}
-
diff --git a/app/ai/claude/components/utils.ts b/app/ai/claude/components/utils.ts
deleted file mode 100644
index d8d706e..0000000
--- a/app/ai/claude/components/utils.ts
+++ /dev/null
@@ -1,191 +0,0 @@
-import { CCData, DailyData, HeatmapDay } from './types'
-
-export const COLORS = ['#c15f3c', '#b1ada1', '#f4f3ee', '#c15f3c', '#b1ada1', '#f4f3ee']
-
-export const MODEL_LABELS: Record = {
- 'claude-sonnet-4-20250514': 'Sonnet 4',
- 'claude-opus-4-1-20250805': 'Opus 4.1',
-}
-
-export const getModelLabel = (modelName: string): string => {
- return MODEL_LABELS[modelName] || modelName
-}
-
-export const formatCurrency = (value: number) => `$${value.toFixed(2)}`
-export const formatTokens = (value: number) => `${value.toFixed(1)}M`
-
-export const computeStreak = (daily: DailyData[]): number => {
- if (!daily.length) return 0
- const datesSet = new Set(daily.map(d => d.date))
- const latest = daily
- .map(d => new Date(d.date + 'T00:00:00Z'))
- .reduce((a, b) => (a > b ? a : b))
-
- const toKey = (d: Date) => {
- const y = d.getUTCFullYear()
- const m = (d.getUTCMonth() + 1).toString().padStart(2, '0')
- const day = d.getUTCDate().toString().padStart(2, '0')
- return `${y}-${m}-${day}`
- }
-
- let count = 0
- for (
- let d = new Date(latest.getTime());
- ;
- d = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() - 1))
- ) {
- const key = toKey(d)
- if (datesSet.has(key)) count++
- else break
- }
- return count
-}
-
-export const formatStreakCompact = (days: number) => {
- if (days >= 365) return `${Math.floor(days / 365)}y`
- if (days >= 30) return `${Math.floor(days / 30)}mo`
- if (days >= 7) return `${Math.floor(days / 7)}w`
- return `${days}d`
-}
-
-export const computeFilledDailyRange = (daily: DailyData[]): DailyData[] => {
- if (!daily.length) return []
-
- const dates = daily.map(d => new Date(d.date + 'T00:00:00Z'))
- const start = dates.reduce((a, b) => (a < b ? a : b))
- const end = dates.reduce((a, b) => (a > b ? a : b))
-
- const byDate = new Map(
- daily.map(d => [d.date, d] as const)
- )
-
- const result: DailyData[] = []
- for (
- let d = new Date(start.getTime());
- d <= end;
- d = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() + 1))
- ) {
- const y = d.getUTCFullYear()
- const m = (d.getUTCMonth() + 1).toString().padStart(2, '0')
- const day = d.getUTCDate().toString().padStart(2, '0')
- const key = `${y}-${m}-${day}`
-
- if (byDate.has(key)) {
- result.push(byDate.get(key)!)
- } else {
- result.push({
- date: key,
- inputTokens: 0,
- outputTokens: 0,
- cacheCreationTokens: 0,
- cacheReadTokens: 0,
- totalTokens: 0,
- totalCost: 0,
- modelsUsed: [],
- modelBreakdowns: [],
- })
- }
- }
- return result
-}
-
-export const buildDailyTrendData = (daily: DailyData[]) => {
- const filled = computeFilledDailyRange(daily)
- return filled.map(day => ({
- date: new Date(day.date + 'T00:00:00').toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
- cost: day.totalCost,
- tokens: day.totalTokens / 1000000,
- inputTokens: day.inputTokens / 1000,
- outputTokens: day.outputTokens / 1000,
- cacheTokens: (day.cacheCreationTokens + day.cacheReadTokens) / 1000000,
- }))
-}
-
-export const prepareHeatmapData = (daily: DailyData[]): (HeatmapDay | null)[][] => {
- const dayMap = new Map()
- daily.forEach(day => {
- dayMap.set(day.date, day)
- })
-
- const today = new Date()
- const startOfYear = new Date(Date.UTC(today.getUTCFullYear(), 0, 1))
- const endDate = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()))
-
- const weeks: (HeatmapDay | null)[][] = []
- let currentWeek: (HeatmapDay | null)[] = []
-
- const firstDay = startOfYear.getUTCDay()
- const startDate = new Date(startOfYear)
- startDate.setUTCDate(startDate.getUTCDate() - firstDay)
-
- for (
- let d = new Date(startDate);
- d <= endDate;
- d = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate() + 1))
- ) {
- if (d < startOfYear) {
- currentWeek.push(null)
- if (d.getUTCDay() === 6) {
- weeks.push(currentWeek)
- currentWeek = []
- }
- continue
- }
- const dateStr = `${d.getUTCFullYear()}-${(d.getUTCMonth() + 1).toString().padStart(2, '0')}-${d.getUTCDate().toString().padStart(2, '0')}`
- const dayData = dayMap.get(dateStr)
-
- currentWeek.push({
- date: dateStr,
- value: dayData ? dayData.totalCost : 0,
- tokens: dayData ? dayData.totalTokens : 0,
- cost: dayData ? dayData.totalCost : 0,
- day: d.getUTCDay(),
- formattedDate: d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' })
- })
-
- if (d.getUTCDay() === 6 || d.getTime() === endDate.getTime()) {
- while (currentWeek.length < 7) {
- currentWeek.push(null)
- }
- weeks.push(currentWeek)
- currentWeek = []
- }
- }
-
- return weeks
-}
-
-export const getHeatmapColor = (maxCost: number, value: number) => {
- if (value === 0) return '#1f2937'
- const denominator = maxCost === 0 ? 1 : maxCost
- const intensity = value / denominator
-
- if (intensity < 0.25) return '#4a3328'
- if (intensity < 0.5) return '#6b4530'
- if (intensity < 0.75) return '#8d5738'
- return '#c15f3c'
-}
-
-export const buildModelUsageData = (daily: DailyData[]) => {
- const raw = daily.reduce((acc, day) => {
- day.modelBreakdowns.forEach(model => {
- const label = getModelLabel(model.modelName)
- const existing = acc.find(m => m.name === label)
- if (existing) {
- existing.value += model.cost
- } else {
- acc.push({ name: label, value: model.cost })
- }
- })
- return acc
- }, [] as { name: string; value: number }[])
- return raw.sort((a, b) => b.value - a.value)
-}
-
-export const buildTokenTypeData = (totals: CCData['totals']) => ([
- { name: 'Input', value: totals.inputTokens },
- { name: 'Output', value: totals.outputTokens },
- { name: 'Cache Creation', value: totals.cacheCreationTokens },
- { name: 'Cache Read', value: totals.cacheReadTokens },
-])
-
diff --git a/app/ai/claude/page.tsx b/app/ai/claude/page.tsx
deleted file mode 100644
index db934a8..0000000
--- a/app/ai/claude/page.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-"use client"
-
-import Header from '@/components/Header'
-import Footer from '@/components/Footer'
-import { useEffect, useState } from 'react'
-import LoadingSkeleton from './components/LoadingSkeleton'
-import PageHeader from './components/PageHeader'
-import StatsGrid from './components/StatsGrid'
-import Activity from './components/Activity'
-import ModelUsageCard from './components/ModelUsageCard'
-import TokenTypeBreakdown from './components/TokenTypeBreakdown'
-import TokenComposition from './components/TokenComposition'
-import RecentSessions from './components/RecentSessions'
-import { CCData } from './components/types'
-
-export default function AI() {
- const [data, setData] = useState(null)
- const [loading, setLoading] = useState(true)
- const [error, setError] = useState(null)
-
- useEffect(() => {
- fetch('/data/cc.json')
- .then(res => {
- if (!res.ok) throw new Error('Failed to fetch data')
- return res.json()
- })
- .then(data => {
- setData(data)
- setLoading(false)
- })
- .catch(err => {
- setError(err.message)
- setLoading(false)
- })
- }, [])
-
- if (loading) {
- return (
-
-
-
-
-
- )
- }
-
- if (error || !data) {
- return (
-
-
-
- Error loading data: {error}
-
-
-
- )
- }
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
diff --git a/app/ai/components/AIStack.tsx b/app/ai/components/AIStack.tsx
deleted file mode 100644
index 2abaf6b..0000000
--- a/app/ai/components/AIStack.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import { TbStack2 } from 'react-icons/tb'
-import Link from '@/components/objects/Link'
-import type { AITool } from '../types'
-
-interface AIStackProps {
- tools: AITool[]
-}
-
-export default function AIStack({ tools }: AIStackProps) {
- const getStatusColor = (status: string) => {
- switch (status) {
- case 'primary': return 'text-green-400 border-green-400 bg-green-400/10'
- case 'active': return 'text-green-300 border-green-300 bg-green-300/10'
- case 'occasional': return 'text-orange-300 border-orange-300 bg-orange-300/10'
- default: return 'text-gray-400 border-gray-400'
- }
- }
-
- const getStatusLabel = (status: string) => {
- switch (status) {
- case 'primary': return 'Primary'
- case 'active': return 'Active Use'
- case 'occasional': return 'Occasional Use'
- default: return status
- }
- }
-
- const formatPrice = (price: number) => {
- if (price === 0) return 'Free'
- if (price % 1 === 0) return `$${price}/mo`
- return `$${price.toFixed(2)}/mo`
- }
-
- return (
-
-
-
-
- My AI Stack
-
-
The AI tools I use as a part of my routine and workflow.
-
-
- {tools.map((tool, index) => (
-
-
-
- {tool.icon &&
}
- {tool.svg && (
-
- {tool.svg}
-
- )}
-
-
-
{tool.name}
- {tool.price !== undefined && (
-
- {tool.discountedPrice !== undefined ? (
- <>
-
- {formatPrice(tool.price)}
-
-
- {formatPrice(tool.discountedPrice)}
-
- >
- ) : (
-
- {formatPrice(tool.price)}
-
- )}
-
- )}
-
-
{tool.description}
-
-
-
-
-
- {getStatusLabel(tool.status)}
-
-
- {tool.link && (
-
- Visit →
-
- )}
- {tool.usage && (
-
- Usage →
-
- )}
-
-
-
- ))}
-
-
- )
-}
diff --git a/app/ai/components/FavoriteModels.tsx b/app/ai/components/FavoriteModels.tsx
deleted file mode 100644
index f5b812f..0000000
--- a/app/ai/components/FavoriteModels.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { Brain, Star } from 'lucide-react'
-import type { FavoriteModel } from '../types'
-
-interface FavoriteModelsProps {
- models: FavoriteModel[]
-}
-
-export default function FavoriteModels({ models }: FavoriteModelsProps) {
- return (
-
-
-
-
- Favorite Models
-
-
Based on personal preference
-
-
- {models.map((model, index) => (
-
-
-
-
{model.name}
-
{model.provider}
-
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
-
-
{model.review}
-
- ))}
-
-
- )
-}
diff --git a/app/ai/components/FavoriteTools.tsx b/app/ai/components/FavoriteTools.tsx
deleted file mode 100644
index d04fe03..0000000
--- a/app/ai/components/FavoriteTools.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { Star } from 'lucide-react'
-import { TbTool } from 'react-icons/tb'
-import type { AIReview } from '../types'
-
-interface FavoriteToolsProps {
- reviews: AIReview[]
-}
-
-export default function FavoriteTools({ reviews }: FavoriteToolsProps) {
- return (
-
-
-
-
- Favorite Tools
-
-
Based on personal preference
-
-
- {reviews.map((review, index) => (
-
-
-
{review.tool}
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
-
-
-
-
Pros:
-
- {review.pros.map((pro, i) => (
- • {pro}
- ))}
-
-
-
-
Cons:
-
- {review.cons.map((con, i) => (
- • {con}
- ))}
-
-
-
-
{review.verdict}
-
- ))}
-
-
- )
-}
diff --git a/app/ai/components/TopPick.tsx b/app/ai/components/TopPick.tsx
deleted file mode 100644
index b58daa7..0000000
--- a/app/ai/components/TopPick.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { Trophy, ChevronRight } from 'lucide-react'
-import { SiClaude } from 'react-icons/si'
-import Link from '@/components/objects/Link'
-
-export default function TopPick() {
- return (
-
-
-
- Top Pick of 2025
-
-
-
-
-
-
-
Claude
-
by Anthropic
-
-
- Visit
-
-
- My Usage
-
-
-
-
-
-
- Claude has become my go-to AI assistant for coding, writing, and learning very quickly.
- I believe their Max 5x ($100/mo) is the best value for budget-conscious consumers like myself.
-
-
-
- Top-Tier Tool Calling
- High-Value Plans
- Good Speed
-
-
-
-
-
-
- )
-}
diff --git a/app/ai/data.tsx b/app/ai/data.tsx
deleted file mode 100644
index 3c457ca..0000000
--- a/app/ai/data.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-import {
- SiClaude,
- SiGithubcopilot,
- SiGooglegemini,
- SiPerplexity,
- SiOpenai
-} from 'react-icons/si'
-import type { AITool, FavoriteModel, AIReview } from './types'
-
-export const aiTools: AITool[] = [
- {
- name: "Claude Max 5x",
- icon: SiClaude,
- description: "My favorite model provider for general use and coding",
- status: "primary",
- usage: "/ai/claude",
- link: "https://claude.ai/",
- price: 100
- },
- {
- name: "ChatGPT Business",
- icon: SiOpenai,
- description: "Feature-rich and budget-friendly (for now)",
- status: "active",
- link: "https://chatgpt.com/",
- price: 60
- },
- {
- name: "GLM Coding Lite",
- svg: (
- /* Icon by lobe-icons: https://github.com/lobehub/lobe-icons */
-
- Z.ai
-
-
- ),
- description: "Cheap, Claude-like model with a slow API",
- status: "active",
- link: "https://z.ai/",
- price: 3
- },
- {
- name: "Gemini Pro",
- icon: SiGooglegemini,
- description: "Chatting, asking questions, and image generation",
- status: "occasional",
- link: "https://gemini.google.com/",
- price: 20,
- discountedPrice: 0
- },
- {
- name: "Qwen Chat",
- svg: (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ),
- description: "My favorite open source LLM for chatting",
- status: "occasional",
- link: "https://chat.qwen.ai/",
- price: 0
- },
- {
- name: "Perplexity Pro",
- icon: SiPerplexity,
- description: "Reliable for more in-depth searching",
- status: "occasional",
- link: "https://perplexity.ai/",
- price: 20,
- discountedPrice: 0
- },
- {
- name: "OpenCode",
- svg: (
-
-
-
-
-
-
-
-
-
-
-
-
- ),
- description: "My favorite FOSS AI coding assistant",
- status: "occasional",
- link: "https://opencode.ai/",
- price: 0
- },
- {
- name: "GitHub Copilot Pro",
- icon: SiGithubcopilot,
- description: "Random edits when I don't want to start a Claude session",
- status: "occasional",
- link: "https://github.com/features/copilot",
- price: 10,
- discountedPrice: 0
- },
- {
- name: "v0 Free",
- svg: v0 ,
- description: "Generating boilerplate UIs",
- status: "occasional",
- link: "https://v0.dev/",
- price: 0
- },
-]
-
-export const favoriteModels: FavoriteModel[] = [
- {
- name: "Claude 4 Sonnet",
- provider: "Anthropic",
- review: "The perfect balance of capability, speed, and price. Perfect for development with React.",
- rating: 5
- },
- {
- name: "Claude 4.1 Opus",
- provider: "Anthropic",
- review: "Amazing planner, useful for Plan Mode in Claude Code. Useful in code generation, albeit at a higher cost.",
- rating: 5
- },
- {
- name: "Qwen3-235B-A22B",
- provider: "Alibaba",
- review: "The OG thinking model. Amazing, funny, and smart for chats. Surprisingly good at coding too.",
- rating: 5
- },
- {
- name: "GPT-5",
- provider: "OpenAI",
- review: "A model I am still testing with. Seems to be good with coding and following instructions so far, but not with the same flair as Claude.",
- rating: 4
- },
- {
- name: "Qwen3-Max-Preview",
- provider: "Alibaba",
- review: "A new personality for Qwen3 at a larger size, amazing for use in chats. I'm not so happy that it's closed source (for now).",
- rating: 4
- },
- {
- name: "Gemini 2.5 Pro",
- provider: "Google",
- review: "Amazing for Deep Research and reasoning tasks. I hate it for coding.",
- rating: 4
- },
- {
- name: "gemma3 27B",
- provider: "Google",
- review: "My favorite for playing around with AI or creating a project. Easy to run locally and open weight!",
- rating: 4
- },
-]
-
-export const aiReviews: AIReview[] = [
- {
- tool: "Claude Code",
- rating: 5,
- pros: ["Flagship models", "High usage limits", "Exceptional Claude integration"],
- cons: ["API interface be slow at times", "High investment cost to get full value"],
- verdict: "Best overall for Claude lovers"
- },
- {
- tool: "Cursor",
- rating: 4,
- pros: ["Works like magic", "Lots of model support", "Huge ecosystem and community"],
- cons: ["Expensive", "Hype around it is dying", "Unclear/manipulative pricing"],
- verdict: "Great all-rounder, slowly dying"
- },
- {
- tool: "Trae",
- rating: 4,
- pros: ["Good UI/UX", "Very budget-friendly", "Fantastic premium usage limits"],
- cons: ["No thinking", "Occasional parsing issues"],
- verdict: "Budget-friendly productivity boost"
- },
- {
- tool: "GitHub Copilot",
- rating: 3,
- pros: ["Latest models", "Great autocomplete", "Budget-friendly subscription price"],
- cons: ["No thinking", "Low quality output", "Bad support for other IDEs"],
- verdict: "Good for casual use"
- },
-]
diff --git a/app/ai/page.tsx b/app/ai/page.tsx
deleted file mode 100644
index ef9a604..0000000
--- a/app/ai/page.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-"use client"
-
-import Header from '@/components/Header'
-import Footer from '@/components/Footer'
-import { Brain } from 'lucide-react'
-import TopPick from './components/TopPick'
-import AIStack from './components/AIStack'
-import FavoriteModels from './components/FavoriteModels'
-import FavoriteTools from './components/FavoriteTools'
-import { aiTools, favoriteModels, aiReviews } from './data'
-
-export default function AI() {
- return (
-
-
-
-
-
-
-
-
AI
-
My journey with using LLMs
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
\ No newline at end of file
diff --git a/app/ai/types.ts b/app/ai/types.ts
deleted file mode 100644
index 5bf7aae..0000000
--- a/app/ai/types.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-export interface AITool {
- name: string;
- icon?: React.ElementType;
- svg?: React.ReactNode;
- description: string;
- status: 'primary' | 'active' | 'occasional' | string;
- link?: string;
- usage?: string;
- price?: number;
- discountedPrice?: number;
-}
-
-export interface FavoriteModel {
- name: string;
- provider: string;
- review: string;
- rating: number;
-}
-
-export interface AIReview {
- tool: string;
- rating: number;
- pros: string[];
- cons: string[];
- verdict: string;
-}
\ No newline at end of file
diff --git a/app/contact/page.tsx b/app/contact/page.tsx
index ee209ba..0edfd2f 100644
--- a/app/contact/page.tsx
+++ b/app/contact/page.tsx
@@ -2,11 +2,11 @@
import Header from '@/components/Header'
import Footer from '@/components/Footer'
-import Button from '@/components/objects/Button'
+import ContactButton from '@/components/objects/ContactButton'
import { Phone } from 'lucide-react'
import { useTranslation } from 'react-i18next'
-import { SiGithub, SiForgejo, SiTelegram } from 'react-icons/si'
-import { Mail, Smartphone } from 'lucide-react'
+import { faPhone, faEnvelope } from '@fortawesome/free-solid-svg-icons'
+import { faGithub, faTelegram, faBluesky, faXTwitter } from '@fortawesome/free-brands-svg-icons'
export default function Contact() {
const { t } = useTranslation();
@@ -23,65 +23,56 @@ export default function Contact() {
];
const contactButtonLabels = [
- "ihatenodejs",
- "aidan",
- "p0ntu5",
- "+1 802-416-9516",
- "aidan@p0ntus.com",
+ t('contact.buttons.github'),
+ t('contact.buttons.telegram'),
+ t('contact.buttons.bluesky'),
+ t('contact.buttons.x'),
+ t('contact.buttons.phone'),
+ t('contact.buttons.email')
];
const contactButtonHrefs = [
"https://github.com/ihatenodejs",
- "https://git.p0ntus.com/aidan",
"https://t.me/p0ntu5",
+ "https://bsky.app/profile/aidxn.cc",
+ "https://x.com/ihatenodejs",
"tel:+18024169516",
"mailto:aidan@p0ntus.com"
];
- const contactButtonIcons = [
- ,
- ,
- ,
- ,
-
- ];
+ const contactButtonIcons = [faGithub, faTelegram, faBluesky, faXTwitter, faPhone, faEnvelope];
return (
-
-
-
- {t('contact.title')}
-
+
-
-
- {contactButtonLabels.map((label, index) => (
-
- {label}
-
- ))}
-
- {sections.map((section, sectionIndex) => (
-
-
{section.title}
- {section.texts.map((text, index) => (
-
{text}
- ))}
-
+
+ {t('contact.title')}
+
+
+ {contactButtonLabels.map((label, index) => (
+
))}
+
+ {sections.map((section, sectionIndex) => (
+
+
{section.title}
+ {section.texts.map((text, index) => (
+
{text}
+ ))}
+
+ ))}
diff --git a/app/device/bonito/page.tsx b/app/device/bonito/page.tsx
deleted file mode 100644
index 2ba4125..0000000
--- a/app/device/bonito/page.tsx
+++ /dev/null
@@ -1,199 +0,0 @@
-import Header from "@/components/Header"
-import Footer from "@/components/Footer"
-import {
- Cpu,
- MemoryStick,
- HardDrive,
- Hash,
- Music,
-} from "lucide-react"
-import { FaGoogle } from "react-icons/fa"
-import { VscTerminalLinux } from "react-icons/vsc"
-import { MdOutlineAndroid } from "react-icons/md"
-import { LuPackageOpen } from "react-icons/lu"
-import { RiTelegram2Fill } from "react-icons/ri"
-import Image from "next/image"
-import Link from "@/components/objects/Link"
-
-export default function Bonito() {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- Pixel 3a XL
-
- bonito
-
-
-
-
-
-
- Specs
-
-
-
-
- Chipset: Qualcomm Snapdragon 670
-
-
-
- Storage: 64GB
-
-
-
- RAM: 4GB
-
-
-
-
-
-
- Modifications
-
-
-
-
- Kernel Version:
- 4.9.337
-
-
-
- ROM:
-
- Ubuntu Touch
-
-
- {/*
-
- Root:
-
- Magisk
-
- N/A
-
*/}
-
-
-
-
-
-
-
- Apps
-
-
-
-
- Music:
-
- uSonic
-
-
- {/*
-
- Files:
-
- MiXplorer Beta
-
- N/A
-
*/}
-
-
- Telegram Client:
-
- TELEports
-
-
- {/*
-
- YouTube:
-
- Tubular
-
-
*/}
-
-
- {/*
-
-
- Modules
-
-
-
-
- bindhosts
-
-
-
-
- Magisk iOS Emoji
-
-
-
-
*/}
-
-
-
-
-
-
-
-
- )
-}
-
diff --git a/app/device/cheetah/page.tsx b/app/device/cheetah/page.tsx
deleted file mode 100644
index 40600a4..0000000
--- a/app/device/cheetah/page.tsx
+++ /dev/null
@@ -1,249 +0,0 @@
-import Header from "@/components/Header"
-import Footer from "@/components/Footer"
-import {
- Cpu,
- MemoryStick,
- HardDrive,
- Hash,
- Hammer,
- Music,
- Folder,
- Layers,
- SquarePen
-} from "lucide-react"
-import { FaGoogle, FaYoutube } from "react-icons/fa"
-import { VscTerminalLinux } from "react-icons/vsc"
-import { MdOutlineAndroid } from "react-icons/md"
-import { LuPackageOpen } from "react-icons/lu"
-import { RiTelegram2Fill } from "react-icons/ri"
-import Image from "next/image"
-import Link from "@/components/objects/Link"
-import { FaStarHalfStroke, FaStar } from "react-icons/fa6"
-
-export default function Cheetah() {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- Pixel 7 Pro
-
- cheetah
-
-
-
-
-
-
- Specs
-
-
-
-
- CPU: Google Tensor G2
-
-
-
- Storage: 128GB
-
-
-
- RAM: 12GB
-
-
-
-
-
-
- Modifications
-
-
-
-
- Kernel:
- 6.1.99-android14
-
-
-
- ROM:
-
- crDroid Android 11.6
-
-
-
-
- Root:
-
- KernelSU-Next
-
-
-
-
-
-
-
-
-
- Apps
-
-
-
-
- Music:
-
- Tidal
-
-
-
-
- Files:
-
- MiXplorer
-
-
-
-
- TG Client:
-
- AyuGram
-
-
-
-
- YouTube:
-
- ReVanced
-
-
-
-
-
-
-
- Modules
-
-
-
-
- bindhosts
-
-
-
-
- Emoji Replacer
-
-
-
-
- ReZygisk
-
-
-
-
- LSPosed JingMatrix
-
-
-
-
-
-
-
-
-
- Review
-
-
-
- Rating:
-
-
-
-
-
-
- Coming from a Galaxy A32 5G, the Pixel 7 Pro is a massive upgrade. The Tensor chip is highly performant, and with 12GB of RAM, the device is extremely snappy.
-
-
- I have had some issues with battery, although this may be due to Play Integrity Fix, which is known to consume battery. However, the camera has been a massive improvement, and the photos it is capable of taking are amazing.
-
-
- While the volume buttons did fall off, I do not discredit them for this, as Android makes it easy to have customizable on-screen volume buttons, something iPhones do not have.
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
diff --git a/app/device/komodo/page.tsx b/app/device/komodo/page.tsx
deleted file mode 100644
index b512b2b..0000000
--- a/app/device/komodo/page.tsx
+++ /dev/null
@@ -1,247 +0,0 @@
-import Header from "@/components/Header"
-import Footer from "@/components/Footer"
-import {
- Cpu,
- MemoryStick,
- HardDrive,
- Hash,
- Hammer,
- Music,
- Folder,
- Layers,
-} from "lucide-react"
-import { FaGoogle, FaYoutube } from "react-icons/fa"
-import { VscTerminalLinux } from "react-icons/vsc"
-import { MdOutlineAndroid } from "react-icons/md"
-import { LuPackageOpen } from "react-icons/lu"
-import { RiTelegram2Fill } from "react-icons/ri"
-import Image from "next/image"
-import Link from "@/components/objects/Link"
-
-export default function Cheetah() {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- Pixel 9 Pro XL
-
- komodo
-
-
-
-
-
-
- Specs
-
-
-
-
- CPU: Google Tensor G4
-
-
-
- Storage: 128GB
-
-
-
- RAM: 16GB
-
-
-
-
-
-
- Modifications
-
-
-
-
- Kernel:
-
- 6.1.138-android14-SUSFS-Wild
-
-
-
-
- ROM:
-
- Android 16 Beta QPR2
-
-
-
-
- Root:
-
- KernelSU-Next
-
-
-
-
-
-
-
-
-
- Apps
-
-
-
-
- Music:
-
- Tidal
-
-
-
-
- Files:
-
- MiXplorer
-
-
-
-
- TG Client:
-
- AyuGram
-
-
-
-
- YouTube:
-
- ReVanced
-
-
-
-
-
-
-
- Modules
-
-
-
-
- bindhosts
-
-
-
-
- Emoji Replacer
-
-
-
-
- F-Droid Privileged Extension
-
-
-
-
- SUSFS-FOR-KERNELSU
-
-
-
-
- Tricky Store
-
-
-
-
- Yuri Keybox Manager
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
diff --git a/app/domains/page.tsx b/app/domains/page.tsx
index 185c65c..63bb165 100644
--- a/app/domains/page.tsx
+++ b/app/domains/page.tsx
@@ -1,7 +1,8 @@
import Header from '@/components/Header'
import Footer from '@/components/Footer'
import { Link } from "lucide-react"
-import { TbCurrencyDollarOff } from "react-icons/tb";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
+import { faBan } from "@fortawesome/free-solid-svg-icons"
import domains from "@/public/data/domains.json"
export default function Domains() {
@@ -10,16 +11,17 @@ export default function Domains() {
-
-
-
-
-
- My Domains
-
+
+
+
+ My Domains
+
-
+
These domains are not for sale.
diff --git a/app/globals.css b/app/globals.css
index 9b1c661..e05ccc7 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -66,13 +66,8 @@ html {
}
}
-.hover\:glow {
- transition: text-shadow 0.3s ease;
- text-shadow: 0 0 0px rgba(255, 255, 255, 0);
-}
-
.hover\:glow:hover {
- text-shadow: 0 0 15px rgba(255, 255, 255, 0.9);
+ animation: pulse-glow 2s infinite;
}
.sub {
diff --git a/app/layout.tsx b/app/layout.tsx
index 758a424..a682861 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,71 +1,74 @@
-import React from 'react'
-import { Metadata, Viewport } from 'next'
+"use client"
+
+import React, { useEffect } from 'react'
import './globals.css'
+import '@fortawesome/fontawesome-svg-core/styles.css'
+import { config } from '@fortawesome/fontawesome-svg-core'
import { GeistSans } from 'geist/font/sans'
-import AnimatedTitle from '../components/AnimatedTitle'
-import I18nProvider from '../components/I18nProvider'
+import '../i18n'
-export const metadata: Metadata = {
- title: 'aidxn.cc',
- description: "The Internet home of Aidan. Come on in!",
- authors: [{ name: 'aidxn.cc' }],
- robots: 'index, follow',
- metadataBase: new URL('https://aidxn.cc'),
- openGraph: {
- type: "website",
- url: "https://aidxn.cc",
- title: "aidxn.cc",
- description: "The Internet home of Aidan. Come on in!",
- siteName: "aidxn.cc",
- images: [
- {
- url: "https://aidxn.cc/android-icon-192x192.png",
- width: 192,
- height: 192,
- },
- ],
- },
- icons: {
- icon: [
- { url: '/favicon-16x16.png', sizes: '16x16', type: 'image/png' },
- { url: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
- { url: '/favicon-96x96.png', sizes: '96x96', type: 'image/png' },
- { url: '/android-icon-192x192.png', sizes: '192x192', type: 'image/png' },
- ],
- apple: [
- { url: '/apple-icon-57x57.png', sizes: '57x57' },
- { url: '/apple-icon-60x60.png', sizes: '60x60' },
- { url: '/apple-icon-72x72.png', sizes: '72x72' },
- { url: '/apple-icon-76x76.png', sizes: '76x76' },
- { url: '/apple-icon-114x114.png', sizes: '114x114' },
- { url: '/apple-icon-120x120.png', sizes: '120x120' },
- { url: '/apple-icon-144x144.png', sizes: '144x144' },
- { url: '/apple-icon-152x152.png', sizes: '152x152' },
- { url: '/apple-icon-180x180.png', sizes: '180x180' },
- ],
- },
- manifest: '/manifest.json',
-}
-
-export const viewport: Viewport = {
- themeColor: '#111827',
- width: 'device-width',
- initialScale: 1,
-}
+config.autoAddCss = false
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
+ useEffect(() => {
+ const title = 'aidxn.cc';
+ let index = 1;
+ let forward = true;
+ const interval = setInterval(() => {
+ document.title = title.substring(0, index);
+ if (forward) {
+ index++;
+ if (index > title.length) {
+ forward = false;
+ index = title.length - 1;
+ }
+ } else {
+ index--;
+ if (index < 1) {
+ forward = true;
+ index = 1;
+ }
+ }
+ }, 500);
+ return () => clearInterval(interval);
+ }, []);
+
return (
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{children}
-
-
-
+
+
);
-}
\ No newline at end of file
+}
+
diff --git a/app/manifesto/page.tsx b/app/manifesto/page.tsx
index 4f13d49..ab93ff3 100644
--- a/app/manifesto/page.tsx
+++ b/app/manifesto/page.tsx
@@ -8,16 +8,14 @@ export default function Manifesto() {
-
-
-
-
-
- Internet Manifesto
-
+
+
-
-
+
+ Internet Manifesto
+
+
+
1. Empathy and Understanding
@@ -28,7 +26,6 @@ export default function Manifesto() {
Suspend judgment and seek to understand
Recognize the humanity in every digital interaction
-
2. Unconditional Sharing!
@@ -41,14 +38,12 @@ export default function Manifesto() {
Support open-source principles
Create extensive documentation on all of my projects
-
3. Genuine Human Connection
I aim to create a genuine human connection with all people I meet, regardless of who or where they are from.
-
4. Privacy & Self-Hosted Services
@@ -65,7 +60,6 @@ export default function Manifesto() {
Focus my services on being free and open
Suggest and support privacy-focused software
-
I Commit
diff --git a/app/music/page.tsx b/app/music/page.tsx
new file mode 100644
index 0000000..dacb362
--- /dev/null
+++ b/app/music/page.tsx
@@ -0,0 +1,26 @@
+import Header from '@/components/Header'
+import MusicWidget from '@/components/widgets/Music'
+import MusicInfo from '@/components/objects/MusicInfo'
+import Footer from '@/components/Footer'
+import { Music as MusicNote } from "lucide-react";
+
+export default function Music() {
+ return (
+
+
+
+
+
+
+
+ Music and Me
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/page.tsx b/app/page.tsx
index 65b0146..2df63fe 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -3,28 +3,13 @@
import Header from '@/components/Header'
import Footer from '@/components/Footer'
import Button from '@/components/objects/Button'
+import Link from '@/components/objects/Link'
import LastPlayed from '@/components/widgets/NowPlaying'
-import LiveIndicator from '@/components/widgets/LiveIndicator'
-
import Image from 'next/image'
-
-import {CreditCard, Mail, PillBottle, Scale, UserCircle} from 'lucide-react'
-import { BsArrowClockwise } from "react-icons/bs";
+import { CreditCard, Mail, PillBottle, Scale } from 'lucide-react'
import { FaHandcuffs } from "react-icons/fa6"
-import {
- SiGithubsponsors,
- SiNextdotjs,
- SiTailwindcss,
- SiDocker,
- SiLinux,
- SiTypescript,
- SiClaude,
- SiPostgresql
-} from 'react-icons/si'
-
import { useTranslation } from 'react-i18next'
-import {TbHeartHandshake, TbUserHeart, TbMessage} from "react-icons/tb";
-import {BiDonateHeart} from "react-icons/bi";
+import { SiGithubsponsors } from 'react-icons/si'
export default function Home() {
const { t } = useTranslation()
@@ -58,120 +43,80 @@ export default function Home() {
-
-
-
-
-
-
-
+
+
{mainSections.map((section, secIndex) => (
-
- {section === t('home.sections.whereYouAre') ? (
-
-
- {section}
-
- ) : section === t('home.sections.whoIAm') ? (
-
-
- {section}
-
- ) : section === t('home.sections.whatIDo') ? (
-
-
- {section}
-
- ) : (section)}
- {section === t('home.sections.whatIDo') && (
-
-
-
-
-
-
-
-
-
- )}
+
+ {section}
{mainStrings[secIndex].map((text: string, index: number) => (
{text}
+ {secIndex === 2 && index === 2 && (
+ <>
+ {' '}
+
+ CVE-2025-29927
+
+ .
+ >
+ )}
))}
))}
-
@@ -179,4 +124,4 @@ export default function Home() {
);
-}
+}
\ No newline at end of file
diff --git a/app/phone/page.tsx b/app/phone/page.tsx
new file mode 100644
index 0000000..2898d7a
--- /dev/null
+++ b/app/phone/page.tsx
@@ -0,0 +1,257 @@
+import Header from "@/components/Header"
+import Footer from "@/components/Footer"
+import { Smartphone, Cpu, MemoryStick, HardDrive, Hash, Hammer, Music, Folder, Layers, SquarePen } from "lucide-react"
+import { FaGoogle, FaYoutube } from "react-icons/fa"
+import { VscTerminalLinux } from "react-icons/vsc"
+import { MdOutlineAndroid } from "react-icons/md"
+import { LuPackageOpen } from "react-icons/lu"
+import { RiTelegram2Fill } from "react-icons/ri"
+import Image from "next/image"
+import Link from "@/components/objects/Link"
+import { FaStarHalfStroke, FaStar } from "react-icons/fa6"
+
+export default function About() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pixel 7 Pro
+
+
cheetah
+
+
+
+ Specifications
+
+
+
+ CPU: Google Tensor G2
+
+
+
+ Storage: 128GB
+
+
+
+ RAM: 12GB
+
+
+
+
+ Modifications
+
+
+
+ Kernel:
+
+ android13-5.10.WILD
+
+
+
+
+ ROM:
+
+ AxionAOSP v1.1
+
+
+
+
+ Root:
+
+ KernelSU-Next
+
+
+
+
+
+
+
+ Apps
+
+
+
+ Music:
+
+ Qobuz
+
+
+
+
+ Files:
+
+ MiXplorer Beta
+
+
+
+
+ Telegram:
+
+ Cherrygram
+
+
+
+
+ YouTube:
+
+ ReVanced Extended
+
+
+
+
+
+ Modules
+
+
+
+
+ Play Integrity Fix
+
+
+
+
+ Tricky Store
+
+
+
+
+ Shamiko
+
+
+
+
+ LSPosed_mod
+
+
+
+
+ Zygisk Next
+
+
+
+
+ SUSFS for KernelSU
+
+
+
+
+
+
+
+
+ Review
+
+
+ Rating:
+ {" "}
+
+
+
+ Coming from a Galaxy A32 5G, the Pixel 7 Pro is a massive upgrade. The Tensor chip is highly performant, and with 12GB of RAM, the device is extremely snappy.
+
+
+ I have had some issues with battery, although this may be due to Play Integrity Fix, which is known to consume battery. However, the camera has been a massive improvement, and the photos it is capable of taking are amazing.
+
+
+ While the volume buttons did fall off, I do not discredit them for this, as Android makes it easy to have customizable on-screen volume buttons, something iPhones do not have.
+
+
+
+
+
+
+
+
+ )
+}
+
diff --git a/app/robots.ts b/app/robots.ts
deleted file mode 100644
index 8451432..0000000
--- a/app/robots.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import type { MetadataRoute } from 'next'
-
-export const robots: MetadataRoute.Robots = {
- rules: {
- userAgent: '*',
- allow: '/',
- },
- sitemap: 'https://aidxn.cc/sitemap.xml',
-}
-
-export default function handler(): MetadataRoute.Robots {
- return robots
-}
\ No newline at end of file
diff --git a/app/sitemap.ts b/app/sitemap.ts
deleted file mode 100644
index b620df9..0000000
--- a/app/sitemap.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import type { MetadataRoute } from 'next'
-
-export default function sitemap(): MetadataRoute.Sitemap {
- return [
- {
- url: 'https://aidxn.cc',
- lastModified: new Date(),
- changeFrequency: 'weekly',
- priority: 1.0,
- },
- {
- url: 'https://aidxn.cc/about',
- lastModified: new Date(),
- changeFrequency: 'weekly',
- priority: 0.8,
- },
- {
- url: 'https://aidxn.cc/ai',
- lastModified: new Date(),
- changeFrequency: 'weekly',
- priority: 0.9,
- },
- {
- url: 'https://aidxn.cc/ai/claude',
- lastModified: new Date(),
- changeFrequency: 'daily',
- priority: 0.9,
- },
- {
- url: 'https://aidxn.cc/contact',
- lastModified: new Date(),
- changeFrequency: 'monthly',
- priority: 0.8,
- },
- {
- url: 'https://aidxn.cc/domains',
- lastModified: new Date(),
- changeFrequency: 'monthly',
- priority: 0.8,
- },
- {
- url: 'https://aidxn.cc/device/cheetah',
- lastModified: new Date(),
- changeFrequency: 'weekly' /* yes, i really re-flash roms this often */,
- priority: 0.8,
- },
- {
- url: 'https://aidxn.cc/device/bonito',
- lastModified: new Date(),
- changeFrequency: 'weekly',
- priority: 0.8,
- },
- {
- url: 'https://aidxn.cc/device/komodo',
- lastModified: new Date(),
- changeFrequency: 'weekly',
- priority: 0.8,
- },
- {
- url: 'https://aidxn.cc/manifesto',
- lastModified: new Date(),
- changeFrequency: 'yearly',
- priority: 0.7,
- },
- ]
-}
\ No newline at end of file
diff --git a/app/time-periods/early-summer-2024/page.tsx b/app/time-periods/early-summer-2024/page.tsx
new file mode 100644
index 0000000..15869fd
--- /dev/null
+++ b/app/time-periods/early-summer-2024/page.tsx
@@ -0,0 +1,15 @@
+import Header from '@/components/Header'
+import WhatWasGoingOn from '@/components/pages/time-periods/early-summer-2024/WhatWasGoingOn'
+import Footer from '@/components/Footer'
+
+export default function EarlySummer2024() {
+ return (
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/time-periods/early-summer-2024/what-was-going-on/page.tsx b/app/time-periods/early-summer-2024/what-was-going-on/page.tsx
new file mode 100644
index 0000000..31a9ee4
--- /dev/null
+++ b/app/time-periods/early-summer-2024/what-was-going-on/page.tsx
@@ -0,0 +1,15 @@
+import Header from '@/components/Header'
+import WhatWasGoingOn from '@/components/pages/time-periods/early-summer-2024/WhatWasGoingOn'
+import Footer from '@/components/Footer'
+
+export default function Music() {
+ return (
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/time-periods/late-summer-2024/page.tsx b/app/time-periods/late-summer-2024/page.tsx
new file mode 100644
index 0000000..d45de92
--- /dev/null
+++ b/app/time-periods/late-summer-2024/page.tsx
@@ -0,0 +1,15 @@
+import Header from '@/components/Header'
+import WhatWasGoingOn from '@/components/pages/time-periods/late-summer-2024/WhatWasGoingOn'
+import Footer from '@/components/Footer'
+
+export default function LateSummer2024() {
+ return (
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/time-periods/late-summer-2024/what-was-going-on/page.tsx b/app/time-periods/late-summer-2024/what-was-going-on/page.tsx
new file mode 100644
index 0000000..353e524
--- /dev/null
+++ b/app/time-periods/late-summer-2024/what-was-going-on/page.tsx
@@ -0,0 +1,15 @@
+import Header from '@/components/Header'
+import WhatWasGoingOn from '@/components/pages/time-periods/late-summer-2024/WhatWasGoingOn'
+import Footer from '@/components/Footer'
+
+export default function Music() {
+ return (
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/components/AnimatedTitle.tsx b/components/AnimatedTitle.tsx
deleted file mode 100644
index ea8346c..0000000
--- a/components/AnimatedTitle.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-"use client"
-
-import { useEffect } from "react";
-
-export default function AnimatedTitle() {
- useEffect(() => {
- const title = 'aidxn.cc';
- let index = 1;
- let forward = true;
- const interval = setInterval(() => {
- document.title = title.substring(0, index);
- if (forward) {
- index++;
- if (index > title.length) {
- forward = false;
- index = title.length - 1;
- }
- } else {
- index--;
- if (index < 1) {
- forward = true;
- index = 1;
- }
- }
- }, 500);
- return () => clearInterval(interval);
- }, []);
- return null;
-}
diff --git a/components/Footer.tsx b/components/Footer.tsx
index 65a2d88..95d8534 100644
--- a/components/Footer.tsx
+++ b/components/Footer.tsx
@@ -7,7 +7,7 @@ export default function Footer() {
return (
-
+
Open Source and Copyright-Free
diff --git a/components/Header.tsx b/components/Header.tsx
index 89d959c..4c8efbd 100644
--- a/components/Header.tsx
+++ b/components/Header.tsx
@@ -2,22 +2,7 @@
import React, { useState, useRef, useEffect } from 'react'
import Link from 'next/link'
-import {
- House,
- Link as LinkIcon,
- User,
- Phone,
- BookOpen,
- X,
- Menu,
- Globe,
- ChevronDown,
- ChevronRight,
- Brain,
- Smartphone
-} from 'lucide-react'
-import { TbUserHeart } from 'react-icons/tb'
-import { SiClaude, SiGoogle } from 'react-icons/si'
+import { House, Link as LinkIcon, User, Phone, BookOpen, Music, Rss, X, Menu, Globe, ChevronDown } from 'lucide-react'
import { useTranslation } from 'react-i18next'
interface NavItemProps {
@@ -35,193 +20,12 @@ const NavItem = ({ href, icon, children }: NavItemProps) => (
);
-interface DropdownNavItemProps {
- id: string;
- href: string;
- icon: React.ElementType;
- children: React.ReactNode;
- dropdownContent: React.ReactNode;
- isMobile?: boolean;
- isOpen?: boolean;
- onOpenChange?: (id: string | null) => void;
-}
-
-const DropdownNavItem = ({ id, href, icon, children, dropdownContent, isMobile = false, isOpen = false, onOpenChange }: DropdownNavItemProps) => {
- const dropdownRef = useRef
(null);
-
- useEffect(() => {
- const handleClickOutside = (event: MouseEvent) => {
- if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
- onOpenChange?.(null);
- }
- };
-
- if (isMobile && isOpen) {
- document.addEventListener('click', handleClickOutside);
- return () => document.removeEventListener('click', handleClickOutside);
- }
- }, [isMobile, isOpen, onOpenChange]);
-
- const handleMouseEnter = () => {
- if (!isMobile) {
- onOpenChange?.(id);
- }
- };
-
- const handleMouseLeave = (e: React.MouseEvent) => {
- if (!isMobile) {
- const relatedTarget = e.relatedTarget as HTMLElement;
- if (relatedTarget && dropdownRef.current?.contains(relatedTarget)) {
- return;
- }
- onOpenChange?.(null);
- }
- };
-
- const handleClick = (e: React.MouseEvent) => {
- if (isMobile) {
- e.preventDefault();
- e.stopPropagation();
- onOpenChange?.(isOpen ? null : id);
- }
- };
-
- return (
-
-
-
- {React.createElement(icon, { className: "text-md mr-2", strokeWidth: 2.5, size: 20 })}
- {children}
-
-
-
- {isOpen && (
- <>
- {/* Invisible bridge to handle gap */}
- {!isMobile && (
-
- )}
-
- {dropdownContent}
-
- >
- )}
-
- );
-};
-
-interface NestedDropdownItemProps {
- children: React.ReactNode;
- nestedContent: React.ReactNode;
- isMobile?: boolean;
-}
-
-const NestedDropdownItem = ({ children, nestedContent, isMobile = false }: NestedDropdownItemProps) => {
- const [isOpen, setIsOpen] = useState(false);
- const itemRef = useRef(null);
- const timeoutRef = useRef(null);
-
- const handleMouseEnter = () => {
- if (!isMobile) {
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
- setIsOpen(true);
- }
- };
-
- const handleMouseLeave = (e: React.MouseEvent) => {
- if (!isMobile) {
- const relatedTarget = e.relatedTarget as HTMLElement;
- if (relatedTarget && itemRef.current?.contains(relatedTarget)) {
- return;
- }
- timeoutRef.current = setTimeout(() => setIsOpen(false), 100);
- }
- };
-
- const handleClick = (e: React.MouseEvent) => {
- if (isMobile) {
- e.preventDefault();
- e.stopPropagation();
- setIsOpen(!isOpen);
- }
- };
-
- if (isMobile) {
- return (
-
-
-
-
- {children}
-
-
-
- {isOpen && (
-
- {nestedContent}
-
- )}
-
- );
- }
-
- return (
-
-
-
-
- {children}
-
-
-
- {isOpen && (
- <>
- {/* Invisible bridge to handle gap */}
-
-
- {nestedContent}
-
- >
- )}
-
- );
-};
-
const LanguageSelector = () => {
const { i18n } = useTranslation();
const [isOpen, setIsOpen] = useState(false);
const [isMobile, setIsMobile] = useState(false);
const dropdownRef = useRef(null);
-
+
const languages = [
{ code: 'en-US', name: 'English' },
];
@@ -230,14 +34,14 @@ const LanguageSelector = () => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 1024);
};
-
+
checkMobile();
window.addEventListener('resize', checkMobile);
return () => window.removeEventListener('resize', checkMobile);
}, []);
- const changeLanguage = async (lng: string) => {
- await i18n.changeLanguage(lng);
+ const changeLanguage = (lng: string) => {
+ i18n.changeLanguage(lng);
setIsOpen(false);
};
@@ -248,33 +52,9 @@ const LanguageSelector = () => {
}
};
- if (isMobile) {
- document.addEventListener('mousedown', handleClickOutside);
- return () => document.removeEventListener('mousedown', handleClickOutside);
- }
- }, [isMobile]);
-
- const handleMouseEnter = () => {
- if (!isMobile) {
- setIsOpen(true);
- }
- };
-
- const handleMouseLeave = (e: React.MouseEvent) => {
- if (!isMobile) {
- const relatedTarget = e.relatedTarget as HTMLElement;
- if (relatedTarget && dropdownRef.current?.contains(relatedTarget)) {
- return;
- }
- setIsOpen(false);
- }
- };
-
- const handleClick = () => {
- if (isMobile) {
- setIsOpen(!isOpen);
- }
- };
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => document.removeEventListener('mousedown', handleClickOutside);
+ }, []);
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Escape') {
@@ -285,58 +65,53 @@ const LanguageSelector = () => {
}
};
+ const buttonContent = (
+ <>
+
+ {languages.find(lang => lang.code === i18n.language)?.name || 'English'}
+ {!isMobile && (
+
+ )}
+ >
+ );
+
return (
-
-
+ setIsOpen(!isOpen)}
onKeyDown={handleKeyDown}
- className={`flex items-center ${isMobile ? 'justify-between' : ''} text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all duration-300 ${isMobile ? 'w-full' : ''}`}
+ className={`flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all duration-300 ${isMobile ? 'w-full' : ''}`}
aria-expanded={isOpen}
aria-haspopup="true"
>
-
-
- {languages.find(lang => lang.code === i18n.language)?.name || 'English'}
-
-
+ {buttonContent}
{isOpen && (
- <>
- {/* Invisible bridge to handle gap */}
- {!isMobile && (
-
- )}
-
- {languages.map((lang) => (
- changeLanguage(lang.code)}
- className={`block w-full text-left ${isMobile ? 'px-4 py-2.5' : 'px-5 py-3'} ${isMobile ? 'text-sm' : 'text-base'} rounded-md ${
- i18n.language === lang.code
- ? 'text-white bg-gray-700/50'
- : 'text-gray-300 hover:text-white hover:bg-gray-700/50'
- } transition-all duration-300`}
- role="menuitem"
- >
- {lang.name}
-
- ))}
-
- >
+
+ {languages.map((lang) => (
+ changeLanguage(lang.code)}
+ className={`block w-full text-left px-4 py-2 text-sm ${
+ i18n.language === lang.code
+ ? 'text-white bg-gray-700'
+ : 'text-gray-300 hover:text-white hover:bg-gray-700'
+ }`}
+ role="menuitem"
+ >
+ {lang.name}
+
+ ))}
+
)}
);
@@ -344,130 +119,35 @@ const LanguageSelector = () => {
export default function Header() {
const [isOpen, setIsOpen] = useState(false);
- const [isMobile, setIsMobile] = useState(false);
- const [activeDropdown, setActiveDropdown] = useState(null);
- const toggleMenu = () => {
- setIsOpen(!isOpen);
- if (isOpen) {
- setActiveDropdown(null);
- }
- };
-
- const handleDropdownChange = (id: string | null) => {
- setActiveDropdown(id);
- };
-
- useEffect(() => {
- const checkMobile = () => {
- setIsMobile(window.innerWidth < 1024);
- };
-
- checkMobile();
- window.addEventListener('resize', checkMobile);
- return () => window.removeEventListener('resize', checkMobile);
- }, []);
-
- const aboutDropdownContent = (
- <>
-
-
-
- Get to Know Me
-
-
-
-
- Pixel 3a XL (bonito)
-
-
-
- Pixel 7 Pro (cheetah)
-
-
-
- Pixel 9 Pro (komodo)
-
- >
- }
- >
- Devices
-
-
- >
- );
-
- const aiDropdownContent = (
-
-
-
- Claude Usage
-
-
- );
+ const toggleMenu = () => setIsOpen(!isOpen);
return (
- <>
-
-
- {isOpen && (
-
- )}
-
-
- aidxn.cc
-
-
- {isOpen ? : }
-
-
- Home
-
- About Me
-
-
- AI
-
- Contact
- Domains
- Manifesto
-
-
-
-
-
+
+
+
+ aidxn.cc
+
+
+ {isOpen ? : }
+
+
+ Home
+ About
+ Contact
+ Domains
+ Manifesto
+ Music
+ Blog
+
-
-
- >
+
+
+
+
+
+
);
}
+
diff --git a/components/I18nProvider.tsx b/components/I18nProvider.tsx
deleted file mode 100644
index 3ddf176..0000000
--- a/components/I18nProvider.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-"use client";
-
-import { ReactNode } from "react";
-import "../i18n";
-
-export default function I18nProvider({ children }: { children: ReactNode }) {
- return <>{children}>;
-}
diff --git a/components/objects/BackButton.tsx b/components/objects/BackButton.tsx
new file mode 100644
index 0000000..f1cf8be
--- /dev/null
+++ b/components/objects/BackButton.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import Link from 'next/link';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
+
+interface BackButtonProps {
+ href: string;
+ label?: string;
+}
+
+const BackButton: React.FC
= ({ href, label = 'Back' }) => {
+ return (
+
+
+ {label}
+
+ );
+};
+
+export default BackButton;
\ No newline at end of file
diff --git a/components/objects/Button.tsx b/components/objects/Button.tsx
index 8d3caf6..db6693d 100644
--- a/components/objects/Button.tsx
+++ b/components/objects/Button.tsx
@@ -1,40 +1,30 @@
import React from 'react'
import Link from 'next/link'
+import { cn } from '@/lib/utils'
interface ButtonProps {
href: string
+ label: string
+ icon?: React.ElementType
target?: string
- variant?: "primary" | "rounded"
className?: string
- icon?: React.ReactNode
- children: React.ReactNode
}
-const Button: React.FC = ({ href, target, variant, className, icon, children }) => {
- if (!variant || variant === "primary") {
- return (
-
- {icon}
- {children}
-
- )
- } else if (variant === "rounded") {
- return (
-
- {icon}
- {children}
-
- )
- }
+const Button: React.FC = ({ href, label, icon, target, className }) => {
+ return (
+
+ {icon && React.createElement(icon, { size: 20, className: "mr-2" })}
+ {label}
+
+ )
}
export default Button
\ No newline at end of file
diff --git a/components/objects/ContactButton.tsx b/components/objects/ContactButton.tsx
new file mode 100644
index 0000000..53000cc
--- /dev/null
+++ b/components/objects/ContactButton.tsx
@@ -0,0 +1,26 @@
+import { IconDefinition } from '@fortawesome/fontawesome-svg-core'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import Link from 'next/link';
+
+interface ContactButtonProps {
+ href: string;
+ icon: IconDefinition;
+ label: string;
+ className?: string;
+}
+
+function ContactButton({ href, icon, label, className }: ContactButtonProps) {
+ return (
+
+
+ {label}
+
+ )
+}
+
+export default ContactButton;
\ No newline at end of file
diff --git a/components/objects/MusicInfo.tsx b/components/objects/MusicInfo.tsx
new file mode 100644
index 0000000..450cf8e
--- /dev/null
+++ b/components/objects/MusicInfo.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import Button from './Button';
+
+interface TimePeriod {
+ title: string;
+ slug: string;
+}
+
+const timePeriods: TimePeriod[] = [
+ { title: 'Late Summer 2024', slug: 'late-summer-2024' },
+ { title: 'Early Summer 2024', slug: 'early-summer-2024' },
+];
+
+const MusicInfo: React.FC = () => {
+ return (
+
+ {timePeriods.map((period) => (
+
+ ))}
+
+ );
+};
+
+export default MusicInfo;
+
diff --git a/components/objects/MusicText.tsx b/components/objects/MusicText.tsx
deleted file mode 100644
index 4131b6c..0000000
--- a/components/objects/MusicText.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-"use client"
-
-import type React from "react"
-
-interface ScrollTxtProps {
- text: string
- className?: string
- type?: 'artist' | 'track' | 'release'
-}
-
-const ScrollTxt: React.FC = ({ text, className = "", type }) => {
- const getTypeClass = (type?: string) => {
- switch(type) {
- case 'artist':
- return 'text-white text-xs opacity-90 font-medium text-[8px]'
- case 'track':
- return 'text-white text-xs font-bold'
- case 'release':
- return 'text-white text-xs opacity-90 font-medium text-[8px]'
- default:
- return ''
- }
- }
-
- const textClass = getTypeClass(type)
-
- return (
-
- )
-}
-
-export default ScrollTxt
-
diff --git a/components/objects/RandomFooterMsg.tsx b/components/objects/RandomFooterMsg.tsx
index 5a5a4a4..41a86a4 100644
--- a/components/objects/RandomFooterMsg.tsx
+++ b/components/objects/RandomFooterMsg.tsx
@@ -1,16 +1,14 @@
-"use client"
-
import {
SiNextdotjs,
SiLucide,
SiVercel,
+ SiCloudflarepages,
SiSimpleicons,
SiFontawesome,
SiShadcnui,
SiTailwindcss
} from "react-icons/si"
import Link from 'next/link'
-import { useState, useEffect } from 'react'
export const footerMessages = [
[
@@ -33,6 +31,11 @@ export const footerMessages = [
"https://vercel.com/font",
],
+ [
+ "Hosted by Cloudflare",
+ "https://workers.cloudflare.com/",
+
+ ],
[
"Icons by Font Awesome",
"https://fontawesome.com/",
@@ -51,30 +54,11 @@ export const footerMessages = [
]
export default function RandomFooterMsg() {
- const [randomIndex, setRandomIndex] = useState(0)
- const [isMounted, setIsMounted] = useState(false)
-
- useEffect(() => {
- setIsMounted(true)
- setRandomIndex(Math.floor(Math.random() * footerMessages.length))
- }, [])
-
- if (!isMounted) {
- const [message, url, icon] = footerMessages[0]
- return (
-
-
- {icon}
- {message}
-
-
- )
- }
-
+ const randomIndex = Math.floor(Math.random() * footerMessages.length)
const [message, url, icon] = footerMessages[randomIndex]
return (
-
+
{icon}
{message}
diff --git a/components/objects/ScrollTxt.tsx b/components/objects/ScrollTxt.tsx
new file mode 100644
index 0000000..ea5b898
--- /dev/null
+++ b/components/objects/ScrollTxt.tsx
@@ -0,0 +1,47 @@
+"use client"
+
+import type React from "react"
+import { useEffect, useRef, useState } from "react"
+
+interface ScrollTxtProps {
+ text: string
+ className?: string
+}
+
+const ScrollTxt: React.FC
= ({ text, className = "" }) => {
+ const containerRef = useRef(null)
+ const textRef = useRef(null)
+ const [shouldScroll, setShouldScroll] = useState(false)
+
+ useEffect(() => {
+ if (containerRef.current && textRef.current) {
+ const containerWidth = containerRef.current.offsetWidth
+ const textWidth = textRef.current.offsetWidth
+ setShouldScroll(textWidth > containerWidth)
+ }
+ }, []) // Updated dependency array
+
+ return (
+
+
+ {shouldScroll ? (
+ <>
+ {text}
+ •
+ {text}
+ •
+ {text}
+ >
+ ) : (
+ text
+ )}
+
+
+ )
+}
+
+export default ScrollTxt
+
diff --git a/components/pages/time-periods/early-summer-2024/WhatWasGoingOn.tsx b/components/pages/time-periods/early-summer-2024/WhatWasGoingOn.tsx
new file mode 100644
index 0000000..6689389
--- /dev/null
+++ b/components/pages/time-periods/early-summer-2024/WhatWasGoingOn.tsx
@@ -0,0 +1,27 @@
+import React from 'react'
+import BackButton from '@/components/objects/BackButton'
+
+const WhatWasGoingOnLateSummer2024: React.FC = () => {
+ return (
+
+
+ What was going on during the start of summer 2024?
+
+
+
+ During Early Summer 2024, I was walking a ton in towns all across Massachusetts. During this time, I would listen to a lot of music. I regret not finding out about LastFM for so long... During this time, I was always happy, especially when I had music or a YouTube video playing. I would also call my friends often during this time.
+
+
Context
+
+ This summer was the one where I came back from my abusive treatment center. I was finally free from the place that had been holding me back for so long. So as you can imagine, I felt free as a bird.
+
+
+ With this chance to explore, being in so many different towns, I really had a good time and made good memories, which I will not be writing about.
+
+
+
+
+ );
+};
+
+export default WhatWasGoingOnLateSummer2024;
\ No newline at end of file
diff --git a/components/pages/time-periods/late-summer-2024/WhatWasGoingOn.tsx b/components/pages/time-periods/late-summer-2024/WhatWasGoingOn.tsx
new file mode 100644
index 0000000..9f5b03c
--- /dev/null
+++ b/components/pages/time-periods/late-summer-2024/WhatWasGoingOn.tsx
@@ -0,0 +1,26 @@
+import React from 'react'
+import BackButton from '@/components/objects/BackButton'
+
+const WhatWasGoingOnLateSummer2024: React.FC = () => {
+ return (
+
+
+ What was going on during the end of summer 2024?
+
+
+
+ During late summer 2024, my depression and the "after effects" of treatment really kicked in. I had quit going to my therapist as I didn't feel like they were doing much of anything for me. I am very happy to say that since I quit my therapist, I have been doing much better.
+
+
+ At this time, the baseball season was over, so I was walking around much less. I was still listening to a lot of music and I started getting into less depressed songs. I was also starting to get into more "normal" music, which was an interesting phase (which I believe I'm still in).
+
+
+ A highlight of late summer 2024 was a vacation I took. This vacation has entire albums which remind me of it and I will always cherish those memories deeply.
+
+
+
+
+ );
+};
+
+export default WhatWasGoingOnLateSummer2024;
diff --git a/components/widgets/FeaturedRepos.tsx b/components/widgets/FeaturedRepos.tsx
index 7dc5ef6..36e76ab 100644
--- a/components/widgets/FeaturedRepos.tsx
+++ b/components/widgets/FeaturedRepos.tsx
@@ -1,8 +1,9 @@
-import { SiGithub, SiForgejo } from "react-icons/si"
-import { TbStar, TbGitBranch } from "react-icons/tb"
-import featuredProjects from "@/public/data/featured.json"
-import Link from "next/link"
-import { cn } from "@/lib/utils"
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+import { faGitAlt, faGithub } from '@fortawesome/free-brands-svg-icons'
+import { faStar, faCodeBranch } from '@fortawesome/free-solid-svg-icons'
+import featuredProjects from '@/public/data/featured.json'
+import Link from 'next/link'
+import { cn } from '@/lib/utils'
export default function GitHubFeatured({ className }: { className?: string }) {
return (
@@ -10,16 +11,16 @@ export default function GitHubFeatured({ className }: { className?: string }) {
{featuredProjects.map((project) => (
-
- {project.github ? : } {project.name}
+
+ {project.name}
{project.description}
View Repo
- {project.stars}
- {project.forks}
+ {project.stars}
+ {project.forks}
diff --git a/components/widgets/LiveIndicator.tsx b/components/widgets/LiveIndicator.tsx
deleted file mode 100644
index d357719..0000000
--- a/components/widgets/LiveIndicator.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-"use client"
-
-import { useEffect, useState } from "react"
-import { connectSocket } from "@/lib/socket"
-
-const LiveIndicator = () => {
- const [connected, setConnected] = useState(false)
-
- useEffect(() => {
- const socket = connectSocket()
-
- socket.on('connect', () => {
- setConnected(true)
- })
-
- socket.on('disconnect', () => {
- setConnected(false)
- })
-
- return () => {
- socket.off('connect')
- socket.off('disconnect')
- }
- }, [])
-
- return (
-
-
-
- {connected ? "LIVE" : "Connecting..."}
-
-
- )
-}
-
-export default LiveIndicator
\ No newline at end of file
diff --git a/components/widgets/Music.tsx b/components/widgets/Music.tsx
new file mode 100644
index 0000000..ca3dce3
--- /dev/null
+++ b/components/widgets/Music.tsx
@@ -0,0 +1,127 @@
+"use client"
+
+import { useState, useEffect } from "react"
+import Image from "next/image"
+import { Play, SkipBack, SkipForward } from "lucide-react"
+import LoadingSpinner from "../objects/LoadingSpinner"
+import { SeekBar } from "@/components/objects/SeekBar"
+
+interface Song {
+ albumArt: string
+ name: string
+ artist: string
+ duration: string
+ link?: string
+}
+
+interface Period {
+ timePeriod: string
+ songs: Song[]
+}
+
+export default function Home() {
+ const [timePeriod, setTimePeriod] = useState("Early Summer 2024")
+ const [songs, setSongs] = useState([])
+ const [currentIndex, setCurrentIndex] = useState(0)
+ const [isLoading, setIsLoading] = useState(true)
+ const [currentPosition, setCurrentPosition] = useState(0)
+
+ useEffect(() => {
+ setIsLoading(true)
+ fetch("/data/music.json")
+ .then((response) => response.json())
+ .then((data: Period[]) => {
+ const selectedPeriod = data.find((period) => period.timePeriod === timePeriod)
+ const songsList = selectedPeriod ? selectedPeriod.songs : []
+ setSongs(songsList)
+ const newIndex = Math.floor(Math.random() * songsList.length)
+ setCurrentIndex(newIndex)
+ // Set initial random position for the selected song
+ if (songsList.length > 0) {
+ const durationInSeconds = parseDuration(songsList[newIndex]?.duration || "0:00")
+ setCurrentPosition(Math.floor(Math.random() * durationInSeconds))
+ }
+ setIsLoading(false)
+ })
+ .catch((error) => {
+ console.error("Error fetching music data:", error)
+ setIsLoading(false)
+ })
+ }, [timePeriod])
+
+ const handleNext = () => {
+ setCurrentIndex((prevIndex) => {
+ const nextIndex = (prevIndex + 1) % songs.length
+ const durationInSeconds = parseDuration(songs[nextIndex].duration)
+ setCurrentPosition(Math.floor(Math.random() * durationInSeconds))
+ return nextIndex
+ })
+ }
+
+ const handlePrevious = () => {
+ setCurrentIndex((prevIndex) => {
+ const nextIndex = (prevIndex - 1 + songs.length) % songs.length
+ const durationInSeconds = parseDuration(songs[nextIndex].duration)
+ setCurrentPosition(Math.floor(Math.random() * durationInSeconds))
+ return nextIndex
+ })
+ }
+
+ const parseDuration = (duration: string): number => {
+ const [minutes, seconds] = duration.split(":").map(Number)
+ return minutes * 60 + seconds
+ }
+
+ return (
+
+
+ {isLoading && }
+
+ {!isLoading && songs.length > 0 && (
+
+
+
{songs[currentIndex].name}
+
{songs[currentIndex].artist}
+
+
+
+
+
+
window.open(songs[currentIndex]?.link, "_blank")}>
+
+
+
+
+
+
+
+ )}
+
+
+
+ Time Period
+
+ setTimePeriod(e.target.value)}
+ className="px-3 py-2 bg-gray-700 rounded-sm mb-2"
+ >
+ Early Summer 2024
+
+
+
+
+ )
+}
+
diff --git a/components/widgets/NowPlaying.tsx b/components/widgets/NowPlaying.tsx
index 1f96af0..a9c98c9 100644
--- a/components/widgets/NowPlaying.tsx
+++ b/components/widgets/NowPlaying.tsx
@@ -1,290 +1,253 @@
"use client"
import type React from "react"
-import { useEffect, useState } from "react"
-import { Loader2, AlertCircle } from "lucide-react"
-import { PiMusicNotesFill } from "react-icons/pi";
-import { FaBluetoothB } from "react-icons/fa6";
-import { IoBatteryFullSharp } from "react-icons/io5"
-import { IoIosPlay } from "react-icons/io"
-import { TbDiscOff } from "react-icons/tb"
+import { useEffect, useState, useCallback, useRef } from "react"
+import Image from "next/image"
+import { Music, ExternalLink, Disc, User, Loader2, AlertCircle } from "lucide-react"
+import { TbDiscOff, TbDisc } from "react-icons/tb"
+import Marquee from "react-fast-marquee"
import { Progress } from "@/components/ui/progress"
import Link from "@/components/objects/Link"
-import ScrollTxt from "@/components/objects/MusicText"
-import { connectSocket, disconnectSocket } from "@/lib/socket"
-interface LastFmResponse {
- album?: {
- image?: Array<{ size: string; '#text': string }>
- }
- track?: {
- album?: {
- image?: Array<{ size: string; '#text': string }>
- }
- }
-}
-
-interface NowPlayingData {
- track_name?: string
- artist_name?: string
+interface Track {
+ track_name: string
+ artist_name: string
release_name?: string
mbid?: string
- coverArt?: string | null
- lastFmData?: LastFmResponse
- status: 'loading' | 'partial' | 'complete' | 'error'
- message?: string
}
-const NowPlaying: React.FC = () => {
- const [nowPlaying, setNowPlaying] = useState({ status: 'loading' })
- const [currentTime, setCurrentTime] = useState(new Date())
- const [volume, setVolume] = useState(25)
- const [screenOn, setScreenOn] = useState(true)
- const [progressSteps, setProgressSteps] = useState({ current: 0, total: 3 })
+const ScrollableText: React.FC<{ text: string; className?: string }> = ({ text, className = "" }) => {
+ const containerRef = useRef(null)
+ const [shouldScroll, setShouldScroll] = useState(false)
useEffect(() => {
- const socket = connectSocket()
-
- socket.on('connect', () => {
- console.log('Connected to server')
- socket.emit('requestNowPlaying')
- socket.emit('startAutoRefresh')
- })
-
- socket.on('disconnect', () => {
- console.log('[i] Disconnected from server')
- })
-
- socket.on('nowPlaying', (data: NowPlayingData) => {
- console.log('Received now playing data:', data)
- setNowPlaying(prevState => ({
- ...prevState,
- ...data
- }))
-
- if (data.status === 'loading') {
- setProgressSteps({ current: 1, total: 3 })
- } else if (data.status === 'partial') {
- setProgressSteps({ current: 2, total: 3 })
- } else if (data.status === 'complete') {
- setProgressSteps({ current: 3, total: 3 })
- }
- })
-
- socket.on('connect_error', (error) => {
- console.error('[!] Connection error:', error)
- setNowPlaying({ status: 'error', message: 'Connection failed' })
- })
-
- return () => {
- socket.off('connect')
- socket.off('disconnect')
- socket.off('nowPlaying')
- socket.off('connect_error')
- disconnectSocket()
+ if (containerRef.current) {
+ setShouldScroll(containerRef.current.scrollWidth > containerRef.current.clientWidth)
+ console.log("[i] text width checked: ", containerRef.current.scrollWidth, containerRef.current.clientWidth)
}
- }, [])
+ }, [containerRef])
- useEffect(() => {
- const timer = setInterval(() => {
- setCurrentTime(new Date())
- }, 1000)
- return () => clearInterval(timer)
- }, [])
-
- const formatTime = (date: Date) => {
- return date.toLocaleTimeString('en-US', {
- hour: 'numeric',
- minute: '2-digit',
- hour12: true
- })
- }
-
- const renderScreenContent = () => {
- if (nowPlaying.status === 'loading') {
- return (
-
-
-
-
{nowPlaying.message || 'Connecting...'}
-
0 ? (progressSteps.current * 100) / progressSteps.total : 0}
- className="h-1"
- />
-
-
- )
- }
-
- if (nowPlaying.status === 'error') {
- return (
-
-
-
- {nowPlaying.message || 'Error loading data'}
-
-
- )
- }
-
- if (!nowPlaying.track_name) {
- return (
-
-
-
- Nothing playing
-
-
- Check my ListenBrainz
-
-
- )
- }
-
- // normal state
+ if (shouldScroll) {
+ console.log("✅ scrolling is active")
return (
- <>
-
-
-
-
- {nowPlaying.release_name && }
-
-
- {/* Album art */}
-
- {nowPlaying.status === 'partial' && !nowPlaying.coverArt ? (
-
- ) : nowPlaying.coverArt ? (
- // eslint-disable-next-line @next/next/no-img-element
-
- ) : (
-
- )}
-
- >
+
+ {text}
+ •
+
)
}
return (
-
-
- {/* Volume buttons */}
-
-
setVolume(v => Math.min(100, v + 5))}>
{/* up */}
-
{/* play/pause */}
-
setVolume(v => Math.max(0, v - 5))}>
{/* down */}
+
+ )
+}
+
+const NowPlaying: React.FC = () => {
+ const [track, setTrack] = useState
(null)
+ const [coverArt, setCoverArt] = useState(null)
+ const [loading, setLoading] = useState(true)
+ const [loadingStatus, setLoadingStatus] = useState("Initializing")
+ const [error, setError] = useState(null)
+ const [progress, setProgress] = useState(0)
+ const [steps, setSteps] = useState(0)
+
+ const updateProgress = useCallback((current: number, total: number, status: string) => {
+ setProgress(current)
+ setSteps(total)
+ setLoadingStatus(status)
+ console.log(`[${current}/${total}] ${status}`)
+ }, [])
+
+ const fetchAlbumArt = useCallback(async (artist: string, album?: string) => {
+ if (!album) {
+ updateProgress(0, 0, "No album found")
+ setCoverArt(null)
+ setLoading(false)
+ return
+ }
+ try {
+ updateProgress(2, 3, `Searching for album: ${artist} - ${album}`)
+ const response = await fetch(
+ `https://musicbrainz.org/ws/2/release/?query=artist:${encodeURIComponent(
+ artist
+ )}%20AND%20release:${encodeURIComponent(album)}&fmt=json`
+ )
+ if (!response.ok) {
+ updateProgress(0, 0, `Album art fetch error: ${response.status}`)
+ setError("Error fetching album art (see console for details)")
+ setLoading(false)
+ return
+ }
+ const data = await response.json()
+ if (data.releases && data.releases.length > 0) {
+ const mbid = data.releases[0].id
+ updateProgress(3, 3, "Fetching cover art...")
+ setTrack(prev => prev ? { ...prev, mbid: `${mbid || null}` } : { track_name: "", artist_name: "", release_name: undefined, mbid: `${mbid || null}` })
+ const coverArtResponse = await fetch(`https://coverartarchive.org/release/${mbid}/front`)
+ if (coverArtResponse.ok) {
+ setCoverArt(coverArtResponse.url)
+ setLoading(false)
+ } else {
+ updateProgress(0, 0, "Cover art not found")
+ setCoverArt(null)
+ setLoading(false)
+ }
+ } else {
+ updateProgress(0, 0, "No releases found")
+ setCoverArt(null)
+ setLoading(false)
+ }
+ } catch (error) {
+ updateProgress(0, 0, `Error: ${error}`)
+ setCoverArt(null)
+ setLoading(false)
+ }
+ }, [updateProgress])
+
+ const fetchNowPlaying = useCallback(async () => {
+ updateProgress(1, 3, "Fetching current listen...")
+ try {
+ const response = await fetch("https://api.listenbrainz.org/1/user/p0ntus/playing-now")
+ const data = await response.json()
+
+ if (data.payload.count > 0 && data.payload.listens[0].track_metadata) {
+ const trackMetadata = data.payload.listens[0].track_metadata
+ console.log("= TRACK METADATA =")
+ if (trackMetadata.track_name) { console.log("🎵", trackMetadata.track_name) }
+ if (trackMetadata.artist_name) { console.log("🎤", trackMetadata.artist_name) }
+ if (trackMetadata.release_name) { console.log("💿", trackMetadata.release_name) }
+ setTrack({
+ track_name: trackMetadata.track_name,
+ artist_name: trackMetadata.artist_name,
+ release_name: trackMetadata.release_name,
+ mbid: trackMetadata.mbid,
+ })
+ updateProgress(2, 3, "Finding album art...")
+ await fetchAlbumArt(trackMetadata.artist_name, trackMetadata.release_name)
+ } else {
+ updateProgress(0, 0, "No track playing")
+ setLoading(false)
+ }
+ } catch (error) {
+ updateProgress(0, 0, `Error: ${error}`)
+ setError("Error fetching now playing data")
+ setLoading(false)
+ }
+ }, [fetchAlbumArt, updateProgress])
+
+ useEffect(() => {
+ fetchNowPlaying()
+ }, [fetchNowPlaying])
+
+ if (loading) {
+ console.log("[LastPlayed] Loading state rendered")
+ return (
+
+
+
+
Fetching music data...
- {/* Top power button */}
-
setScreenOn(prev => !prev)}>
- {/* White bezel (fuses screen+home btn) */}
-
- {/* Virtual screen */}
-
- {screenOn && (
-
-
-
-
{formatTime(currentTime)}
-
-
-
-
-
-
- )}
- {screenOn ? renderScreenContent() : (
-
- )}
- {/* Player controls and seekbar */}
- {screenOn && nowPlaying.track_name && (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
setVolume(Number(e.target.value))} className="absolute top-0 left-0 w-full h-full opacity-0 cursor-pointer" />
-
-
-
- )}
-
- {/* Home button */}
-
+
0 ? (progress * 100) / steps : 0} className="mb-4" />
+
+
+ {loadingStatus} {steps > 0 && `(${progress}/${steps})`}
+
+ )
+ }
+
+ if (error) {
+ console.log("[LastPlayed] Error state rendered")
+ return (
+
+ )
+ }
+
+ if (!track) {
+ console.log("[LastPlayed] Hidden due to no track data")
+ return (
+
+
+
+
Nothing's playing right now
+
+
+
Can you believe it? I'm not listening to anything on ListenBrainz right now! If you're in the mood, feel free to check out my ListenBrainz.
+
+
+ )
+ }
+
+ console.log("[LastPlayed] Rendered track:", track.track_name)
+ return (
+
+
+
+
Now Playing
+
+
+ {coverArt ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+ LIVE data provided by ListenBrainz
+
+
+
+ Last updated: {new Date().toLocaleString()}
+
+
)
}
diff --git a/lib/now-playing-server.ts b/lib/now-playing-server.ts
deleted file mode 100644
index 57696fc..0000000
--- a/lib/now-playing-server.ts
+++ /dev/null
@@ -1,263 +0,0 @@
-import { Server as SocketServer } from 'socket.io'
-
-interface TrackMetadata {
- track_name: string
- artist_name: string
- release_name?: string
- mbid?: string
- additional_info?: {
- recording_mbid?: string
- artist_mbids?: string[]
- release_mbid?: string
- }
-}
-
-interface LastFmImage {
- size: string
- '#text': string
-}
-
-interface LastFmAlbum {
- image?: LastFmImage[]
-}
-
-interface LastFmTrack {
- album?: LastFmAlbum
-}
-
-interface LastFmResponse {
- album?: LastFmAlbum
- track?: LastFmTrack
-}
-
-interface NowPlayingData {
- track_name?: string
- artist_name?: string
- release_name?: string
- mbid?: string
- coverArt?: string | null
- lastFmData?: LastFmResponse
- status: 'loading' | 'partial' | 'complete' | 'error'
- message?: string
-}
-
-export class NowPlayingService {
- private readonly io: SocketServer
- private readonly lastFmApiKey: string | undefined
-
- constructor(io: SocketServer) {
- this.io = io
- this.lastFmApiKey = process.env.LASTFM_API_KEY
- }
-
- async fetchNowPlaying(socketId: string) {
- const emit = (data: Partial
) => {
- this.io.to(socketId).emit('nowPlaying', data)
- }
-
- try {
- emit({ status: 'loading', message: 'Fetching from ListenBrainz...' })
-
- const listenBrainzResponse = await fetch(
- 'https://api.listenbrainz.org/1/user/p0ntus/playing-now',
- {
- headers: process.env.LISTENBRAINZ_TOKEN
- ? { Authorization: `Token ${process.env.LISTENBRAINZ_TOKEN}` }
- : {}
- }
- )
-
- if (!listenBrainzResponse.ok) {
- emit({
- status: 'error',
- message: `ListenBrainz error: ${listenBrainzResponse.status}`
- })
- return
- }
-
- const listenBrainzData = await listenBrainzResponse.json()
-
- if (listenBrainzData.payload.count === 0) {
- emit({
- status: 'complete',
- message: 'No track currently playing'
- })
- return
- }
-
- const trackMetadata: TrackMetadata = listenBrainzData.payload.listens[0].track_metadata
-
- emit({
- status: 'partial',
- track_name: trackMetadata.track_name,
- artist_name: trackMetadata.artist_name,
- release_name: trackMetadata.release_name,
- mbid: trackMetadata.additional_info?.release_mbid,
- message: 'Fetching additional info...'
- })
-
- // Try to get data from Last.fm if MBID
- let lastFmData: LastFmResponse | null = null
- let lastFmCoverArt: string | null = null
-
- if (this.lastFmApiKey) {
- emit({ status: 'partial', message: 'Fetching from Last.fm...' })
-
- const lastFmQueries = []
-
- // Try with MBID if available
- if (trackMetadata.additional_info?.recording_mbid) {
- lastFmQueries.push(this.fetchLastFmByMbid(trackMetadata.additional_info.recording_mbid))
- }
-
- // Also try with track and artist name
- lastFmQueries.push(this.fetchLastFmByTrack(
- trackMetadata.artist_name,
- trackMetadata.track_name
- ))
-
- const lastFmResults = await Promise.allSettled(lastFmQueries)
-
- for (const result of lastFmResults) {
- if (result.status === 'fulfilled' && result.value) {
- lastFmData = result.value
- // Extract cover
- if (lastFmData.album?.image) {
- const images = lastFmData.album.image
- const largeImage = images.find((img: LastFmImage) => img.size === 'extralarge') ||
- images.find((img: LastFmImage) => img.size === 'large') ||
- images[images.length - 1]
- if (largeImage && largeImage['#text'] && largeImage['#text'].trim() !== '') {
- lastFmCoverArt = largeImage['#text']
- }
- } else if (lastFmData.track?.album?.image) {
- const images = lastFmData.track.album.image
- const largeImage = images.find((img: LastFmImage) => img.size === 'extralarge') ||
- images.find((img: LastFmImage) => img.size === 'large') ||
- images[images.length - 1]
- if (largeImage && largeImage['#text'] && largeImage['#text'].trim() !== '') {
- lastFmCoverArt = largeImage['#text']
- }
- }
- break
- }
- }
- }
-
- // Get album art
- let finalCoverArt = lastFmCoverArt
-
- if (!finalCoverArt) {
- if (trackMetadata.additional_info?.release_mbid) {
- emit({ status: 'partial', message: 'Fetching from Cover Art Archive...' })
-
- try {
- const coverArtResponse = await fetch(
- `https://coverartarchive.org/release/${trackMetadata.additional_info.release_mbid}/front`
- )
-
- if (coverArtResponse.ok) {
- finalCoverArt = coverArtResponse.url
- }
- } catch (error) {
- console.log('[!] Cover Art Archive direct fetch failed:', error)
- }
- }
-
- if (!finalCoverArt && trackMetadata.release_name && trackMetadata.artist_name) {
- emit({ status: 'partial', message: 'Searching MusicBrainz for album art...' })
-
- try {
- const mbSearchResponse = await fetch(
- `https://musicbrainz.org/ws/2/release/?query=artist:${encodeURIComponent(
- trackMetadata.artist_name
- )}%20AND%20release:${encodeURIComponent(trackMetadata.release_name)}&fmt=json&limit=1`
- )
-
- if (mbSearchResponse.ok) {
- const mbData = await mbSearchResponse.json()
-
- if (mbData.releases && mbData.releases.length > 0) {
- const releaseMbid = mbData.releases[0].id
-
- try {
- const coverArtResponse = await fetch(
- `https://coverartarchive.org/release/${releaseMbid}/front`
- )
-
- if (coverArtResponse.ok) {
- finalCoverArt = coverArtResponse.url
- }
- } catch (error) {
- console.log('[!] Cover Art Archive fallback fetch failed:', error)
- }
- }
- }
- } catch (error) {
- console.log('[!] MusicBrainz search failed:', error)
- }
- }
- }
-
- emit({
- status: 'complete',
- track_name: trackMetadata.track_name,
- artist_name: trackMetadata.artist_name,
- release_name: trackMetadata.release_name,
- mbid: trackMetadata.additional_info?.release_mbid || trackMetadata.mbid,
- coverArt: finalCoverArt || null,
- lastFmData: lastFmData || undefined,
- message: 'Complete'
- })
- } catch (error) {
- console.error('[!] Error in fetchNowPlaying:', error)
- emit({
- status: 'error',
- message: error instanceof Error ? error.message : 'Unknown error occurred'
- })
- }
- }
-
- private async fetchLastFmByMbid(mbid: string): Promise {
- if (!this.lastFmApiKey) return null
-
- try {
- const response = await fetch(
- `https://ws.audioscrobbler.com/2.0/?method=track.getInfoByMbid&mbid=${mbid}&api_key=${this.lastFmApiKey}&format=json`
- )
-
- if (response.ok) {
- return await response.json() as LastFmResponse
- }
- } catch (error) {
- console.log('[!] Last.fm MBID fetch failed:', error)
- }
-
- return null
- }
-
- private async fetchLastFmByTrack(artist: string, track: string): Promise {
- if (!this.lastFmApiKey) return null
-
- try {
- const params = new URLSearchParams({
- method: 'track.getInfo',
- api_key: this.lastFmApiKey,
- artist: artist,
- track: track,
- format: 'json',
- autocorrect: '1'
- })
-
- const response = await fetch(`https://ws.audioscrobbler.com/2.0/?${params}`)
-
- if (response.ok) {
- return await response.json() as LastFmResponse
- }
- } catch (error) {
- console.log('[!] Last.fm track fetch failed:', error)
- }
-
- return null
- }
-}
\ No newline at end of file
diff --git a/lib/socket.ts b/lib/socket.ts
deleted file mode 100644
index e1efc03..0000000
--- a/lib/socket.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-"use client"
-
-import { io, Socket } from "socket.io-client"
-
-let socket: Socket | null = null
-
-export const getSocket = (): Socket => {
- if (!socket) {
- socket = io(undefined, {
- autoConnect: false,
- })
- }
- return socket
-}
-
-export const connectSocket = (): Socket => {
- const s = getSocket()
- if (!s.connected) {
- s.connect()
- }
- return s
-}
-
-export const disconnectSocket = (): void => {
- if (socket?.connected) {
- socket.disconnect()
- }
-}
\ No newline at end of file
diff --git a/next.config.ts b/next.config.ts
index a23d318..ec75bba 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -16,6 +16,12 @@ const nextConfig: NextConfig = {
port: '',
pathname: '/**',
},
+ {
+ protocol: 'https',
+ hostname: '*.archive.org',
+ port: '',
+ pathname: '/**',
+ },
],
dangerouslyAllowSVG: true,
},
diff --git a/package-lock.json b/package-lock.json
index 912450d..3d0a20b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,33 +8,38 @@
"name": "aidxncc",
"version": "0.1.0",
"dependencies": {
- "@radix-ui/react-progress": "^1.1.7",
+ "@fortawesome/fontawesome-svg-core": "^6.7.2",
+ "@fortawesome/free-brands-svg-icons": "^6.7.2",
+ "@fortawesome/free-solid-svg-icons": "^6.7.2",
+ "@fortawesome/react-fontawesome": "^0.2.2",
+ "@radix-ui/react-progress": "^1.1.6",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"geist": "^1.4.2",
"i18next": "^24.2.3",
- "i18next-browser-languagedetector": "^8.2.0",
+ "i18next-browser-languagedetector": "^8.1.0",
"lucide-react": "^0.485.0",
- "next": "^15.4.5",
- "react": "^19.1.1",
- "react-dom": "^19.1.1",
- "react-i18next": "^15.6.1",
+ "next": "^15.3.4",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-fast-marquee": "^1.6.5",
+ "react-i18next": "^15.5.1",
"react-icons": "^5.5.0",
- "tailwind-merge": "^3.3.1",
+ "tailwind-merge": "^3.2.0",
"tailwindcss-animate": "^1.0.7",
- "tw-animate-css": "^1.3.6"
+ "tw-animate-css": "^1.2.9"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.1",
- "@tailwindcss/postcss": "^4.1.11",
- "@types/node": "^20.19.9",
- "@types/react": "^19.1.9",
- "@types/react-dom": "^19.1.7",
- "eslint": "^9.32.0",
+ "@tailwindcss/postcss": "^4.1.6",
+ "@types/node": "^20.17.46",
+ "@types/react": "^19.1.3",
+ "@types/react-dom": "^19.1.3",
+ "eslint": "^9.26.0",
"eslint-config-next": "15.1.3",
- "postcss": "^8.5.6",
- "tailwindcss": "^4.1.11",
- "typescript": "^5.9.2"
+ "postcss": "^8.5.3",
+ "tailwindcss": "^4.1.6",
+ "typescript": "^5.8.3"
}
},
"node_modules/@alloc/quick-lru": {
@@ -55,7 +60,6 @@
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
- "license": "Apache-2.0",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
@@ -65,9 +69,9 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.28.2",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz",
- "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz",
+ "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -86,9 +90,9 @@
}
},
"node_modules/@emnapi/runtime": {
- "version": "1.4.5",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz",
- "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==",
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
+ "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==",
"license": "MIT",
"optional": true,
"dependencies": {
@@ -149,9 +153,9 @@
}
},
"node_modules/@eslint/config-array": {
- "version": "0.21.0",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
- "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
+ "version": "0.20.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
+ "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -164,9 +168,9 @@
}
},
"node_modules/@eslint/config-helpers": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz",
- "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==",
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz",
+ "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -174,9 +178,9 @@
}
},
"node_modules/@eslint/core": {
- "version": "0.15.1",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz",
- "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==",
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
+ "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -211,16 +215,13 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.32.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz",
- "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==",
+ "version": "9.26.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.26.0.tgz",
+ "integrity": "sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://eslint.org/donate"
}
},
"node_modules/@eslint/object-schema": {
@@ -234,19 +235,77 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz",
- "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==",
+ "version": "0.2.8",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz",
+ "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^0.15.1",
+ "@eslint/core": "^0.13.0",
"levn": "^0.4.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@fortawesome/fontawesome-common-types": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
+ "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/fontawesome-svg-core": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
+ "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
+ "license": "MIT",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.7.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-brands-svg-icons": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz",
+ "integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==",
+ "license": "(CC-BY-4.0 AND MIT)",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.7.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-solid-svg-icons": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz",
+ "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==",
+ "license": "(CC-BY-4.0 AND MIT)",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.7.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/react-fontawesome": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz",
+ "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==",
+ "license": "MIT",
+ "dependencies": {
+ "prop-types": "^15.8.1"
+ },
+ "peerDependencies": {
+ "@fortawesome/fontawesome-svg-core": "~1 || ~6",
+ "react": ">=16.3"
+ }
+ },
"node_modules/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -314,9 +373,9 @@
}
},
"node_modules/@img/sharp-darwin-arm64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz",
- "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz",
+ "integrity": "sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==",
"cpu": [
"arm64"
],
@@ -332,13 +391,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-darwin-arm64": "1.2.0"
+ "@img/sharp-libvips-darwin-arm64": "1.1.0"
}
},
"node_modules/@img/sharp-darwin-x64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz",
- "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.1.tgz",
+ "integrity": "sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==",
"cpu": [
"x64"
],
@@ -354,13 +413,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-darwin-x64": "1.2.0"
+ "@img/sharp-libvips-darwin-x64": "1.1.0"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz",
- "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz",
+ "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==",
"cpu": [
"arm64"
],
@@ -374,9 +433,9 @@
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz",
- "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz",
+ "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==",
"cpu": [
"x64"
],
@@ -390,9 +449,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz",
- "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz",
+ "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==",
"cpu": [
"arm"
],
@@ -406,9 +465,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz",
- "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz",
+ "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==",
"cpu": [
"arm64"
],
@@ -422,9 +481,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-ppc64": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz",
- "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz",
+ "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==",
"cpu": [
"ppc64"
],
@@ -438,9 +497,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz",
- "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz",
+ "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==",
"cpu": [
"s390x"
],
@@ -454,9 +513,9 @@
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz",
- "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz",
+ "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==",
"cpu": [
"x64"
],
@@ -470,9 +529,9 @@
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz",
- "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz",
+ "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==",
"cpu": [
"arm64"
],
@@ -486,9 +545,9 @@
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz",
- "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz",
+ "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==",
"cpu": [
"x64"
],
@@ -502,9 +561,9 @@
}
},
"node_modules/@img/sharp-linux-arm": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz",
- "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.1.tgz",
+ "integrity": "sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==",
"cpu": [
"arm"
],
@@ -520,13 +579,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-arm": "1.2.0"
+ "@img/sharp-libvips-linux-arm": "1.1.0"
}
},
"node_modules/@img/sharp-linux-arm64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz",
- "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.1.tgz",
+ "integrity": "sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==",
"cpu": [
"arm64"
],
@@ -542,35 +601,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-arm64": "1.2.0"
- }
- },
- "node_modules/@img/sharp-linux-ppc64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz",
- "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==",
- "cpu": [
- "ppc64"
- ],
- "license": "Apache-2.0",
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/libvips"
- },
- "optionalDependencies": {
- "@img/sharp-libvips-linux-ppc64": "1.2.0"
+ "@img/sharp-libvips-linux-arm64": "1.1.0"
}
},
"node_modules/@img/sharp-linux-s390x": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz",
- "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.1.tgz",
+ "integrity": "sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==",
"cpu": [
"s390x"
],
@@ -586,13 +623,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-s390x": "1.2.0"
+ "@img/sharp-libvips-linux-s390x": "1.1.0"
}
},
"node_modules/@img/sharp-linux-x64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz",
- "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.1.tgz",
+ "integrity": "sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==",
"cpu": [
"x64"
],
@@ -608,13 +645,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linux-x64": "1.2.0"
+ "@img/sharp-libvips-linux-x64": "1.1.0"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz",
- "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.1.tgz",
+ "integrity": "sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==",
"cpu": [
"arm64"
],
@@ -630,13 +667,13 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linuxmusl-arm64": "1.2.0"
+ "@img/sharp-libvips-linuxmusl-arm64": "1.1.0"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz",
- "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.1.tgz",
+ "integrity": "sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==",
"cpu": [
"x64"
],
@@ -652,20 +689,20 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-libvips-linuxmusl-x64": "1.2.0"
+ "@img/sharp-libvips-linuxmusl-x64": "1.1.0"
}
},
"node_modules/@img/sharp-wasm32": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz",
- "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.1.tgz",
+ "integrity": "sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==",
"cpu": [
"wasm32"
],
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
- "@emnapi/runtime": "^1.4.4"
+ "@emnapi/runtime": "^1.4.0"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@@ -674,29 +711,10 @@
"url": "https://opencollective.com/libvips"
}
},
- "node_modules/@img/sharp-win32-arm64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz",
- "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==",
- "cpu": [
- "arm64"
- ],
- "license": "Apache-2.0 AND LGPL-3.0-or-later",
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/libvips"
- }
- },
"node_modules/@img/sharp-win32-ia32": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz",
- "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.1.tgz",
+ "integrity": "sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==",
"cpu": [
"ia32"
],
@@ -713,9 +731,9 @@
}
},
"node_modules/@img/sharp-win32-x64": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz",
- "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.1.tgz",
+ "integrity": "sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==",
"cpu": [
"x64"
],
@@ -736,7 +754,6 @@
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
"dev": true,
- "license": "ISC",
"dependencies": {
"minipass": "^7.0.4"
},
@@ -749,7 +766,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
"integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
@@ -760,7 +776,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6.0.0"
}
@@ -769,20 +784,40 @@
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
"integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
- "dev": true,
- "license": "MIT"
+ "dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.29",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
"integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@modelcontextprotocol/sdk": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz",
+ "integrity": "sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "cors": "^2.8.5",
+ "cross-spawn": "^7.0.3",
+ "eventsource": "^3.0.2",
+ "express": "^5.0.1",
+ "express-rate-limit": "^7.5.0",
+ "pkce-challenge": "^5.0.0",
+ "raw-body": "^3.0.0",
+ "zod": "^3.23.8",
+ "zod-to-json-schema": "^3.24.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.9.tgz",
@@ -797,10 +832,9 @@
}
},
"node_modules/@next/env": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.5.tgz",
- "integrity": "sha512-ruM+q2SCOVCepUiERoxOmZY9ZVoecR3gcXNwCYZRvQQWRjhOiPJGmQ2fAiLR6YKWXcSAh7G79KEFxN3rwhs4LQ==",
- "license": "MIT"
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.4.tgz",
+ "integrity": "sha512-ZkdYzBseS6UjYzz6ylVKPOK+//zLWvD6Ta+vpoye8cW11AjiQjGYVibF0xuvT4L0iJfAPfZLFidaEzAOywyOAQ=="
},
"node_modules/@next/eslint-plugin-next": {
"version": "15.1.3",
@@ -813,13 +847,12 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.5.tgz",
- "integrity": "sha512-84dAN4fkfdC7nX6udDLz9GzQlMUwEMKD7zsseXrl7FTeIItF8vpk1lhLEnsotiiDt+QFu3O1FVWnqwcRD2U3KA==",
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.4.tgz",
+ "integrity": "sha512-z0qIYTONmPRbwHWvpyrFXJd5F9YWLCsw3Sjrzj2ZvMYy9NPQMPZ1NjOJh4ojr4oQzcGYwgJKfidzehaNa1BpEg==",
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -829,13 +862,12 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.5.tgz",
- "integrity": "sha512-CL6mfGsKuFSyQjx36p2ftwMNSb8PQog8y0HO/ONLdQqDql7x3aJb/wB+LA651r4we2pp/Ck+qoRVUeZZEvSurA==",
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.4.tgz",
+ "integrity": "sha512-Z0FYJM8lritw5Wq+vpHYuCIzIlEMjewG2aRkc3Hi2rcbULknYL/xqfpBL23jQnCSrDUGAo/AEv0Z+s2bff9Zkw==",
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -845,13 +877,12 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.5.tgz",
- "integrity": "sha512-1hTVd9n6jpM/thnDc5kYHD1OjjWYpUJrJxY4DlEacT7L5SEOXIifIdTye6SQNNn8JDZrcN+n8AWOmeJ8u3KlvQ==",
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.4.tgz",
+ "integrity": "sha512-l8ZQOCCg7adwmsnFm8m5q9eIPAHdaB2F3cxhufYtVo84pymwKuWfpYTKcUiFcutJdp9xGHC+F1Uq3xnFU1B/7g==",
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -861,13 +892,12 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.5.tgz",
- "integrity": "sha512-4W+D/nw3RpIwGrqpFi7greZ0hjrCaioGErI7XHgkcTeWdZd146NNu1s4HnaHonLeNTguKnL2Urqvj28UJj6Gqw==",
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.4.tgz",
+ "integrity": "sha512-wFyZ7X470YJQtpKot4xCY3gpdn8lE9nTlldG07/kJYexCUpX1piX+MBfZdvulo+t1yADFVEuzFfVHfklfEx8kw==",
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -877,13 +907,12 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.5.tgz",
- "integrity": "sha512-N6Mgdxe/Cn2K1yMHge6pclffkxzbSGOydXVKYOjYqQXZYjLCfN/CuFkaYDeDHY2VBwSHyM2fUjYBiQCIlxIKDA==",
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.4.tgz",
+ "integrity": "sha512-gEbH9rv9o7I12qPyvZNVTyP/PWKqOp8clvnoYZQiX800KkqsaJZuOXkWgMa7ANCCh/oEN2ZQheh3yH8/kWPSEg==",
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -893,13 +922,12 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.5.tgz",
- "integrity": "sha512-YZ3bNDrS8v5KiqgWE0xZQgtXgCTUacgFtnEgI4ccotAASwSvcMPDLua7BWLuTfucoRv6mPidXkITJLd8IdJplQ==",
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.4.tgz",
+ "integrity": "sha512-Cf8sr0ufuC/nu/yQ76AnarbSAXcwG/wj+1xFPNbyNo8ltA6kw5d5YqO8kQuwVIxk13SBdtgXrNyom3ZosHAy4A==",
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -909,13 +937,12 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.5.tgz",
- "integrity": "sha512-9Wr4t9GkZmMNcTVvSloFtjzbH4vtT4a8+UHqDoVnxA5QyfWe6c5flTH1BIWPGNWSUlofc8dVJAE7j84FQgskvQ==",
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.4.tgz",
+ "integrity": "sha512-ay5+qADDN3rwRbRpEhTOreOn1OyJIXS60tg9WMYTWCy3fB6rGoyjLVxc4dR9PYjEdR2iDYsaF5h03NA+XuYPQQ==",
"cpu": [
"arm64"
],
- "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -925,13 +952,12 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.5.tgz",
- "integrity": "sha512-voWk7XtGvlsP+w8VBz7lqp8Y+dYw/MTI4KeS0gTVtfdhdJ5QwhXLmNrndFOin/MDoCvUaLWMkYKATaCoUkt2/A==",
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.4.tgz",
+ "integrity": "sha512-4kDt31Bc9DGyYs41FTL1/kNpDeHyha2TC0j5sRRoKCyrhNcfZ/nRQkAUlF27mETwm8QyHqIjHJitfcza2Iykfg==",
"cpu": [
"x64"
],
- "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1019,12 +1045,12 @@
}
},
"node_modules/@radix-ui/react-primitive": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
- "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.2.tgz",
+ "integrity": "sha512-uHa+l/lKfxuDD2zjN/0peM/RhhSmRjr5YWdk/37EnSv1nJ88uvG85DPexSm8HdFQROd2VdERJ6ynXbkCFi+APw==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-slot": "1.2.3"
+ "@radix-ui/react-slot": "1.2.2"
},
"peerDependencies": {
"@types/react": "*",
@@ -1042,13 +1068,13 @@
}
},
"node_modules/@radix-ui/react-progress": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz",
- "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==",
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.6.tgz",
+ "integrity": "sha512-QzN9a36nKk2eZKMf9EBCia35x3TT+SOgZuzQBVIHyRrmYYi73VYBRK3zKwdJ6az/F5IZ6QlacGJBg7zfB85liA==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-context": "1.1.2",
- "@radix-ui/react-primitive": "2.1.3"
+ "@radix-ui/react-primitive": "2.1.2"
},
"peerDependencies": {
"@types/react": "*",
@@ -1066,9 +1092,9 @@
}
},
"node_modules/@radix-ui/react-slot": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
- "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.2.tgz",
+ "integrity": "sha512-y7TBO4xN4Y94FvcWIOIh18fM4R1A8S4q1jhoz4PNzOoHsFcN8pogcFmZrTYAm4F9VRUrWP/Mw7xSKybIeRI+CQ==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.2"
@@ -1097,6 +1123,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@swc/counter": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+ "license": "Apache-2.0"
+ },
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -1111,7 +1143,6 @@
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz",
"integrity": "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.3.0",
"enhanced-resolve": "^5.18.1",
@@ -1128,7 +1159,6 @@
"integrity": "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==",
"dev": true,
"hasInstallScript": true,
- "license": "MIT",
"dependencies": {
"detect-libc": "^2.0.4",
"tar": "^7.4.3"
@@ -1159,7 +1189,6 @@
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"android"
@@ -1176,7 +1205,6 @@
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -1193,7 +1221,6 @@
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -1210,7 +1237,6 @@
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"freebsd"
@@ -1227,7 +1253,6 @@
"arm"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1244,7 +1269,6 @@
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1261,7 +1285,6 @@
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1278,7 +1301,6 @@
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1295,7 +1317,6 @@
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1320,7 +1341,6 @@
"wasm32"
],
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.4.3",
@@ -1334,6 +1354,66 @@
"node": ">=14.0.0"
}
},
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
+ "version": "1.4.3",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.0.2",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.4.3",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
+ "version": "1.0.2",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
+ "version": "0.2.11",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@tybys/wasm-util": "^0.9.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
+ "version": "0.9.0",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
+ "version": "2.8.0",
+ "dev": true,
+ "inBundle": true,
+ "license": "0BSD",
+ "optional": true
+ },
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz",
@@ -1342,7 +1422,6 @@
"arm64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1359,7 +1438,6 @@
"x64"
],
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1373,7 +1451,6 @@
"resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.11.tgz",
"integrity": "sha512-q/EAIIpF6WpLhKEuQSEVMZNMIY8KhWoAemZ9eylNAih9jxMGAYPPWBn3I9QL/2jZ+e7OEz/tZkX5HwbBR4HohA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"@tailwindcss/node": "4.1.11",
@@ -1415,19 +1492,19 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "20.19.9",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz",
- "integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==",
+ "version": "20.17.46",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.46.tgz",
+ "integrity": "sha512-0PQHLhZPWOxGW4auogW0eOQAuNIlCYvibIpG67ja0TOJ6/sehu+1en7sfceUn+QQtx4Rk3GxbLNwPh0Cav7TWw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~6.21.0"
+ "undici-types": "~6.19.2"
}
},
"node_modules/@types/react": {
- "version": "19.1.9",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz",
- "integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==",
+ "version": "19.1.3",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.3.tgz",
+ "integrity": "sha512-dLWQ+Z0CkIvK1J8+wrDPwGxEYFA4RAyHoZPxHVGspYmFVnwGSNT24cGIhFJrtfRnWVuW8X7NO52gCXmhkVUWGQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -1435,24 +1512,31 @@
}
},
"node_modules/@types/react-dom": {
- "version": "19.1.7",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz",
- "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==",
+ "version": "19.1.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.3.tgz",
+ "integrity": "sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg==",
"devOptional": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^19.0.0"
}
},
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz",
- "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==",
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz",
+ "integrity": "sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0"
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "8.32.0",
+ "@typescript-eslint/type-utils": "8.32.0",
+ "@typescript-eslint/utils": "8.32.0",
+ "@typescript-eslint/visitor-keys": "8.32.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.3.1",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.1.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1460,12 +1544,84 @@
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.0.tgz",
+ "integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.32.0",
+ "@typescript-eslint/types": "8.32.0",
+ "@typescript-eslint/typescript-estree": "8.32.0",
+ "@typescript-eslint/visitor-keys": "8.32.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.0.tgz",
+ "integrity": "sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.32.0",
+ "@typescript-eslint/visitor-keys": "8.32.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.0.tgz",
+ "integrity": "sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "8.32.0",
+ "@typescript-eslint/utils": "8.32.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz",
- "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==",
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.0.tgz",
+ "integrity": "sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1476,15 +1632,122 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz",
- "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==",
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.0.tgz",
+ "integrity": "sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.38.0",
- "eslint-visitor-keys": "^4.2.1"
+ "@typescript-eslint/types": "8.32.0",
+ "@typescript-eslint/visitor-keys": "8.32.0",
+ "debug": "^4.3.4",
+ "fast-glob": "^3.3.2",
+ "is-glob": "^4.0.3",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.0.tgz",
+ "integrity": "sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.7.0",
+ "@typescript-eslint/scope-manager": "8.32.0",
+ "@typescript-eslint/types": "8.32.0",
+ "@typescript-eslint/typescript-estree": "8.32.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.32.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.0.tgz",
+ "integrity": "sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.32.0",
+ "eslint-visitor-keys": "^4.2.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1735,10 +1998,24 @@
"win32"
]
},
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "version": "8.14.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
+ "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"license": "MIT",
"bin": {
@@ -2026,6 +2303,27 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -2050,6 +2348,27 @@
"node": ">=8"
}
},
+ "node_modules/busboy": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+ "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+ "dependencies": {
+ "streamsearch": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
@@ -2152,7 +2471,6 @@
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
"dev": true,
- "license": "BlueOak-1.0.0",
"engines": {
"node": ">=18"
}
@@ -2236,6 +2554,63 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -2380,6 +2755,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/detect-libc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
@@ -2418,6 +2803,13 @@
"node": ">= 0.4"
}
},
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
@@ -2425,12 +2817,21 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.18.2",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
"integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -2613,6 +3014,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -2627,23 +3035,24 @@
}
},
"node_modules/eslint": {
- "version": "9.32.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz",
- "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==",
+ "version": "9.26.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.26.0.tgz",
+ "integrity": "sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
- "@eslint/config-array": "^0.21.0",
- "@eslint/config-helpers": "^0.3.0",
- "@eslint/core": "^0.15.0",
+ "@eslint/config-array": "^0.20.0",
+ "@eslint/config-helpers": "^0.2.1",
+ "@eslint/core": "^0.13.0",
"@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.32.0",
- "@eslint/plugin-kit": "^0.3.4",
+ "@eslint/js": "9.26.0",
+ "@eslint/plugin-kit": "^0.2.8",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
+ "@modelcontextprotocol/sdk": "^1.8.0",
"@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15",
"ajv": "^6.12.4",
@@ -2651,9 +3060,9 @@
"cross-spawn": "^7.0.6",
"debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^8.4.0",
- "eslint-visitor-keys": "^4.2.1",
- "espree": "^10.4.0",
+ "eslint-scope": "^8.3.0",
+ "eslint-visitor-keys": "^4.2.0",
+ "espree": "^10.3.0",
"esquery": "^1.5.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@@ -2667,7 +3076,8 @@
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.3"
+ "optionator": "^0.9.3",
+ "zod": "^3.24.2"
},
"bin": {
"eslint": "bin/eslint.js"
@@ -2715,380 +3125,6 @@
}
}
},
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz",
- "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.38.0",
- "@typescript-eslint/type-utils": "8.38.0",
- "@typescript-eslint/utils": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0",
- "graphemer": "^1.4.0",
- "ignore": "^7.0.0",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^8.38.0",
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz",
- "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/typescript-estree": "8.38.0",
- "@typescript-eslint/utils": "8.38.0",
- "debug": "^4.3.4",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz",
- "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/project-service": "8.38.0",
- "@typescript-eslint/tsconfig-utils": "8.38.0",
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz",
- "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.38.0",
- "@typescript-eslint/types": "^8.38.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz",
- "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz",
- "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.38.0",
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/typescript-estree": "8.38.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz",
- "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/project-service": "8.38.0",
- "@typescript-eslint/tsconfig-utils": "8.38.0",
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz",
- "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.38.0",
- "@typescript-eslint/types": "^8.38.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz",
- "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/parser": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz",
- "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.38.0",
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/typescript-estree": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz",
- "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/project-service": "8.38.0",
- "@typescript-eslint/tsconfig-utils": "8.38.0",
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz",
- "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.38.0",
- "@typescript-eslint/types": "^8.38.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz",
- "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/fast-glob": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
- "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.8"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/eslint-config-next/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/eslint-config-next/node_modules/ignore": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
- "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/eslint-config-next/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/eslint-import-resolver-node": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
@@ -3333,9 +3369,9 @@
}
},
"node_modules/eslint-scope": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
- "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
+ "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
@@ -3350,9 +3386,9 @@
}
},
"node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+ "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -3363,15 +3399,15 @@
}
},
"node_modules/espree": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
- "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "version": "10.3.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
+ "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
- "acorn": "^8.15.0",
+ "acorn": "^8.14.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.1"
+ "eslint-visitor-keys": "^4.2.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3426,6 +3462,98 @@
"node": ">=0.10.0"
}
},
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/eventsource": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.6.tgz",
+ "integrity": "sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eventsource-parser": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/eventsource-parser": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.1.tgz",
+ "integrity": "sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/express": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express-rate-limit": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz",
+ "integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/express-rate-limit"
+ },
+ "peerDependencies": {
+ "express": "^4.11 || 5 || ^5.0.0-beta.1"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -3513,6 +3641,24 @@
"node": ">=8"
}
},
+ "node_modules/finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -3567,6 +3713,26 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -3747,8 +3913,7 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true,
- "license": "ISC"
+ "dev": true
},
"node_modules/graphemer": {
"version": "1.4.0",
@@ -3860,6 +4025,23 @@
"void-elements": "3.1.0"
}
},
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/i18next": {
"version": "24.2.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-24.2.3.tgz",
@@ -3892,14 +4074,27 @@
}
},
"node_modules/i18next-browser-languagedetector": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz",
- "integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.1.0.tgz",
+ "integrity": "sha512-mHZxNx1Lq09xt5kCauZ/4bsXOEA2pfpwSoU11/QTJB+pD94iONFwp+ohqi///PwiFvjFOxe1akYCdHyFo1ng5Q==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.2"
}
},
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -3937,6 +4132,13 @@
"node": ">=0.8.19"
}
},
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -3952,6 +4154,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -4202,6 +4414,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -4393,7 +4612,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
@@ -4508,7 +4726,6 @@
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
"integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
"dev": true,
- "license": "MPL-2.0",
"dependencies": {
"detect-libc": "^2.0.3"
},
@@ -4540,7 +4757,6 @@
"arm64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
@@ -4561,7 +4777,6 @@
"x64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
@@ -4582,7 +4797,6 @@
"x64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"freebsd"
@@ -4603,7 +4817,6 @@
"arm"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"linux"
@@ -4624,7 +4837,6 @@
"arm64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"linux"
@@ -4645,7 +4857,6 @@
"arm64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"linux"
@@ -4666,7 +4877,6 @@
"x64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"linux"
@@ -4687,7 +4897,6 @@
"x64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"linux"
@@ -4708,7 +4917,6 @@
"arm64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"win32"
@@ -4729,7 +4937,6 @@
"x64"
],
"dev": true,
- "license": "MPL-2.0",
"optional": true,
"os": [
"win32"
@@ -4769,7 +4976,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
"license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
@@ -4792,7 +4998,6 @@
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0"
}
@@ -4807,6 +5012,29 @@
"node": ">= 0.4"
}
},
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -4831,6 +5059,29 @@
"node": ">=8.6"
}
},
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -4859,7 +5110,6 @@
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"dev": true,
- "license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
@@ -4869,7 +5119,6 @@
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"minipass": "^7.1.2"
},
@@ -4882,7 +5131,6 @@
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
"dev": true,
- "license": "MIT",
"bin": {
"mkdirp": "dist/cjs/src/bin.js"
},
@@ -4941,14 +5189,25 @@
"dev": true,
"license": "MIT"
},
- "node_modules/next": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/next/-/next-15.4.5.tgz",
- "integrity": "sha512-nJ4v+IO9CPmbmcvsPebIoX3Q+S7f6Fu08/dEWu0Ttfa+wVwQRh9epcmsyCPjmL2b8MxC+CkBR97jgDhUUztI3g==",
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "dev": true,
"license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/next": {
+ "version": "15.3.4",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.3.4.tgz",
+ "integrity": "sha512-mHKd50C+mCjam/gcnwqL1T1vPx/XQNFlXqFIVdgQdVAFY9iIQtY0IfaVflEYzKiqjeA7B0cYYMaCrmAYFjs4rA==",
"dependencies": {
- "@next/env": "15.4.5",
+ "@next/env": "15.3.4",
+ "@swc/counter": "0.1.3",
"@swc/helpers": "0.5.15",
+ "busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
"styled-jsx": "5.1.6"
@@ -4960,19 +5219,19 @@
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "15.4.5",
- "@next/swc-darwin-x64": "15.4.5",
- "@next/swc-linux-arm64-gnu": "15.4.5",
- "@next/swc-linux-arm64-musl": "15.4.5",
- "@next/swc-linux-x64-gnu": "15.4.5",
- "@next/swc-linux-x64-musl": "15.4.5",
- "@next/swc-win32-arm64-msvc": "15.4.5",
- "@next/swc-win32-x64-msvc": "15.4.5",
- "sharp": "^0.34.3"
+ "@next/swc-darwin-arm64": "15.3.4",
+ "@next/swc-darwin-x64": "15.3.4",
+ "@next/swc-linux-arm64-gnu": "15.3.4",
+ "@next/swc-linux-arm64-musl": "15.3.4",
+ "@next/swc-linux-x64-gnu": "15.3.4",
+ "@next/swc-linux-x64-musl": "15.3.4",
+ "@next/swc-win32-arm64-msvc": "15.3.4",
+ "@next/swc-win32-x64-msvc": "15.3.4",
+ "sharp": "^0.34.1"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
- "@playwright/test": "^1.51.1",
+ "@playwright/test": "^1.41.2",
"babel-plugin-react-compiler": "*",
"react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
"react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
@@ -5025,7 +5284,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -5144,6 +5402,29 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -5225,6 +5506,16 @@
"node": ">=6"
}
},
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -5252,6 +5543,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/path-to-regexp": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
+ "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -5271,6 +5572,16 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pkce-challenge": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
+ "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -5282,9 +5593,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.6",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
- "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
+ "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true,
"funding": [
{
@@ -5302,7 +5613,7 @@
],
"license": "MIT",
"dependencies": {
- "nanoid": "^3.3.11",
+ "nanoid": "^3.3.8",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
@@ -5324,7 +5635,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
@@ -5332,6 +5642,20 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -5342,6 +5666,22 @@
"node": ">=6"
}
},
+ "node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -5363,34 +5703,70 @@
],
"license": "MIT"
},
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
+ "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.6.3",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/react": {
- "version": "19.1.1",
- "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
- "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
+ "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
- "version": "19.1.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
- "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
+ "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
"license": "MIT",
"dependencies": {
"scheduler": "^0.26.0"
},
"peerDependencies": {
- "react": "^19.1.1"
+ "react": "^19.1.0"
+ }
+ },
+ "node_modules/react-fast-marquee": {
+ "version": "1.6.5",
+ "resolved": "https://registry.npmjs.org/react-fast-marquee/-/react-fast-marquee-1.6.5.tgz",
+ "integrity": "sha512-swDnPqrT2XISAih0o74zQVE2wQJFMvkx+9VZXYYNSLb/CUcAzU9pNj637Ar2+hyRw6b4tP6xh4GQZip2ZCpQpg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">= 16.8.0 || ^18.0.0",
+ "react-dom": ">= 16.8.0 || ^18.0.0"
}
},
"node_modules/react-i18next": {
- "version": "15.6.1",
- "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.6.1.tgz",
- "integrity": "sha512-uGrzSsOUUe2sDBG/+FJq2J1MM+Y4368/QW8OLEKSFvnDflHBbZhSd1u3UkW0Z06rMhZmnB/AQrhCpYfE5/5XNg==",
+ "version": "15.5.1",
+ "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.1.tgz",
+ "integrity": "sha512-C8RZ7N7H0L+flitiX6ASjq9p5puVJU1Z8VyL3OgM/QOMRf40BMZX+5TkpxzZVcTmOLPX5zlti4InEX5pFyiVeA==",
"license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.27.6",
+ "@babel/runtime": "^7.25.0",
"html-parse-stringify": "^3.0.1"
},
"peerDependencies": {
@@ -5423,7 +5799,6 @@
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/reflect.getprototypeof": {
@@ -5522,6 +5897,23 @@
"node": ">=0.10.0"
}
},
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -5566,6 +5958,27 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/safe-push-apply": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
@@ -5601,6 +6014,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/scheduler": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
@@ -5608,9 +6028,9 @@
"license": "MIT"
},
"node_modules/semver": {
- "version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"devOptional": true,
"license": "ISC",
"bin": {
@@ -5620,6 +6040,45 @@
"node": ">=10"
}
},
+ "node_modules/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -5669,17 +6128,24 @@
"node": ">= 0.4"
}
},
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/sharp": {
- "version": "0.34.3",
- "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz",
- "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==",
+ "version": "0.34.1",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.1.tgz",
+ "integrity": "sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==",
"hasInstallScript": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"color": "^4.2.3",
- "detect-libc": "^2.0.4",
- "semver": "^7.7.2"
+ "detect-libc": "^2.0.3",
+ "semver": "^7.7.1"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@@ -5688,28 +6154,26 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
- "@img/sharp-darwin-arm64": "0.34.3",
- "@img/sharp-darwin-x64": "0.34.3",
- "@img/sharp-libvips-darwin-arm64": "1.2.0",
- "@img/sharp-libvips-darwin-x64": "1.2.0",
- "@img/sharp-libvips-linux-arm": "1.2.0",
- "@img/sharp-libvips-linux-arm64": "1.2.0",
- "@img/sharp-libvips-linux-ppc64": "1.2.0",
- "@img/sharp-libvips-linux-s390x": "1.2.0",
- "@img/sharp-libvips-linux-x64": "1.2.0",
- "@img/sharp-libvips-linuxmusl-arm64": "1.2.0",
- "@img/sharp-libvips-linuxmusl-x64": "1.2.0",
- "@img/sharp-linux-arm": "0.34.3",
- "@img/sharp-linux-arm64": "0.34.3",
- "@img/sharp-linux-ppc64": "0.34.3",
- "@img/sharp-linux-s390x": "0.34.3",
- "@img/sharp-linux-x64": "0.34.3",
- "@img/sharp-linuxmusl-arm64": "0.34.3",
- "@img/sharp-linuxmusl-x64": "0.34.3",
- "@img/sharp-wasm32": "0.34.3",
- "@img/sharp-win32-arm64": "0.34.3",
- "@img/sharp-win32-ia32": "0.34.3",
- "@img/sharp-win32-x64": "0.34.3"
+ "@img/sharp-darwin-arm64": "0.34.1",
+ "@img/sharp-darwin-x64": "0.34.1",
+ "@img/sharp-libvips-darwin-arm64": "1.1.0",
+ "@img/sharp-libvips-darwin-x64": "1.1.0",
+ "@img/sharp-libvips-linux-arm": "1.1.0",
+ "@img/sharp-libvips-linux-arm64": "1.1.0",
+ "@img/sharp-libvips-linux-ppc64": "1.1.0",
+ "@img/sharp-libvips-linux-s390x": "1.1.0",
+ "@img/sharp-libvips-linux-x64": "1.1.0",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.1.0",
+ "@img/sharp-libvips-linuxmusl-x64": "1.1.0",
+ "@img/sharp-linux-arm": "0.34.1",
+ "@img/sharp-linux-arm64": "0.34.1",
+ "@img/sharp-linux-s390x": "0.34.1",
+ "@img/sharp-linux-x64": "0.34.1",
+ "@img/sharp-linuxmusl-arm64": "0.34.1",
+ "@img/sharp-linuxmusl-x64": "0.34.1",
+ "@img/sharp-wasm32": "0.34.1",
+ "@img/sharp-win32-ia32": "0.34.1",
+ "@img/sharp-win32-x64": "0.34.1"
}
},
"node_modules/shebang-command": {
@@ -5837,6 +6301,24 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/streamsearch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/string.prototype.includes": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
@@ -6023,9 +6505,9 @@
}
},
"node_modules/tailwind-merge": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
- "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.2.0.tgz",
+ "integrity": "sha512-FQT/OVqCD+7edmmJpsgCsY820RTD5AkBryuG5IUqR5YQZSdj5xlH5nLgH7YPths7WsLPSpSBNneJdM8aS8aeFA==",
"license": "MIT",
"funding": {
"type": "github",
@@ -6035,8 +6517,7 @@
"node_modules/tailwindcss": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz",
- "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==",
- "license": "MIT"
+ "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="
},
"node_modules/tailwindcss-animate": {
"version": "1.0.7",
@@ -6052,7 +6533,6 @@
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
"integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -6062,7 +6542,6 @@
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
"dev": true,
- "license": "ISC",
"dependencies": {
"@isaacs/fs-minipass": "^4.0.0",
"chownr": "^3.0.0",
@@ -6133,6 +6612,16 @@
"node": ">=8.0"
}
},
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
"node_modules/ts-api-utils": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
@@ -6166,9 +6655,9 @@
"license": "0BSD"
},
"node_modules/tw-animate-css": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.6.tgz",
- "integrity": "sha512-9dy0R9UsYEGmgf26L8UcHiLmSFTHa9+D7+dAt/G/sF5dCnPePZbfgDYinc7/UzAM7g/baVrmS6m9yEpU46d+LA==",
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.2.9.tgz",
+ "integrity": "sha512-9O4k1at9pMQff9EAcCEuy1UNO43JmaPQvq+0lwza9Y0BQ6LB38NiMj+qHqjoQf40355MX+gs6wtlR6H9WsSXFg==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/Wombosvideo"
@@ -6187,6 +6676,21 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
@@ -6266,9 +6770,9 @@
}
},
"node_modules/typescript": {
- "version": "5.9.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
- "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
@@ -6299,12 +6803,22 @@
}
},
"node_modules/undici-types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
- "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"license": "MIT"
},
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/unrs-resolver": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.2.tgz",
@@ -6348,6 +6862,16 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
@@ -6472,12 +6996,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/yallist": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
"dev": true,
- "license": "BlueOak-1.0.0",
"engines": {
"node": ">=18"
}
@@ -6494,6 +7024,26 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zod": {
+ "version": "3.24.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.4.tgz",
+ "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-to-json-schema": {
+ "version": "3.24.5",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz",
+ "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==",
+ "dev": true,
+ "license": "ISC",
+ "peerDependencies": {
+ "zod": "^3.24.1"
+ }
}
}
}
diff --git a/package.json b/package.json
index 4c45b57..d43a153 100644
--- a/package.json
+++ b/package.json
@@ -3,43 +3,44 @@
"version": "0.1.0",
"private": true,
"scripts": {
- "dev": "bun run server.ts",
+ "dev": "next dev --turbopack",
"build": "next build",
- "start": "NODE_ENV=production bun run server.ts",
+ "start": "next start",
"lint": "next lint"
},
"dependencies": {
- "@radix-ui/react-progress": "^1.1.7",
+ "@fortawesome/fontawesome-svg-core": "^6.7.2",
+ "@fortawesome/free-brands-svg-icons": "^6.7.2",
+ "@fortawesome/free-solid-svg-icons": "^6.7.2",
+ "@fortawesome/react-fontawesome": "^0.2.2",
+ "@radix-ui/react-progress": "^1.1.6",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
- "geist": "^1.5.1",
+ "geist": "^1.4.2",
"i18next": "^24.2.3",
- "i18next-browser-languagedetector": "^8.2.0",
+ "i18next-browser-languagedetector": "^8.1.0",
"lucide-react": "^0.485.0",
- "next": "^15.5.3",
- "react": "^19.1.1",
- "react-dom": "^19.1.1",
- "react-i18next": "^15.7.3",
+ "next": "^15.3.4",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-fast-marquee": "^1.6.5",
+ "react-i18next": "^15.5.1",
"react-icons": "^5.5.0",
- "recharts": "^3.2.0",
- "socket.io": "^4.8.1",
- "socket.io-client": "^4.8.1",
- "tailwind-merge": "^3.3.1",
+ "tailwind-merge": "^3.2.0",
"tailwindcss-animate": "^1.0.7",
- "tw-animate-css": "^1.3.8"
+ "tw-animate-css": "^1.2.9"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.1",
- "@tailwindcss/postcss": "^4.1.13",
- "@types/node": "^24.4.0",
- "@types/react": "^19.1.13",
- "@types/react-dom": "^19.1.9",
- "eslint": "^9.35.0",
+ "@tailwindcss/postcss": "^4.1.6",
+ "@types/node": "^20.17.46",
+ "@types/react": "^19.1.3",
+ "@types/react-dom": "^19.1.3",
+ "eslint": "^9.26.0",
"eslint-config-next": "15.1.3",
- "postcss": "^8.5.6",
- "tailwindcss": "^4.1.13",
- "tsx": "^4.20.5",
- "typescript": "^5.9.2"
+ "postcss": "^8.5.3",
+ "tailwindcss": "^4.1.6",
+ "typescript": "^5.8.3"
},
"trustedDependencies": [
"sharp",
diff --git a/public/data/cc.json b/public/data/cc.json
deleted file mode 100644
index fb1adba..0000000
--- a/public/data/cc.json
+++ /dev/null
@@ -1,857 +0,0 @@
-{
- "daily": [
- {
- "date": "2025-08-08",
- "inputTokens": 14919,
- "outputTokens": 23378,
- "cacheCreationTokens": 480031,
- "cacheReadTokens": 11034031,
- "totalTokens": 11552359,
- "totalCost": 6.777273749999996,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 4837,
- "outputTokens": 20788,
- "cacheCreationTokens": 443453,
- "cacheReadTokens": 10661975,
- "cost": 5.18787225
- },
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 10082,
- "outputTokens": 2590,
- "cacheCreationTokens": 36578,
- "cacheReadTokens": 372056,
- "cost": 1.5894014999999997
- }
- ]
- },
- {
- "date": "2025-08-09",
- "inputTokens": 3142,
- "outputTokens": 20594,
- "cacheCreationTokens": 513312,
- "cacheReadTokens": 13270007,
- "totalTokens": 13807055,
- "totalCost": 20.561232300000007,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 373,
- "outputTokens": 10485,
- "cacheCreationTokens": 294339,
- "cacheReadTokens": 7740261,
- "cost": 17.92121775
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 2769,
- "outputTokens": 10109,
- "cacheCreationTokens": 218973,
- "cacheReadTokens": 5529746,
- "cost": 2.640014549999999
- }
- ]
- },
- {
- "date": "2025-08-10",
- "inputTokens": 2384,
- "outputTokens": 33087,
- "cacheCreationTokens": 752268,
- "cacheReadTokens": 12833548,
- "totalTokens": 13621287,
- "totalCost": 24.83825640000001,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 983,
- "outputTokens": 24065,
- "cacheCreationTokens": 320876,
- "cacheReadTokens": 9495745,
- "cost": 22.079662499999998
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 1401,
- "outputTokens": 9022,
- "cacheCreationTokens": 431392,
- "cacheReadTokens": 3337803,
- "cost": 2.7585938999999993
- }
- ]
- },
- {
- "date": "2025-08-11",
- "inputTokens": 1127,
- "outputTokens": 23663,
- "cacheCreationTokens": 746606,
- "cacheReadTokens": 10310633,
- "totalTokens": 11082029,
- "totalCost": 31.256441999999993,
- "modelsUsed": [
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 1127,
- "outputTokens": 23663,
- "cacheCreationTokens": 746606,
- "cacheReadTokens": 10310633,
- "cost": 31.256441999999993
- }
- ]
- },
- {
- "date": "2025-08-12",
- "inputTokens": 17245,
- "outputTokens": 164864,
- "cacheCreationTokens": 2646250,
- "cacheReadTokens": 49767559,
- "totalTokens": 52595918,
- "totalCost": 85.49760780000005,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 13710,
- "outputTokens": 77330,
- "cacheCreationTokens": 1413354,
- "cacheReadTokens": 26762148,
- "cost": 72.64900950000008
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 3535,
- "outputTokens": 87534,
- "cacheCreationTokens": 1232896,
- "cacheReadTokens": 23005411,
- "cost": 12.848598300000004
- }
- ]
- },
- {
- "date": "2025-08-13",
- "inputTokens": 29365,
- "outputTokens": 23237,
- "cacheCreationTokens": 1034891,
- "cacheReadTokens": 7332169,
- "totalTokens": 8419662,
- "totalCost": 9.039594749999997,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 24909,
- "outputTokens": 18462,
- "cacheCreationTokens": 935307,
- "cacheReadTokens": 6758235,
- "cost": 5.886528749999999
- },
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 4456,
- "outputTokens": 4775,
- "cacheCreationTokens": 99584,
- "cacheReadTokens": 573934,
- "cost": 3.1530659999999995
- }
- ]
- },
- {
- "date": "2025-08-14",
- "inputTokens": 4984,
- "outputTokens": 20654,
- "cacheCreationTokens": 676409,
- "cacheReadTokens": 8769252,
- "totalTokens": 9471299,
- "totalCost": 13.503454350000002,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 282,
- "outputTokens": 6364,
- "cacheCreationTokens": 260989,
- "cacheReadTokens": 3092770,
- "cost": 10.014228749999996
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 4702,
- "outputTokens": 14290,
- "cacheCreationTokens": 415420,
- "cacheReadTokens": 5676482,
- "cost": 3.489225600000001
- }
- ]
- },
- {
- "date": "2025-08-15",
- "inputTokens": 6744,
- "outputTokens": 53509,
- "cacheCreationTokens": 1315474,
- "cacheReadTokens": 18699807,
- "totalTokens": 20075534,
- "totalCost": 37.771287000000015,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 3739,
- "outputTokens": 36231,
- "cacheCreationTokens": 818888,
- "cacheReadTokens": 9919502,
- "cost": 33.00681300000001
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 3005,
- "outputTokens": 17278,
- "cacheCreationTokens": 496586,
- "cacheReadTokens": 8780305,
- "cost": 4.764474
- }
- ]
- },
- {
- "date": "2025-08-16",
- "inputTokens": 67226,
- "outputTokens": 230912,
- "cacheCreationTokens": 4693459,
- "cacheReadTokens": 126251857,
- "totalTokens": 131243454,
- "totalCost": 67.51195695000014,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 66858,
- "outputTokens": 225159,
- "cacheCreationTokens": 4442992,
- "cacheReadTokens": 122698549,
- "cost": 57.048743700000024
- },
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 368,
- "outputTokens": 5753,
- "cacheCreationTokens": 250467,
- "cacheReadTokens": 3553308,
- "cost": 10.463213249999994
- }
- ]
- },
- {
- "date": "2025-08-17",
- "inputTokens": 5258,
- "outputTokens": 107279,
- "cacheCreationTokens": 2065168,
- "cacheReadTokens": 40221095,
- "totalTokens": 42398800,
- "totalCost": 46.292036099999905,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 1306,
- "outputTokens": 37998,
- "cacheCreationTokens": 568961,
- "cacheReadTokens": 11688668,
- "cost": 31.07046074999999
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 3952,
- "outputTokens": 69281,
- "cacheCreationTokens": 1496207,
- "cacheReadTokens": 28532427,
- "cost": 15.221575350000005
- }
- ]
- },
- {
- "date": "2025-08-18",
- "inputTokens": 26822,
- "outputTokens": 158126,
- "cacheCreationTokens": 4162794,
- "cacheReadTokens": 85133032,
- "totalTokens": 89480774,
- "totalCost": 98.36223149999994,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 1334,
- "outputTokens": 59577,
- "cacheCreationTokens": 1226868,
- "cacheReadTokens": 27304867,
- "cost": 68.4493605
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 25488,
- "outputTokens": 98549,
- "cacheCreationTokens": 2935926,
- "cacheReadTokens": 57828165,
- "cost": 29.912871000000024
- }
- ]
- },
- {
- "date": "2025-08-19",
- "inputTokens": 25035,
- "outputTokens": 192422,
- "cacheCreationTokens": 2749046,
- "cacheReadTokens": 86412205,
- "totalTokens": 89378708,
- "totalCost": 120.90988019999996,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 6500,
- "outputTokens": 120014,
- "cacheCreationTokens": 1447294,
- "cacheReadTokens": 43939676,
- "cost": 102.14482650000001
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 18535,
- "outputTokens": 72408,
- "cacheCreationTokens": 1301752,
- "cacheReadTokens": 42472529,
- "cost": 18.76505370000004
- }
- ]
- },
- {
- "date": "2025-08-20",
- "inputTokens": 1777,
- "outputTokens": 45019,
- "cacheCreationTokens": 1288952,
- "cacheReadTokens": 18847679,
- "totalTokens": 20183427,
- "totalCost": 46.130642700000024,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 1472,
- "outputTokens": 29172,
- "cacheCreationTokens": 1017913,
- "cacheReadTokens": 14937895,
- "cost": 43.702691249999994
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 305,
- "outputTokens": 15847,
- "cacheCreationTokens": 271039,
- "cacheReadTokens": 3909784,
- "cost": 2.4279514499999997
- }
- ]
- },
- {
- "date": "2025-08-21",
- "inputTokens": 81,
- "outputTokens": 3400,
- "cacheCreationTokens": 57191,
- "cacheReadTokens": 406935,
- "totalTokens": 467607,
- "totalCost": 1.0935505500000002,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 37,
- "outputTokens": 826,
- "cacheCreationTokens": 29950,
- "cacheReadTokens": 172089,
- "cost": 0.882201
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 44,
- "outputTokens": 2574,
- "cacheCreationTokens": 27241,
- "cacheReadTokens": 234846,
- "cost": 0.21134955
- }
- ]
- },
- {
- "date": "2025-08-22",
- "inputTokens": 201,
- "outputTokens": 26357,
- "cacheCreationTokens": 182770,
- "cacheReadTokens": 1764101,
- "totalTokens": 1973429,
- "totalCost": 8.052878999999999,
- "modelsUsed": [
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 201,
- "outputTokens": 26357,
- "cacheCreationTokens": 182770,
- "cacheReadTokens": 1764101,
- "cost": 8.052878999999999
- }
- ]
- },
- {
- "date": "2025-08-23",
- "inputTokens": 114,
- "outputTokens": 6030,
- "cacheCreationTokens": 408902,
- "cacheReadTokens": 2606990,
- "totalTokens": 3022036,
- "totalCost": 11.605633500000005,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 88,
- "outputTokens": 5424,
- "cacheCreationTokens": 387862,
- "cacheReadTokens": 2545780,
- "cost": 11.499202500000006
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 26,
- "outputTokens": 606,
- "cacheCreationTokens": 21040,
- "cacheReadTokens": 61210,
- "cost": 0.106431
- }
- ]
- },
- {
- "date": "2025-08-26",
- "inputTokens": 2836,
- "outputTokens": 22779,
- "cacheCreationTokens": 465292,
- "cacheReadTokens": 11182259,
- "totalTokens": 11673166,
- "totalCost": 25.288227900000006,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 2745,
- "outputTokens": 19221,
- "cacheCreationTokens": 405641,
- "cacheReadTokens": 10473081,
- "cost": 24.798140250000003
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 91,
- "outputTokens": 3558,
- "cacheCreationTokens": 59651,
- "cacheReadTokens": 709178,
- "cost": 0.49008765
- }
- ]
- },
- {
- "date": "2025-08-30",
- "inputTokens": 151,
- "outputTokens": 63263,
- "cacheCreationTokens": 430727,
- "cacheReadTokens": 4992045,
- "totalTokens": 5486186,
- "totalCost": 20.311188749999992,
- "modelsUsed": [
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 151,
- "outputTokens": 63263,
- "cacheCreationTokens": 430727,
- "cacheReadTokens": 4992045,
- "cost": 20.311188749999992
- }
- ]
- },
- {
- "date": "2025-08-31",
- "inputTokens": 108,
- "outputTokens": 777,
- "cacheCreationTokens": 40539,
- "cacheReadTokens": 305195,
- "totalTokens": 346619,
- "totalCost": 1.2777937499999998,
- "modelsUsed": [
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 108,
- "outputTokens": 777,
- "cacheCreationTokens": 40539,
- "cacheReadTokens": 305195,
- "cost": 1.2777937499999998
- }
- ]
- },
- {
- "date": "2025-09-01",
- "inputTokens": 592,
- "outputTokens": 28240,
- "cacheCreationTokens": 712734,
- "cacheReadTokens": 12698327,
- "totalTokens": 13439893,
- "totalCost": 34.53813299999999,
- "modelsUsed": [
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 592,
- "outputTokens": 28240,
- "cacheCreationTokens": 712734,
- "cacheReadTokens": 12698327,
- "cost": 34.53813299999999
- }
- ]
- },
- {
- "date": "2025-09-06",
- "inputTokens": 1668,
- "outputTokens": 33964,
- "cacheCreationTokens": 833152,
- "cacheReadTokens": 7717866,
- "totalTokens": 8586650,
- "totalCost": 27.341439,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 590,
- "outputTokens": 32624,
- "cacheCreationTokens": 715702,
- "cacheReadTokens": 7239371,
- "cost": 26.734119
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 1078,
- "outputTokens": 1340,
- "cacheCreationTokens": 117450,
- "cacheReadTokens": 478495,
- "cost": 0.6073200000000001
- }
- ]
- },
- {
- "date": "2025-09-07",
- "inputTokens": 114,
- "outputTokens": 1815,
- "cacheCreationTokens": 34842,
- "cacheReadTokens": 441584,
- "totalTokens": 478355,
- "totalCost": 0.2906997,
- "modelsUsed": [
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 114,
- "outputTokens": 1815,
- "cacheCreationTokens": 34842,
- "cacheReadTokens": 441584,
- "cost": 0.2906997
- }
- ]
- },
- {
- "date": "2025-09-08",
- "inputTokens": 986,
- "outputTokens": 43404,
- "cacheCreationTokens": 1059761,
- "cacheReadTokens": 10126143,
- "totalTokens": 11230294,
- "totalCost": 13.057204650000008,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 59,
- "outputTokens": 6291,
- "cacheCreationTokens": 138364,
- "cacheReadTokens": 2448010,
- "cost": 6.739049999999998
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 927,
- "outputTokens": 37113,
- "cacheCreationTokens": 921397,
- "cacheReadTokens": 7678133,
- "cost": 6.318154650000004
- }
- ]
- },
- {
- "date": "2025-09-09",
- "inputTokens": 8308,
- "outputTokens": 25340,
- "cacheCreationTokens": 822848,
- "cacheReadTokens": 15392924,
- "totalTokens": 16249420,
- "totalCost": 34.003420200000015,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 818,
- "outputTokens": 20524,
- "cacheCreationTokens": 598685,
- "cacheReadTokens": 13061090,
- "cost": 32.36854874999999
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 7490,
- "outputTokens": 4816,
- "cacheCreationTokens": 224163,
- "cacheReadTokens": 2331834,
- "cost": 1.6348714500000001
- }
- ]
- },
- {
- "date": "2025-09-10",
- "inputTokens": 6970,
- "outputTokens": 56622,
- "cacheCreationTokens": 2561420,
- "cacheReadTokens": 41730332,
- "totalTokens": 44355344,
- "totalCost": 99.1074762,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 1372,
- "outputTokens": 33019,
- "cacheCreationTokens": 1955184,
- "cacheReadTokens": 37322873,
- "cost": 95.14101450000001
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 5598,
- "outputTokens": 23603,
- "cacheCreationTokens": 606236,
- "cacheReadTokens": 4407459,
- "cost": 3.9664617000000004
- }
- ]
- },
- {
- "date": "2025-09-11",
- "inputTokens": 6374,
- "outputTokens": 49460,
- "cacheCreationTokens": 2458036,
- "cacheReadTokens": 26091177,
- "totalTokens": 28605047,
- "totalCost": 51.98917170000001,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 820,
- "outputTokens": 16938,
- "cacheCreationTokens": 1169066,
- "cacheReadTokens": 13017543,
- "cost": 42.728951999999985
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 5554,
- "outputTokens": 32522,
- "cacheCreationTokens": 1288970,
- "cacheReadTokens": 13073634,
- "cost": 9.2602197
- }
- ]
- },
- {
- "date": "2025-09-12",
- "inputTokens": 11056,
- "outputTokens": 48249,
- "cacheCreationTokens": 1310531,
- "cacheReadTokens": 29530721,
- "totalTokens": 30900557,
- "totalCost": 16.632927149999993,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 10888,
- "outputTokens": 42034,
- "cacheCreationTokens": 1244336,
- "cacheReadTokens": 28918658,
- "cost": 14.005031399999988
- },
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 168,
- "outputTokens": 6215,
- "cacheCreationTokens": 66195,
- "cacheReadTokens": 612063,
- "cost": 2.6278957499999995
- }
- ]
- },
- {
- "date": "2025-09-13",
- "inputTokens": 1473,
- "outputTokens": 38594,
- "cacheCreationTokens": 754889,
- "cacheReadTokens": 7447975,
- "totalTokens": 8242931,
- "totalCost": 27.64876425,
- "modelsUsed": [
- "claude-sonnet-4-20250514",
- "claude-opus-4-1-20250805"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 1437,
- "outputTokens": 38340,
- "cacheCreationTokens": 724797,
- "cacheReadTokens": 7342175,
- "cost": 27.50026125
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 36,
- "outputTokens": 254,
- "cacheCreationTokens": 30092,
- "cacheReadTokens": 105800,
- "cost": 0.148503
- }
- ]
- },
- {
- "date": "2025-09-15",
- "inputTokens": 498,
- "outputTokens": 54148,
- "cacheCreationTokens": 988285,
- "cacheReadTokens": 16800377,
- "totalTokens": 17843308,
- "totalCost": 46.537434450000006,
- "modelsUsed": [
- "claude-opus-4-1-20250805",
- "claude-sonnet-4-20250514"
- ],
- "modelBreakdowns": [
- {
- "modelName": "claude-opus-4-1-20250805",
- "inputTokens": 448,
- "outputTokens": 52014,
- "cacheCreationTokens": 924435,
- "cacheReadTokens": 16653998,
- "cost": 46.221923249999996
- },
- {
- "modelName": "claude-sonnet-4-20250514",
- "inputTokens": 50,
- "outputTokens": 2134,
- "cacheCreationTokens": 63850,
- "cacheReadTokens": 146379,
- "cost": 0.3155112
- }
- ]
- }
- ],
- "totals": {
- "inputTokens": 247558,
- "outputTokens": 1599186,
- "cacheCreationTokens": 36246579,
- "cacheReadTokens": 678117825,
- "totalTokens": 716211148,
- "totalCost": 1027.2278395500002
- }
-}
diff --git a/public/data/domains.json b/public/data/domains.json
index 8ab1592..c29b608 100644
--- a/public/data/domains.json
+++ b/public/data/domains.json
@@ -6,23 +6,23 @@
},
{
"id": 2,
- "domain": "pontushost.com",
- "usage": "My hosting provider project"
+ "domain": "aidxn.fun",
+ "usage": "My alternative homepage (Version 2)"
},
{
"id": 3,
+ "domain": "librecloud.cc",
+ "usage": "LibreCloud's root domain"
+ },
+ {
+ "id": 4,
"domain": "disfunction.blog",
"usage": "My blog's official home"
},
- {
- "id": 4,
- "domain": "androidintegrity.org",
- "usage": "A project to fix Play Integrity"
- },
{
"id": 5,
- "domain": "librecloud.cc",
- "usage": "My old cloud services provider project"
+ "domain": "androidintegrity.org",
+ "usage": "A team project to improve Play Integrity"
},
{
"id": 6,
@@ -47,12 +47,12 @@
{
"id": 10,
"domain": "dontbeevil.lol",
- "usage": "Another fun domain for p0ntus mail"
+ "usage": "A Google meme domain used for p0ntus mail"
},
{
"id": 11,
"domain": "wikitools.cloud",
- "usage": "Unused (for now!)"
+ "usage": "Tools I've made for Wikipedia"
},
{
"id": 12,
diff --git a/public/data/featured.json b/public/data/featured.json
index 508476a..f28b2ea 100644
--- a/public/data/featured.json
+++ b/public/data/featured.json
@@ -4,35 +4,35 @@
"name": "aidxnCC",
"description": "aidxnCC is the third version of my personal website",
"github": false,
- "url": "https://git.p0ntus.com/aidan/aidxnCC",
- "stars": 1,
- "forks": 0
+ "url": "https://git.pontusmail.org/aidan/aidxnCC",
+ "stars": 2,
+ "forks": 1
},
{
"id": 2,
- "name": "abocn/TelegramBot",
+ "name": "librecloud/web",
"description": "Landing page for p0ntus mail",
- "github": true,
- "url": "https://github.com/abocn/TelegramBot",
- "stars": 13,
- "forks": 6
+ "github": false,
+ "url": "https://git.pontusmail.org/librecloud/web",
+ "stars": 0,
+ "forks": 0
},
{
"id": 3,
"name": "modules",
- "description": "A Magisk/KernelSU module repository",
- "github": true,
- "url": "https://github.com/abocn/modules",
- "stars": 5,
+ "description": "An open-source Magisk module and FOSS app store",
+ "github": false,
+ "url": "https://git.pontusmail.org/aidan/modules",
+ "stars": 3,
"forks": 0
},
{
"id": 4,
- "name": "pontus/pontus-front",
- "description": "The frontend and API for p0ntus, my free privacy-focused service provider",
- "github": false,
- "url": "https://git.p0ntus.com/pontus/pontus-front",
- "stars": 1,
- "forks": 0
+ "name": "AndroidIntegrity/website",
+ "description": "AIA website source code",
+ "github": true,
+ "url": "https://github.com/AndroidIntegrity/website",
+ "stars": 6,
+ "forks": 1
}
]
diff --git a/public/data/music.json b/public/data/music.json
new file mode 100644
index 0000000..8c01d75
--- /dev/null
+++ b/public/data/music.json
@@ -0,0 +1,56 @@
+[
+ {
+ "timePeriod": "Early Summer 2024",
+ "songs": [
+ {
+ "albumArt": "https://p0ntus.com/archives/img/noticeme.png",
+ "name": "Notice Me",
+ "artist": "tobi lou feat. MIA GLADSTONE",
+ "duration": "2:35",
+ "link": "https://www.last.fm/music/tobi+lou/Notice+Me"
+ },
+ {
+ "albumArt": "https://p0ntus.com/archives/img/comforttexas.webp",
+ "name": "comfort, texas",
+ "artist": "Buppy.",
+ "duration": "2:11",
+ "link": "https://www.last.fm/music/Buppy./comfort,+texas"
+ },
+ {
+ "albumArt": "https://p0ntus.com/archives/img/nonperishable.webp",
+ "name": "Jelly",
+ "artist": "tobi lou",
+ "duration": "1:50",
+ "link": "https://www.last.fm/music/tobi+lou/_/Jelly"
+ },
+ {
+ "albumArt": "https://p0ntus.com/archives/img/exes.webp",
+ "name": "exes",
+ "artist": "Tate McRae",
+ "duration": "2:39",
+ "link": "https://www.last.fm/music/Tate+McRae/exes/exes"
+ },
+ {
+ "albumArt": "https://p0ntus.com/archives/img/ick.webp",
+ "name": "Ick",
+ "artist": "Lay Bankz",
+ "duration": "1:55",
+ "link": "https://www.last.fm/music/Lay+Bankz/_/Ick"
+ },
+ {
+ "albumArt": "https://p0ntus.com/archives/img/nani.webp",
+ "name": "NANi",
+ "artist": "Saweetie",
+ "duration": "2:34",
+ "link": "https://www.last.fm/music/Saweetie/Nani"
+ },
+ {
+ "albumArt": "https://p0ntus.com/archives/img/killerloverboy.webp",
+ "name": "killer lover boy",
+ "artist": "SEB",
+ "duration": "2:14",
+ "link": "https://www.last.fm/music/Seb/_/killer+lover+boy"
+ }
+ ]
+ }
+ ]
\ No newline at end of file
diff --git a/public/img/bonito.png b/public/img/bonito.png
deleted file mode 100644
index 4b418e7..0000000
Binary files a/public/img/bonito.png and /dev/null differ
diff --git a/public/img/komodo.png b/public/img/komodo.png
deleted file mode 100644
index ecf09fa..0000000
Binary files a/public/img/komodo.png and /dev/null differ
diff --git a/public/locales/en-US.json b/public/locales/en-US.json
index e912acf..4ce5aab 100644
--- a/public/locales/en-US.json
+++ b/public/locales/en-US.json
@@ -1,20 +1,20 @@
{
"home": {
"whoAmI": [
- "Hey there! My name is Aidan, and I'm a systems administrator, full-stack developer, and student from the Boston area. I primarily work with Linux, Docker, Next.js, Tailwind CSS and TypeScript.",
- "My favorite projects and hobbies revolve around web development and SysAdmin. Most of my work is released into the public domain.",
- "I'm also a huge advocate for AI and it's practical applications to programming and life itself. I am fond of open-source models the most, specifically Qwen3!",
- "When I'm not programming, I can be found re-flashing my phone with a new custom ROM and jumping between projects. I tend to be quite depressed, but I make do."
+ "Hey there! My name is Aidan, and I'm a systems administrator, full-stack developer, and student from the United States. I primarily work with Linux, Docker, Next.js, and Node.js.",
+ "I primarily focus on Linux system administration with a few servers I run for myself and others. I enjoy working on web development projects on the side, most of which are Unlicensed/CC0.",
+ "When I'm not programming, I can be found re-flashing my phone with a new custom ROM and jumping between projects."
],
"whatIDo": [
- "I'm at my best when I'm doing system administration and development in TypeScript. I frequently implement AI into my workflow.",
- "I manage three servers, including a mailserver (against my better judgement). I'm also crazy enough to self-host LLMs running on CPU.",
- "My biggest project is p0ntus, a cloud services provider which I self-host and maintain. It features most services you would find from large companies like Google, although everything is free and open-source."
+ "I'm at my best when I'm doing system administration, which is what I'd say I have the most experience and familiarity with.",
+ "I host a variety of public-access services and websites on my VPS, most of which can be found on my \"Domains\" page with a short description.",
+ "My biggest project is LibreCloud, a cloud services provider which I self-host and maintain. It features most services you would find from large companies like Google, although everything is free and open-source.",
+ "I frequently write and work on a website hosted on a public Linux server, known as a \"tilde.\""
],
"whereYouAre": [
- "I am not here to brag about my accomplishments or plug my shitty SaaS. That's why I've made every effort to make this website as personal and fun as possible.",
- "I hope you find this website an interesting place to find more about me, but also learn something new; maybe inspire a new project or two.",
- "In a technical sense, this site is hosted on my dedicated server hosted in Buffalo, New York by ColoCrossing."
+ "I am not here to brag about my accomplishments or plug my cool SaaS product. That's why I've made every effort to make this website as personal and fun as possible.",
+ "I hope you find this website an interesting place to find more about me, but also learn something new, and inspire a new project or two.",
+ "This page is currently hosted on Cloudflare Workers, after what happened with "
],
"sections": {
"whoIAm": "Who I am",
@@ -23,7 +23,7 @@
},
"contact": {
"title": "Send me a message",
- "description": "Feel free to reach out for feedback, collaborations, or just a hello! I aim to answer all of my messages in a timely fashion, but please have patience.",
+ "description": "Feel free to reach out for feedback, collaborations, or just a hello :)",
"button": "Contact Me"
},
"donation": {
@@ -31,10 +31,10 @@
"description": "Feeling generous? Support me or one of the causes I support!",
"charities": {
"title": "Charities",
+ "description": "I support the following charities:",
"unsilenced": "Unsilenced",
"drugpolicy": "Drug Policy Alliance",
- "aclu": "ACLU",
- "epic-restart": "EPIC Restart Foundation"
+ "aclu": "ACLU"
},
"donate": {
"title": "Donate to Me",
@@ -67,10 +67,18 @@
"If you need to get in touch with me, please send me a message on Telegram or an email. I will provide my actual phone number if you have a valid reason."
]
}
+ },
+ "buttons": {
+ "github": "ihatenodejs",
+ "telegram": "@p0ntu5",
+ "x": "@ihatenodejs",
+ "bluesky": "@aidxn.cc",
+ "phone": "(802) 416-9516",
+ "email": "aidan@p0ntus.com"
}
},
"about": {
- "title": "Get to Know Me",
+ "title": "About Me",
"description": "Hey there! My name is Aidan, and I'm a systems administrator, full-stack developer, and student from the United States. I primarily work with Linux, Docker, Next.js, and Node.js.",
"sections": {
"projects": "Projects",
@@ -80,37 +88,31 @@
"featuredProjects": "Featured Projects"
},
"projects": [
- "I have worked on countless projects over the past five years, for the most part. I started learning to code with Python when I was seven and my interest has only evolved from there. I got into web development due to my uncle, who taught my how to write my first lines of HTML.",
- "Recently, I have been involved in developing several projects, especially with TypeScript, which is my new favorite language as of a year ago. My biggest project currently is p0ntus, a free service provider for privacy-focused individuals.",
- "You will also come to find that I have an addiction to Docker! Almost every project I've made is able to be run in Docker.",
- "Me and my developer friends operate an organization called ABOCN, where we primarily maintain a Telegram bot called Kowalski. You can find it on Telegram as @KowalskiNodeBot.",
- "I have learned system administration from the past three years of learning Linux for practical use and fun. I currently operate four servers running in the cloud, ran out of Canada, Germany, and the United States.",
- "I own a channel called PontusHub on Telegram, where I post updates about my projects, along with commentary and info about my projects related to the Android rooting community."
+ "I have worked on countless projects over the past five years, for the most part. I have been learning to program in Python since I was seven and have evolved from there. I got into web development due to my uncle, who taught my how to write my first lines of HTML.",
+ "Recently, I have been involved in developing several projects, especially with Node.js, my new favorite language as of a year ago. My biggest project is LibreCloud, a free service provider for individuals.",
+ "In terms of system administration, I have developed my skills over the past three years of learning Linux for fun. I currently operate three servers running in the cloud, which run out of Germany and the United States."
],
"hobbies": [
- "When I'm not programming, I can typically be found distro hopping or flashing a new ROM to my phone. I also spend a lot of time spreading Next.js and TypeScript propaganda to JavaScript developers.",
- "I consider maintaining my devices as a hobby as well, as I devote a lot of time to it. I genuinely enjoy installing Arch, Gentoo, and NixOS frequently, and flashing new ROMs to the phones I own.",
- "I am frequently active on my Forgejo server and GitHub, and aim to make daily contributions. I am a big fan of open source software and public domain software (which most of my repos are licensed under). In fact, the website you're currently on is free and open source. It's even under the public domain!",
- "When I touch grass, I prefer to walk on the streets, especially in Boston, Massachusetts. I also used to swim competitively, though it has turned into to a casual hobby over time.",
- "Editing Wikipedia has also been a good pastime for me, and I have been editing for a year and a half now. As of writing, I have made 6.1k edits to the English Wikipedia. I am also an AfC reviewer, new page reviewer, and rollbacker. You can find me on Wikipedia as OnlyNano."
+ "When I'm not programming, I can typically be found installing another Linux distro on my laptop or flashing a new ROM to my phone. I am also a passionate writer and I like to write creatively in my free time.",
+ "I consider maintaining my technology as a hobby as well, as I devote a lot of time to it. I currently run Gentoo Linux on my Thinkpad T470s, which does not use a single bin package. I am very proud of this laptop, despite it's constant need for compiling updates.",
+ "I am almost always active on my Gitea instance and GitHub and make daily contributions to several of my repositories. I am a big fan of open source software and public domain software (which most of my repos are licensed under). In fact, the website you're currently on is free and open source. It's even under the public domain!",
+ "My Google Pixel 7 Pro (cheetah) runs LineageOS 22.1, and has been one of my favorite additions to my life. It is proudly rooted with KernelSU-Next. It has suffered one drop to it's back on a tile floor."
],
"devices": {
- "Mobile Devices": [
- "I use a Google Pixel 9 Pro XL (komodo) as my daily driver. It runs Android 16 and is proudly rooted with KernelSU-Next.",
- "My previous phone, the Google Pixel 7 Pro (cheetah), is still in use as my secondary WiFi-only device. It runs Android 16 and is proudly rooted with KernelSU-Next.",
- "I also have a Google Pixel 3a XL (bonito) which I use as a tertiary device. It runs LineageOS 22.2 and is rooted with Magisk."
+ "Phone": [
+ "I use a Google Pixel 7 Pro (cheetah) as my daily driver. It runs LineageOS microG and is proudly rooted with KernelSU-Next.",
+ "It's back is shattered and missing volume buttons, but it continues to thrive and survive as my daily driver."
],
- "Laptops": [
- "I currently daily-drive with a 16-inch MacBook Pro with an M4 Max, 64GB of memory, 2TB of storage, 16 core CPU, and a 40 core GPU.",
- "I use a Lenovo Thinkpad T470s with macOS Sequoia (using OpenCore) as my \"side piece,\" if you will. I've had it for about a year now, and it's been a great experience.",
- "I also own two MacBook Airs (2015 and 2013 base models) and an HP Chromebook, used as secondary devices. The 2013 runs unsupported macOS Sequoia Beta, the 2015 runs Xubuntu, and the Chromebook runs Arch Linux."
+ "Laptop": [
+ "I use a Lenovo Thinkpad T470s running Arch Linux. I've had it for about half a year now, and it's been a great experience. I proudly use X11 and LXDE, with some Xfce backend components to make management easier."
]
},
"contributions": [
- "Most of my repositories have migrated to p0ntus git. My username is aidan. You can find me on GitHub as ihatenodejs."
+ "Most of my repositories have migrated to LibreCloud Git. My username is aidan.",
+ "You can find me on GitHub as ihatenodejs."
],
"featuredProjects": [
"Here's just four of my top projects. Star and fork counts are manually updated and count both Gitea and GitHub."
]
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/server.ts b/server.ts
deleted file mode 100644
index 06864c1..0000000
--- a/server.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { createServer } from "node:http";
-import next from "next";
-import { Server } from "socket.io";
-import { NowPlayingService } from "./lib/now-playing-server";
-
-const dev = process.env.NODE_ENV !== "production";
-const hostname = "localhost";
-const port = parseInt(process.env.PORT || "3000", 10);
-
-const app = next({ dev, hostname, port });
-const handler = app.getRequestHandler();
-
-app.prepare().then(() => {
- const httpServer = createServer(handler);
- const io = new Server(httpServer);
-
- const nowPlayingService = new NowPlayingService(io);
-
- io.on("connection", (socket) => {
- console.log("[WS] Client connected:", socket.id);
-
- socket.on("requestNowPlaying", async () => {
- await nowPlayingService.fetchNowPlaying(socket.id);
- });
-
- socket.on("startAutoRefresh", () => {
- const intervalId = setInterval(async () => {
- await nowPlayingService.fetchNowPlaying(socket.id);
- }, 30000);
-
- socket.on("disconnect", () => {
- clearInterval(intervalId);
- console.log("[WS] Client disconnected:", socket.id);
- });
- });
-
- socket.on("disconnect", () => {
- console.log("[WS] Client disconnected:", socket.id);
- });
- });
-
- httpServer.listen(port, () => {
- console.log(`✓ Ready on http://${hostname}:${port}`);
- });
-});
\ No newline at end of file
diff --git a/tailwind.config.ts b/tailwind.config.ts
index e193912..667e618 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -6,6 +6,7 @@ const config: Config = {
content: [
"app/**/*.{ts,tsx}",
"components/**/*.{ts,tsx}",
+ "./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"*.{js,ts,jsx,tsx,mdx}",
diff --git a/tools/ccombine.ts b/tools/ccombine.ts
deleted file mode 100644
index ab9ff23..0000000
--- a/tools/ccombine.ts
+++ /dev/null
@@ -1,237 +0,0 @@
-import fs from "node:fs/promises";
-import path from "node:path";
-
-type NumberLike = number | undefined | null;
-
-interface ModelBreakdown {
- modelName: string;
- inputTokens: number;
- outputTokens: number;
- cacheCreationTokens: number;
- cacheReadTokens: number;
- cost: number;
-}
-
-interface DailyEntry {
- date: string; // YYYY-MM-DD
- inputTokens: number;
- outputTokens: number;
- cacheCreationTokens: number;
- cacheReadTokens: number;
- totalTokens: number;
- totalCost: number;
- modelsUsed?: string[];
- modelBreakdowns?: ModelBreakdown[];
-}
-
-interface Totals {
- inputTokens: number;
- outputTokens: number;
- cacheCreationTokens: number;
- cacheReadTokens: number;
- totalTokens: number;
- totalCost: number;
-}
-
-interface CcFile {
- daily: DailyEntry[];
- totals?: Totals;
-}
-
-function toNumber(n: NumberLike): number {
- return typeof n === "number" && Number.isFinite(n) ? n : 0;
-}
-
-function computeTotals(daily: DailyEntry[]): Totals {
- const totals: Totals = {
- inputTokens: 0,
- outputTokens: 0,
- cacheCreationTokens: 0,
- cacheReadTokens: 0,
- totalTokens: 0,
- totalCost: 0,
- };
- for (const d of daily) {
- totals.inputTokens += toNumber(d.inputTokens);
- totals.outputTokens += toNumber(d.outputTokens);
- totals.cacheCreationTokens += toNumber(d.cacheCreationTokens);
- totals.cacheReadTokens += toNumber(d.cacheReadTokens);
- totals.totalTokens += toNumber(d.totalTokens);
- totals.totalCost += toNumber(d.totalCost);
- }
- return totals;
-}
-
-function isReplacementBetter(a: DailyEntry, b: DailyEntry): boolean {
- const aTokens = toNumber(a.totalTokens);
- const bTokens = toNumber(b.totalTokens);
- if (bTokens !== aTokens) return bTokens > aTokens;
- const aCost = toNumber(a.totalCost);
- const bCost = toNumber(b.totalCost);
- if (bCost !== aCost) return bCost > aCost;
-
- const aBreakdowns = a.modelBreakdowns?.length ?? 0;
- const bBreakdowns = b.modelBreakdowns?.length ?? 0;
- if (bBreakdowns !== aBreakdowns) return bBreakdowns > aBreakdowns;
-
- return false;
-}
-
-async function readJson(filePath: string): Promise {
- const raw = await fs.readFile(filePath, "utf8");
- return JSON.parse(raw) as T;
-}
-
-async function fileExists(filePath: string): Promise {
- try {
- await fs.access(filePath);
- return true;
- } catch {
- return false;
- }
-}
-
-function isObject(value: unknown): value is Record {
- return typeof value === "object" && value !== null;
-}
-
-function coerceTotals(t: unknown): Totals {
- const r = isObject(t) ? t : {};
- return {
- inputTokens: toNumber(r["inputTokens"] as NumberLike),
- outputTokens: toNumber(r["outputTokens"] as NumberLike),
- cacheCreationTokens: toNumber(r["cacheCreationTokens"] as NumberLike),
- cacheReadTokens: toNumber(r["cacheReadTokens"] as NumberLike),
- totalTokens: toNumber(r["totalTokens"] as NumberLike),
- totalCost: toNumber(r["totalCost"] as NumberLike),
- };
-}
-
-function coerceDailyEntry(item: unknown): DailyEntry {
- const r = isObject(item) ? item : {};
-
- const modelBreakdownsRaw = Array.isArray(r["modelBreakdowns"]) ? (r["modelBreakdowns"] as unknown[]) : [];
- const modelBreakdowns: ModelBreakdown[] = modelBreakdownsRaw.map((mb) => {
- const m = isObject(mb) ? mb : {};
- return {
- modelName: typeof m["modelName"] === "string" ? (m["modelName"] as string) : "",
- inputTokens: toNumber(m["inputTokens"] as NumberLike),
- outputTokens: toNumber(m["outputTokens"] as NumberLike),
- cacheCreationTokens: toNumber(m["cacheCreationTokens"] as NumberLike),
- cacheReadTokens: toNumber(m["cacheReadTokens"] as NumberLike),
- cost: toNumber(m["cost"] as NumberLike),
- };
- });
-
- const modelsUsed = Array.isArray(r["modelsUsed"]) ? (r["modelsUsed"] as unknown[]).filter((x): x is string => typeof x === "string") : undefined;
-
- return {
- date: String((r["date"] as unknown) ?? ""),
- inputTokens: toNumber(r["inputTokens"] as NumberLike),
- outputTokens: toNumber(r["outputTokens"] as NumberLike),
- cacheCreationTokens: toNumber(r["cacheCreationTokens"] as NumberLike),
- cacheReadTokens: toNumber(r["cacheReadTokens"] as NumberLike),
- totalTokens: toNumber(r["totalTokens"] as NumberLike),
- totalCost: toNumber(r["totalCost"] as NumberLike),
- modelsUsed,
- modelBreakdowns: modelBreakdowns.length ? modelBreakdowns : undefined,
- };
-}
-
-function normalizeCcShape(obj: unknown): CcFile {
- const o = isObject(obj) ? obj : {};
- const rawDaily = Array.isArray(o["daily"]) ? (o["daily"] as unknown[]) : [];
- const daily = rawDaily.map(coerceDailyEntry);
- const totals = isObject(o["totals"]) ? coerceTotals(o["totals"]) : undefined;
- return { daily, totals };
-}
-
-function sortByDateAsc(entries: DailyEntry[]): DailyEntry[] {
- return entries.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));
-}
-
-async function main() {
- const args = process.argv.slice(2);
- if (args.length === 0 || args.includes("-h") || args.includes("--help")) {
- console.log(`Usage: tsx tools/ccombine.ts [--base public/data/cc.json] [--out ] [--dry]`);
- process.exit(args.length === 0 ? 1 : 0);
- }
-
- let inputPath = "";
- let basePath = path.join(process.cwd(), "public", "data", "cc.json");
- let outPath: string | undefined;
- let dryRun = false;
-
- for (let i = 0; i < args.length; i++) {
- const a = args[i];
- if (a === "--base") {
- basePath = path.resolve(args[++i]);
- } else if (a === "--out") {
- outPath = path.resolve(args[++i]);
- } else if (a === "--dry" || a === "--dry-run") {
- dryRun = true;
- } else if (!a.startsWith("-")) {
- inputPath = path.resolve(a);
- } else {
- console.error(`Unknown option: ${a}`);
- process.exit(1);
- }
- }
-
- if (!inputPath) {
- console.error("Error: missing input path");
- process.exit(1);
- }
- if (!outPath) outPath = basePath;
-
- if (!(await fileExists(inputPath))) {
- console.error(`Error: input file not found: ${inputPath}`);
- process.exit(1);
- }
-
- const baseExists = await fileExists(basePath);
- const baseCc = baseExists ? normalizeCcShape(await readJson(basePath)) : { daily: [] };
- const newCc = normalizeCcShape(await readJson(inputPath));
-
- const baseByDate = new Map();
- for (const d of baseCc.daily) baseByDate.set(d.date, d);
-
- const added: string[] = [];
- const replaced: string[] = [];
- const unchanged: string[] = [];
-
- for (const incoming of newCc.daily) {
- const existing = baseByDate.get(incoming.date);
- if (!existing) {
- baseByDate.set(incoming.date, incoming);
- added.push(incoming.date);
- continue;
- }
- if (isReplacementBetter(existing, incoming)) {
- baseByDate.set(incoming.date, incoming);
- replaced.push(incoming.date);
- } else {
- unchanged.push(incoming.date);
- }
- }
-
- const mergedDaily = sortByDateAsc(Array.from(baseByDate.values()));
- const totals = computeTotals(mergedDaily);
- const merged: CcFile = { daily: mergedDaily, totals };
-
- if (dryRun) {
- console.log("[ccombine] Dry run. No files written.");
- } else {
- await fs.mkdir(path.dirname(outPath), { recursive: true });
- await fs.writeFile(outPath, JSON.stringify(merged, null, 2) + "\n", "utf8");
- }
-
- const outDisplay = dryRun ? "(dry run)" : outPath;
- console.log("[ccombine] Output:", outDisplay);
- console.log(`[ccombine] Added: ${added.length} | Replaced: ${replaced.length} | Unchanged (overlap): ${unchanged.length}`);
-}
-
-main().catch((err) => {
- console.error("[ccombine] Error:", err?.message || err);
- process.exit(1);
-});