From 6760a523e4f90317c3c37ea5e1b184ab1483f489 Mon Sep 17 00:00:00 2001 From: Puechberty Arthur Date: Mon, 23 Feb 2026 03:57:05 +0100 Subject: [PATCH] Refactor code structure and remove redundant sections for improved readability and maintainability --- .env.example | 4 + .vscode/sftp.json | 11 + README.md | 114 +-- app.js | 70 -- app/admin/page.js | 10 + app/api/admin/login/route.js | 29 + app/api/admin/logout/route.js | 15 + app/api/admin/session/route.js | 6 + app/api/analytics/click/route.js | 14 + app/api/analytics/route.js | 12 + app/api/links/[id]/route.js | 17 + app/api/links/route.js | 25 + app/globals.css | 282 ++++++ app/layout.js | 14 + app/page.js | 6 + components/AdminPanel.js | 267 +++++ components/LinksPage.js | 144 +++ config.js | 115 ++- data/analytics.json | 3 + data/links.json | 58 ++ docker-compose.yml | 12 +- lib/auth.js | 35 + lib/storage.js | 121 +++ package-lock.json | 1566 ++++++++++++++++-------------- package.json | 13 +- public/favicon.ico | Bin 0 -> 42443 bytes public/style.css | 149 --- 27 files changed, 2025 insertions(+), 1087 deletions(-) create mode 100644 .env.example create mode 100644 .vscode/sftp.json delete mode 100644 app.js create mode 100644 app/admin/page.js create mode 100644 app/api/admin/login/route.js create mode 100644 app/api/admin/logout/route.js create mode 100644 app/api/admin/session/route.js create mode 100644 app/api/analytics/click/route.js create mode 100644 app/api/analytics/route.js create mode 100644 app/api/links/[id]/route.js create mode 100644 app/api/links/route.js create mode 100644 app/globals.css create mode 100644 app/layout.js create mode 100644 app/page.js create mode 100644 components/AdminPanel.js create mode 100644 components/LinksPage.js create mode 100644 data/analytics.json create mode 100644 data/links.json create mode 100644 lib/auth.js create mode 100644 lib/storage.js create mode 100644 public/favicon.ico delete mode 100644 public/style.css diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4e54088 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +ADMIN_USERNAME=admin +ADMIN_PASSWORD=123456 +ADMIN_SESSION_SECRET=change-me-in-production +PORT=3000 diff --git a/.vscode/sftp.json b/.vscode/sftp.json new file mode 100644 index 0000000..d608a6e --- /dev/null +++ b/.vscode/sftp.json @@ -0,0 +1,11 @@ +{ + "name": "My Server", + "host": "10.0.0.158", + "protocol": "sftp", + "port": 22, + "username": "root", + "remotePath": "/root/links", + "uploadOnSave": false, + "useTempFile": false, + "openSsh": false +} diff --git a/README.md b/README.md index 7edad85..d4003ff 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,93 @@ -# Social Links Website +# Social Links (Next.js) -Une application web Node.js élégante pour afficher et partager vos liens de réseaux sociaux personnels. - -![Social Links Website](https://github.com/user-attachments/assets/61f94cae-166c-4dc0-ad17-2412e184d4ad) +Une page de liens personnelle moderne construite avec Next.js (App Router). ## Fonctionnalités -- 🎨 Interface moderne et responsive -- 🔗 Affichage des liens vers vos réseaux sociaux -- 📱 Compatible mobile et desktop -- 🚀 Serveur Express.js léger -- 🌟 Design avec gradient et animations -- 📊 API REST pour récupérer les liens (extensibilité future) +- 🎨 UI moderne et responsive +- 🔎 Recherche instantanée dans les liens +- 🏷️ Filtres par catégories +- 🌗 Mode clair/sombre (persisté en local) +- 🔐 Espace admin protégé (analytics privées) +- ➕ Ajout et suppression de liens depuis le menu admin ## Installation -1. Clonez le repository : -```bash -git clone https://github.com/arthur-pbty/links.git -cd links -``` - -2. Installez les dépendances : ```bash npm install ``` -3. Personnalisez vos liens sociaux dans `app.js` (voir section Configuration) +## Démarrage -4. Démarrez l'application : ```bash -npm start +npm run dev ``` -5. Ouvrez votre navigateur sur `http://localhost:3000` +Puis ouvre http://localhost:3000 -## Configuration +## Scripts -Pour personnaliser vos liens sociaux, modifiez le tableau `socialLinks` dans le fichier `app.js` : +- `npm run dev` : développement +- `npm run build` : build de production +- `npm start` : démarrage en production -```javascript -const socialLinks = [ - { - name: 'GitHub', - url: 'https://github.com/votre-username', - icon: '🐙', - description: 'Mon profil GitHub' - }, - // Ajoutez vos autres liens ici... -]; +## Variables critiques (.env) + +Copie `.env.example` vers `.env` et ajuste les valeurs : + +```bash +cp .env.example .env ``` -### Structure d'un lien +Variables requises : -- `name` : Nom du réseau social -- `url` : URL vers votre profil -- `icon` : Emoji ou icône à afficher -- `description` : Description courte du lien +- `ADMIN_USERNAME` +- `ADMIN_PASSWORD` +- `ADMIN_SESSION_SECRET` +- `PORT` -## Scripts disponibles +## Configuration des données -- `npm start` : Démarre le serveur en mode production -- `npm run dev` : Démarre le serveur en mode développement +Modifie le fichier `config.js` : -## API +- `profile` : nom, bio, avatar +- `socialLinks` : liste de liens affichés -L'application expose également une API REST : +Chaque lien peut contenir : -- `GET /` : Page principale avec l'interface web -- `GET /api/links` : Récupère la liste des liens en JSON +- `name` +- `url` +- `icon` (fichier dans `public/`) +- `description` +- `category` -## Technologies utilisées +## Admin -- Node.js -- Express.js -- HTML5/CSS3 -- Design responsive +- URL admin : http://localhost:3000/admin +- Identifiant : admin +- Mot de passe : 123456 -## Déploiement +Dans le menu admin, vous pouvez : -Pour déployer sur des plateformes comme Heroku, Vercel, ou Railway : +- consulter les analytics (clics par lien) +- ajouter un lien +- supprimer un lien -1. Assurez-vous que la variable d'environnement `PORT` est configurée -2. Le serveur écoutera automatiquement sur `process.env.PORT || 3000` +## Docker Compose + +Le `docker-compose.yml` lance maintenant : + +1. `npm install` +2. `npm run build` +3. `npm start` + +Test prod Docker : + +```bash +docker compose up --build -d +docker compose ps +``` ## Licence -MIT - Voir le fichier [LICENSE](LICENSE) pour plus de détails. \ No newline at end of file +MIT - Voir [LICENSE](LICENSE) \ No newline at end of file diff --git a/app.js b/app.js deleted file mode 100644 index b0621a8..0000000 --- a/app.js +++ /dev/null @@ -1,70 +0,0 @@ -const express = require('express'); -const path = require('path'); -const config = require('./config'); - -const app = express(); -const PORT = config.server.port; - -// Configuration depuis le fichier config.js -const { profile, socialLinks } = config; - -// Middleware pour servir les fichiers statiques -app.use(express.static(path.join(__dirname, 'public'))); - -// Route principale -app.get('/', (req, res) => { - const html = ` - - - - - - Mes Liens - Arthur - - - -
-
-
- Avatar -
-

${profile.name}

-

${profile.bio}

-
- - - -
-

© 2024 Arthur - Tous droits réservés

-
-
- - - `; - - res.send(html); -}); - -// Route API pour obtenir les liens (optionnel, pour future extensibilité) -app.get('/api/links', (req, res) => { - res.json({ links: socialLinks }); -}); - -// Démarrage du serveur -app.listen(PORT, () => { - console.log(`🚀 Serveur démarré sur http://localhost:${PORT}`); - console.log(`📱 Site de liens sociaux prêt !`); -}); \ No newline at end of file diff --git a/app/admin/page.js b/app/admin/page.js new file mode 100644 index 0000000..a6cf4c5 --- /dev/null +++ b/app/admin/page.js @@ -0,0 +1,10 @@ +import AdminPanel from '../../components/AdminPanel'; + +export const metadata = { + title: 'Admin - Mes Liens', + description: 'Gestion des liens et analytics privées.' +}; + +export default function AdminPage() { + return ; +} diff --git a/app/api/admin/login/route.js b/app/api/admin/login/route.js new file mode 100644 index 0000000..785da77 --- /dev/null +++ b/app/api/admin/login/route.js @@ -0,0 +1,29 @@ +import { NextResponse } from 'next/server'; +import { + ADMIN_COOKIE, + createAdminSessionToken, + isValidAdminCredentials +} from '../../../../lib/auth'; + +export async function POST(request) { + const body = await request.json().catch(() => ({})); + const username = body.username || ''; + const password = body.password || ''; + + if (!isValidAdminCredentials(username, password)) { + return NextResponse.json({ error: 'Identifiants invalides.' }, { status: 401 }); + } + + const response = NextResponse.json({ ok: true }); + response.cookies.set({ + name: ADMIN_COOKIE, + value: createAdminSessionToken(), + httpOnly: true, + sameSite: 'strict', + secure: process.env.NODE_ENV === 'production', + path: '/', + maxAge: 60 * 60 * 12 + }); + + return response; +} diff --git a/app/api/admin/logout/route.js b/app/api/admin/logout/route.js new file mode 100644 index 0000000..4409be8 --- /dev/null +++ b/app/api/admin/logout/route.js @@ -0,0 +1,15 @@ +import { NextResponse } from 'next/server'; +import { ADMIN_COOKIE } from '../../../../lib/auth'; + +export async function POST() { + const response = NextResponse.json({ ok: true }); + response.cookies.set({ + name: ADMIN_COOKIE, + value: '', + path: '/', + httpOnly: true, + sameSite: 'strict', + maxAge: 0 + }); + return response; +} diff --git a/app/api/admin/session/route.js b/app/api/admin/session/route.js new file mode 100644 index 0000000..95ca8e9 --- /dev/null +++ b/app/api/admin/session/route.js @@ -0,0 +1,6 @@ +import { NextResponse } from 'next/server'; +import { isAdminRequest } from '../../../../lib/auth'; + +export async function GET(request) { + return NextResponse.json({ authenticated: isAdminRequest(request) }); +} diff --git a/app/api/analytics/click/route.js b/app/api/analytics/click/route.js new file mode 100644 index 0000000..29eba8a --- /dev/null +++ b/app/api/analytics/click/route.js @@ -0,0 +1,14 @@ +import { NextResponse } from 'next/server'; +import { incrementClick } from '../../../../lib/storage'; + +export async function POST(request) { + const body = await request.json().catch(() => ({})); + const linkId = body.linkId; + + if (!linkId) { + return NextResponse.json({ error: 'linkId requis.' }, { status: 400 }); + } + + await incrementClick(linkId); + return NextResponse.json({ ok: true }); +} diff --git a/app/api/analytics/route.js b/app/api/analytics/route.js new file mode 100644 index 0000000..06be789 --- /dev/null +++ b/app/api/analytics/route.js @@ -0,0 +1,12 @@ +import { NextResponse } from 'next/server'; +import { getAnalyticsForLinks } from '../../../lib/storage'; +import { isAdminRequest } from '../../../lib/auth'; + +export async function GET(request) { + if (!isAdminRequest(request)) { + return NextResponse.json({ error: 'Non autorisé.' }, { status: 401 }); + } + + const analytics = await getAnalyticsForLinks(); + return NextResponse.json({ analytics }); +} diff --git a/app/api/links/[id]/route.js b/app/api/links/[id]/route.js new file mode 100644 index 0000000..b17556b --- /dev/null +++ b/app/api/links/[id]/route.js @@ -0,0 +1,17 @@ +import { NextResponse } from 'next/server'; +import { removeLink } from '../../../../lib/storage'; +import { isAdminRequest } from '../../../../lib/auth'; + +export async function DELETE(request, { params }) { + if (!isAdminRequest(request)) { + return NextResponse.json({ error: 'Non autorisé.' }, { status: 401 }); + } + + const { id } = await params; + const deleted = await removeLink(id); + if (!deleted) { + return NextResponse.json({ error: 'Lien introuvable.' }, { status: 404 }); + } + + return NextResponse.json({ ok: true }); +} diff --git a/app/api/links/route.js b/app/api/links/route.js new file mode 100644 index 0000000..e1aa217 --- /dev/null +++ b/app/api/links/route.js @@ -0,0 +1,25 @@ +import { NextResponse } from 'next/server'; +import { addLink, getLinks } from '../../../lib/storage'; +import { isAdminRequest } from '../../../lib/auth'; + +export async function GET() { + const links = await getLinks(); + return NextResponse.json({ links }); +} + +export async function POST(request) { + if (!isAdminRequest(request)) { + return NextResponse.json({ error: 'Non autorisé.' }, { status: 401 }); + } + + const payload = await request.json().catch(() => ({})); + const required = ['name', 'url']; + const missing = required.some((field) => !payload[field]); + + if (missing) { + return NextResponse.json({ error: 'Nom et URL sont obligatoires.' }, { status: 400 }); + } + + const created = await addLink(payload); + return NextResponse.json({ link: created }, { status: 201 }); +} diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..ed3b72b --- /dev/null +++ b/app/globals.css @@ -0,0 +1,282 @@ +:root { + --bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --surface: rgba(255, 255, 255, 0.95); + --text: #1f2937; + --muted: #6b7280; + --card: #ffffff; + --accent: #4f46e5; + --border: rgba(255, 255, 255, 0.2); + --chip: #eef2ff; +} + +[data-theme='dark'] { + --bg: linear-gradient(135deg, #0f172a 0%, #1e293b 100%); + --surface: rgba(15, 23, 42, 0.92); + --text: #e5e7eb; + --muted: #94a3b8; + --card: rgba(30, 41, 59, 0.9); + --accent: #818cf8; + --border: rgba(148, 163, 184, 0.2); + --chip: rgba(79, 70, 229, 0.2); +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; + min-height: 100%; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; + background: var(--bg); + color: var(--text); +} + +.page { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 24px; +} + +.container { + width: 100%; + max-width: 520px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 24px; + padding: 28px; + box-shadow: 0 16px 48px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(14px); +} + +.header { + display: flex; + justify-content: flex-end; + margin-bottom: 10px; +} + +.theme-toggle { + border: 1px solid var(--border); + background: var(--card); + color: var(--text); + border-radius: 999px; + padding: 8px 12px; + cursor: pointer; +} + +.profile { + text-align: center; + margin-bottom: 22px; +} + +.avatar { + width: 84px; + height: 84px; + border-radius: 50%; + object-fit: cover; + margin-bottom: 10px; + border: 2px solid var(--border); +} + +.profile h1 { + margin: 0; + font-size: 1.9rem; +} + +.bio { + margin-top: 8px; + color: var(--muted); +} + +.controls { + display: grid; + gap: 10px; + margin-bottom: 18px; +} + +.search { + width: 100%; + padding: 12px 14px; + border-radius: 12px; + border: 1px solid var(--border); + background: var(--card); + color: var(--text); +} + +.categories { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.chip { + border: 1px solid transparent; + background: var(--chip); + color: var(--text); + border-radius: 999px; + padding: 8px 12px; + cursor: pointer; +} + +.chip.active { + background: var(--accent); + color: #fff; +} + +.links { + display: flex; + flex-direction: column; + gap: 12px; +} + +.link-card { + display: flex; + align-items: center; + gap: 12px; + text-decoration: none; + color: var(--text); + padding: 14px; + border-radius: 14px; + border: 1px solid var(--border); + background: var(--card); + transition: transform 0.2s ease, border-color 0.2s ease; +} + +.link-card:hover { + transform: translateY(-2px); + border-color: var(--accent); +} + +.icon { + width: 34px; + height: 34px; + object-fit: contain; +} + +.link-info { + flex: 1; +} + +.link-title { + margin: 0; + font-size: 1.02rem; +} + +.link-description { + margin: 3px 0 0; + color: var(--muted); + font-size: 0.9rem; +} + +.link-meta { + text-align: right; + color: var(--muted); + font-size: 0.8rem; +} + +.empty { + text-align: center; + color: var(--muted); + padding: 16px; +} + +footer { + margin-top: 18px; + border-top: 1px solid var(--border); + padding-top: 14px; + text-align: center; + color: var(--muted); + font-size: 0.85rem; +} + +.admin-link { + color: var(--accent); + text-decoration: none; +} + +.admin-link:hover { + text-decoration: underline; +} + +.admin-container { + max-width: 760px; +} + +.admin-head { + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; +} + +.admin-title { + margin: 0; + font-size: 1.8rem; +} + +.admin-subtitle { + margin: 0 0 10px; + font-size: 1.2rem; +} + +.admin-section { + margin-top: 20px; +} + +.admin-form { + display: grid; + gap: 10px; +} + +.admin-list { + display: grid; + gap: 10px; +} + +.admin-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px; + padding: 12px; + border: 1px solid var(--border); + border-radius: 12px; + background: var(--card); +} + +.admin-count { + color: var(--muted); + font-weight: 600; +} + +.danger-btn { + border: 1px solid var(--accent); + background: transparent; + color: var(--accent); + border-radius: 8px; + padding: 8px 10px; + cursor: pointer; +} + +.admin-error { + margin-top: 14px; + color: var(--accent); +} + +@media (max-width: 600px) { + .container { + padding: 20px; + border-radius: 18px; + } + + .profile h1 { + font-size: 1.65rem; + } +} diff --git a/app/layout.js b/app/layout.js new file mode 100644 index 0000000..9210cd8 --- /dev/null +++ b/app/layout.js @@ -0,0 +1,14 @@ +import './globals.css'; + +export const metadata = { + title: 'Mes Liens - Arthur', + description: 'Tous mes liens sociaux et projets au même endroit.' +}; + +export default function RootLayout({ children }) { + return ( + + {children} + + ); +} diff --git a/app/page.js b/app/page.js new file mode 100644 index 0000000..1308ecf --- /dev/null +++ b/app/page.js @@ -0,0 +1,6 @@ +import LinksPage from '../components/LinksPage'; +import { profile } from '../config'; + +export default function Page() { + return ; +} diff --git a/components/AdminPanel.js b/components/AdminPanel.js new file mode 100644 index 0000000..15ee103 --- /dev/null +++ b/components/AdminPanel.js @@ -0,0 +1,267 @@ +'use client'; + +import { useEffect, useMemo, useState } from 'react'; + +const initialForm = { + name: '', + url: '', + icon: '/github.png', + description: '', + category: 'Autres' +}; + +export default function AdminPanel() { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [username, setUsername] = useState('admin'); + const [password, setPassword] = useState(''); + const [links, setLinks] = useState([]); + const [analytics, setAnalytics] = useState([]); + const [form, setForm] = useState(initialForm); + const [error, setError] = useState(''); + const [loading, setLoading] = useState(true); + + async function loadAdminData() { + const [linksResponse, analyticsResponse] = await Promise.all([ + fetch('/api/links'), + fetch('/api/analytics') + ]); + + if (!linksResponse.ok || !analyticsResponse.ok) { + setError('Impossible de charger les données admin.'); + return; + } + + const linksData = await linksResponse.json(); + const analyticsData = await analyticsResponse.json(); + + setLinks(linksData.links || []); + setAnalytics(analyticsData.analytics || []); + setError(''); + } + + useEffect(() => { + async function checkSession() { + const response = await fetch('/api/admin/session'); + const data = await response.json(); + + if (data.authenticated) { + setIsAuthenticated(true); + await loadAdminData(); + } + + setLoading(false); + } + + checkSession(); + }, []); + + async function handleLogin(event) { + event.preventDefault(); + setError(''); + + const response = await fetch('/api/admin/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username, password }) + }); + + if (!response.ok) { + setError('Identifiant ou mot de passe invalide.'); + return; + } + + setIsAuthenticated(true); + setPassword(''); + await loadAdminData(); + } + + async function handleLogout() { + await fetch('/api/admin/logout', { method: 'POST' }); + setIsAuthenticated(false); + setLinks([]); + setAnalytics([]); + } + + async function handleAddLink(event) { + event.preventDefault(); + setError(''); + + const response = await fetch('/api/links', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(form) + }); + + if (!response.ok) { + setError("Impossible d'ajouter le lien."); + return; + } + + setForm(initialForm); + await loadAdminData(); + } + + async function handleDeleteLink(linkId) { + setError(''); + const response = await fetch(`/api/links/${linkId}`, { method: 'DELETE' }); + + if (!response.ok) { + setError('Impossible de supprimer ce lien.'); + return; + } + + setError(''); + await loadAdminData(); + } + + const totalClicks = useMemo( + () => analytics.reduce((sum, item) => sum + (item.clicks || 0), 0), + [analytics] + ); + + if (loading) { + return ( +
+
+

Chargement...

+
+
+ ); + } + + if (!isAuthenticated) { + return ( +
+
+

Admin

+

Accès protégé aux analytics et à la gestion des liens.

+ +
+ setUsername(event.target.value)} + placeholder="Identifiant" + required + /> + setPassword(event.target.value)} + placeholder="Mot de passe" + required + /> + +
+ + {error ?

{error}

: null} +
+
+ ); + } + + return ( +
+
+
+

Menu Admin

+ +
+ +
+

Analytics

+

Total clics: {totalClicks}

+
+ {analytics.map((item) => ( +
+
+ {item.name} +
{item.url}
+
+
{item.clicks} clics
+
+ ))} +
+
+ +
+

Ajouter un lien

+
+ setForm({ ...form, name: event.target.value })} + placeholder="Nom" + required + /> + setForm({ ...form, url: event.target.value })} + placeholder="URL" + required + /> + setForm({ ...form, icon: event.target.value })} + placeholder="Icône (ex: /github.png)" + /> + setForm({ ...form, description: event.target.value })} + placeholder="Description" + /> + setForm({ ...form, category: event.target.value })} + placeholder="Catégorie" + /> + +
+
+ +
+

Supprimer un lien

+
+ {links.map((link) => ( +
+
+ {link.name} +
{link.url}
+
+ +
+ ))} +
+
+ + {error ?

{error}

: null} +
+
+ ); +} diff --git a/components/LinksPage.js b/components/LinksPage.js new file mode 100644 index 0000000..4da3807 --- /dev/null +++ b/components/LinksPage.js @@ -0,0 +1,144 @@ +'use client'; + +import { useEffect, useMemo, useState } from 'react'; + +function normalize(value) { + return (value || '').toLowerCase().trim(); +} + +function getDomain(url) { + try { + return new URL(url).hostname.replace('www.', ''); + } catch { + return ''; + } +} + +export default function LinksPage({ profile, socialLinks }) { + const [query, setQuery] = useState(''); + const [activeCategory, setActiveCategory] = useState('Tous'); + const [theme, setTheme] = useState('light'); + const [links, setLinks] = useState(socialLinks || []); + + useEffect(() => { + const storedTheme = localStorage.getItem('theme') || 'light'; + setTheme(storedTheme); + document.documentElement.setAttribute('data-theme', storedTheme); + + async function loadLinks() { + const response = await fetch('/api/links'); + if (!response.ok) { + return; + } + const data = await response.json(); + setLinks(data.links || []); + } + + loadLinks(); + }, []); + + const categories = useMemo(() => { + const set = new Set((links || []).map((link) => link.category || 'Autres')); + return ['Tous', ...Array.from(set)]; + }, [links]); + + const filteredLinks = useMemo(() => { + return (links || []).filter((link) => { + const matchesCategory = + activeCategory === 'Tous' || (link.category || 'Autres') === activeCategory; + const target = normalize(`${link.name} ${link.description} ${link.url}`); + const matchesSearch = target.includes(normalize(query)); + return matchesCategory && matchesSearch; + }); + }, [links, activeCategory, query]); + + function toggleTheme() { + const nextTheme = theme === 'light' ? 'dark' : 'light'; + setTheme(nextTheme); + localStorage.setItem('theme', nextTheme); + document.documentElement.setAttribute('data-theme', nextTheme); + } + + async function trackClick(linkId) { + await fetch('/api/analytics/click', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ linkId }) + }); + } + + return ( +
+
+
+ +
+ +
+ Avatar +

{profile.name}

+

{profile.bio}

+
+ +
+ setQuery(event.target.value)} + placeholder="Rechercher un lien..." + aria-label="Rechercher un lien" + /> + +
+ {categories.map((category) => ( + + ))} +
+
+ +
+ {filteredLinks.length === 0 ? ( +

Aucun lien ne correspond à ta recherche.

+ ) : ( + filteredLinks.map((link) => ( + trackClick(link.id)} + > + {link.name} +
+

{link.name}

+

{link.description}

+
+
+
{getDomain(link.url)}
+
+
+ )) + )} +
+ +
+ © {new Date().getFullYear()} {profile.name} - Tous droits réservés ·{' '} + + Admin + +
+
+
+ ); +} diff --git a/config.js b/config.js index ced46a9..a8c410e 100644 --- a/config.js +++ b/config.js @@ -1,62 +1,59 @@ -// Configuration pour vos liens de réseaux sociaux -// Modifiez ce fichier pour personnaliser vos liens +// Configuration des données affichées dans l'application Next.js -module.exports = { - // Informations du profil - profile: { - name: 'Arthur', - bio: 'Développeur passionné | Sportif de haut niveau', - avatar: '/avatar.png' // Chemin relatif vers l'image dans public/ +export const profile = { + name: 'Arthur', + bio: 'Développeur passionné | Sportif de haut niveau', + avatar: '/avatar.png' +}; + +export const socialLinks = [ + { + name: 'GitHub', + url: 'https://github.com/arthur-pbty', + icon: '/github.png', + description: 'Mon profil GitHub', + category: 'Développement' }, - - // Liste des liens sociaux - socialLinks: [ - { - name: 'GitHub', - url: 'https://github.com/arthur-pbty', - icon: '/github.png', // Chemin relatif vers l'image dans public/ - description: 'Mon profil GitHub' - }, - { - name: 'Instagram', - url: 'https://www.instagram.com/arthur.pbty/', - icon: '/instagram.png', - description: 'Mes photos et stories' - }, - { - name: 'FFVoile', - url: 'https://www.ffvoile.fr/ffv/sportif/cif/cif_detail.aspx?NoLicence=1443697B', - icon: '/ffvoile.png', - description: 'Mon profil FFVoile' - }, - { - name: 'YouTube', - url: 'https://www.youtube.com/@arthur-pbty', - icon: '/youtube.png', - description: 'Ma chaîne YouTube' - }, - { - name: 'Discord', - url: 'https://discord.gg/MZSseRvCk8', - icon: '/discord.png', - description: 'Rejoignez mon serveur Discord' - }, - { - name: 'TikTok', - url: 'https://www.tiktok.com/@arthur.pbty', - icon: '/tiktok.png', - description: 'Mes vidéos TikTok' - }, - { - name: 'Twitch', - url: 'https://www.twitch.tv/arthur_pbty', - icon: '/twitch.png', - description: 'Mes streams en direct' - } - ], - - // Configuration du serveur - server: { - port: process.env.PORT || 3000 + { + name: 'Instagram', + url: 'https://www.instagram.com/arthur.pbty/', + icon: '/instagram.png', + description: 'Mes photos et stories', + category: 'Réseaux' + }, + { + name: 'FFVoile', + url: 'https://www.ffvoile.fr/ffv/sportif/cif/cif_detail.aspx?NoLicence=1443697B', + icon: '/ffvoile.png', + description: 'Mon profil FFVoile', + category: 'Sport' + }, + { + name: 'YouTube', + url: 'https://www.youtube.com/@arthur-pbty', + icon: '/youtube.png', + description: 'Ma chaîne YouTube', + category: 'Création' + }, + { + name: 'Discord', + url: 'https://discord.gg/MZSseRvCk8', + icon: '/discord.png', + description: 'Rejoignez mon serveur Discord', + category: 'Communauté' + }, + { + name: 'TikTok', + url: 'https://www.tiktok.com/@arthur.pbty', + icon: '/tiktok.png', + description: 'Mes vidéos TikTok', + category: 'Création' + }, + { + name: 'Twitch', + url: 'https://www.twitch.tv/arthur_pbty', + icon: '/twitch.png', + description: 'Mes streams en direct', + category: 'Streaming' } -}; \ No newline at end of file +]; \ No newline at end of file diff --git a/data/analytics.json b/data/analytics.json new file mode 100644 index 0000000..a2140c3 --- /dev/null +++ b/data/analytics.json @@ -0,0 +1,3 @@ +{ + "github-1": 1 +} \ No newline at end of file diff --git a/data/links.json b/data/links.json new file mode 100644 index 0000000..85e229f --- /dev/null +++ b/data/links.json @@ -0,0 +1,58 @@ +[ + { + "id": "github-1", + "name": "GitHub", + "url": "https://github.com/arthur-pbty", + "icon": "/github.png", + "description": "Mon profil GitHub", + "category": "Développement" + }, + { + "id": "instagram-2", + "name": "Instagram", + "url": "https://www.instagram.com/arthur.pbty/", + "icon": "/instagram.png", + "description": "Mes photos et stories", + "category": "Réseaux" + }, + { + "id": "ffvoile-3", + "name": "FFVoile", + "url": "https://www.ffvoile.fr/ffv/sportif/cif/cif_detail.aspx?NoLicence=1443697B", + "icon": "/ffvoile.png", + "description": "Mon profil FFVoile", + "category": "Sport" + }, + { + "id": "youtube-4", + "name": "YouTube", + "url": "https://www.youtube.com/@arthur-pbty", + "icon": "/youtube.png", + "description": "Ma chaîne YouTube", + "category": "Création" + }, + { + "id": "discord-5", + "name": "Discord", + "url": "https://discord.gg/MZSseRvCk8", + "icon": "/discord.png", + "description": "Rejoignez mon serveur Discord", + "category": "Communauté" + }, + { + "id": "tiktok-6", + "name": "TikTok", + "url": "https://www.tiktok.com/@arthur.pbty", + "icon": "/tiktok.png", + "description": "Mes vidéos TikTok", + "category": "Création" + }, + { + "id": "twitch-7", + "name": "Twitch", + "url": "https://www.twitch.tv/arthur_pbty", + "icon": "/twitch.png", + "description": "Mes streams en direct", + "category": "Streaming" + } +] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 442d264..581464b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,6 @@ -version: '3.8' - services: app: - image: node:18 + image: node:20 working_dir: /usr/src/app volumes: - ./:/usr/src/app @@ -10,6 +8,8 @@ services: - "3000:3000" restart: unless-stopped environment: - - NODE_ENV=production - - PORT=3000 - command: sh -c "npm install && npm start" \ No newline at end of file + - PORT=${PORT:-3000} + - ADMIN_USERNAME=${ADMIN_USERNAME} + - ADMIN_PASSWORD=${ADMIN_PASSWORD} + - ADMIN_SESSION_SECRET=${ADMIN_SESSION_SECRET} + command: sh -c "npm install && npm run build && npm start" \ No newline at end of file diff --git a/lib/auth.js b/lib/auth.js new file mode 100644 index 0000000..e40f69d --- /dev/null +++ b/lib/auth.js @@ -0,0 +1,35 @@ +import { createHash } from 'node:crypto'; + +function getRequiredEnv(name) { + const value = process.env[name]; + if (!value) { + throw new Error(`Missing required environment variable: ${name}`); + } + return value; +} + +export const ADMIN_USERNAME = getRequiredEnv('ADMIN_USERNAME'); +export const ADMIN_PASSWORD = getRequiredEnv('ADMIN_PASSWORD'); +export const ADMIN_SESSION_SECRET = getRequiredEnv('ADMIN_SESSION_SECRET'); +export const ADMIN_COOKIE = 'admin_session'; + +function hash(value) { + return createHash('sha256').update(value).digest('hex'); +} + +function expectedToken() { + return hash(`${ADMIN_USERNAME}:${ADMIN_PASSWORD}:${ADMIN_SESSION_SECRET}`); +} + +export function isValidAdminCredentials(username, password) { + return username === ADMIN_USERNAME && password === ADMIN_PASSWORD; +} + +export function createAdminSessionToken() { + return expectedToken(); +} + +export function isAdminRequest(request) { + const token = request.cookies.get(ADMIN_COOKIE)?.value; + return token === expectedToken(); +} diff --git a/lib/storage.js b/lib/storage.js new file mode 100644 index 0000000..0bab1fb --- /dev/null +++ b/lib/storage.js @@ -0,0 +1,121 @@ +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { randomUUID } from 'node:crypto'; +import { socialLinks } from '../config'; + +const DATA_DIR = path.join(process.cwd(), 'data'); +const LINKS_FILE = path.join(DATA_DIR, 'links.json'); +const ANALYTICS_FILE = path.join(DATA_DIR, 'analytics.json'); + +function slugify(text) { + return (text || '') + .toLowerCase() + .trim() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') + .slice(0, 50); +} + +function withId(link, index) { + return { + id: link.id || `${slugify(link.name)}-${index + 1}`, + name: link.name, + url: link.url, + icon: link.icon, + description: link.description || '', + category: link.category || 'Autres' + }; +} + +async function fileExists(filePath) { + try { + await readFile(filePath, 'utf-8'); + return true; + } catch { + return false; + } +} + +async function readJson(filePath, fallback) { + try { + const content = await readFile(filePath, 'utf-8'); + return JSON.parse(content); + } catch { + return fallback; + } +} + +async function writeJson(filePath, value) { + await writeFile(filePath, JSON.stringify(value, null, 2), 'utf-8'); +} + +export async function ensureDataFiles() { + await mkdir(DATA_DIR, { recursive: true }); + + if (!(await fileExists(LINKS_FILE))) { + const initialLinks = socialLinks.map(withId); + await writeJson(LINKS_FILE, initialLinks); + } + + if (!(await fileExists(ANALYTICS_FILE))) { + await writeJson(ANALYTICS_FILE, {}); + } +} + +export async function getLinks() { + await ensureDataFiles(); + return readJson(LINKS_FILE, []); +} + +export async function addLink(payload) { + await ensureDataFiles(); + const links = await getLinks(); + + const newLink = { + id: randomUUID(), + name: payload.name, + url: payload.url, + icon: payload.icon || '/github.png', + description: payload.description || '', + category: payload.category || 'Autres' + }; + + const updatedLinks = [...links, newLink]; + await writeJson(LINKS_FILE, updatedLinks); + return newLink; +} + +export async function removeLink(linkId) { + await ensureDataFiles(); + const links = await getLinks(); + const nextLinks = links.filter((link) => link.id !== linkId); + + if (nextLinks.length === links.length) { + return false; + } + + await writeJson(LINKS_FILE, nextLinks); + return true; +} + +export async function incrementClick(linkId) { + await ensureDataFiles(); + const analytics = await readJson(ANALYTICS_FILE, {}); + analytics[linkId] = (analytics[linkId] || 0) + 1; + await writeJson(ANALYTICS_FILE, analytics); +} + +export async function getAnalyticsForLinks() { + await ensureDataFiles(); + const [links, analytics] = await Promise.all([ + readJson(LINKS_FILE, []), + readJson(ANALYTICS_FILE, {}) + ]); + + return links.map((link) => ({ + id: link.id, + name: link.name, + url: link.url, + clicks: analytics[link.id] || 0 + })); +} diff --git a/package-lock.json b/package-lock.json index f96e4ea..573f302 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,825 +9,905 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "express": "^4.18.2" + "next": "^16.0.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "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==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "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==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/etag": { + "node_modules/@emnapi/runtime": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", "license": "MIT", - "engines": { - "node": ">= 0.6" + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, + "optional": true, "engines": { - "node": ">= 0.10.0" + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "url": "https://opencollective.com/libvips" }, - "engines": { - "node": ">= 0.8" + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" + "url": "https://opencollective.com/libvips" }, - "engines": { - "node": ">= 0.4" + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "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.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "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-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "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-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "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-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "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-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "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-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, "dependencies": { - "function-bind": "^1.1.2" + "@emnapi/runtime": "^1.7.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "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==", + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "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.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "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-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "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/@next/env": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", + "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "tslib": "^2.8.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" }, "engines": { - "node": ">= 0.8" + "node": ">=6.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/caniuse-lite": { + "version": "1.0.30001772", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001772.tgz", + "integrity": "sha512-mIwLZICj+ntVTw4BT2zfp+yu/AqV6GMKfJVJMx3MwPxs+uk/uj2GLl2dH8LQbjiLDX66amCga5nKFyDgRR43kg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", + "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "@next/env": "16.1.6", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.1.6", + "@next/swc-darwin-x64": "16.1.6", + "@next/swc-linux-arm64-gnu": "16.1.6", + "@next/swc-linux-arm64-musl": "16.1.6", + "@next/swc-linux-x64-gnu": "16.1.6", + "@next/swc-linux-x64-musl": "16.1.6", + "@next/swc-win32-arm64-msvc": "16.1.6", + "@next/swc-win32-x64-msvc": "16.1.6", + "sharp": "^0.34.4" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "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", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "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==", + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "engines": { - "node": ">= 0.10" + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "optional": true, "bin": { - "mime": "cli.js" + "semver": "bin/semver.js" }, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, "dependencies": { - "mime-db": "1.52.0" + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { - "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==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" + "url": "https://opencollective.com/libvips" }, - "engines": { - "node": ">= 0.8" + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" - }, - "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==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { + "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "client-only": "0.0.1" }, "engines": { - "node": ">= 0.8" - } - }, - "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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "babel-plugin-macros": { + "optional": true } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" } }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.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==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" } } } diff --git a/package.json b/package.json index 383ecc6..495abfd 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,19 @@ { "name": "links", "version": "1.0.0", - "description": "A web app to distribute personal social media links", - "main": "app.js", + "description": "Une page de liens moderne avec Next.js", + "main": "next.config.js", "scripts": { - "start": "node app.js", - "dev": "node app.js" + "dev": "node ./node_modules/next/dist/bin/next dev", + "build": "node ./node_modules/next/dist/bin/next build", + "start": "node ./node_modules/next/dist/bin/next start" }, "keywords": ["links", "social", "profile"], "author": "arthur-pbty", "license": "MIT", "dependencies": { - "express": "^4.18.2" + "next": "^16.0.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" } } \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0c5ee36176a8518b5304ee4d89aa17e65a861a71 GIT binary patch literal 42443 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Ⓢ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 fzWaf|Mw