From ade69cb644d49a520affba8c945a91423f551323 Mon Sep 17 00:00:00 2001 From: diametrfq Date: Sat, 20 Sep 2025 04:21:35 +0300 Subject: [PATCH 1/2] forgejo --- .forgejo/workflows/deploy.yml | 47 ++++++++++++ .github/workflows/deploy.yml | 140 ---------------------------------- .gitignore | 2 +- 3 files changed, 48 insertions(+), 141 deletions(-) create mode 100644 .forgejo/workflows/deploy.yml delete mode 100644 .github/workflows/deploy.yml diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml new file mode 100644 index 0000000..966747b --- /dev/null +++ b/.forgejo/workflows/deploy.yml @@ -0,0 +1,47 @@ +name: Build, Push, and Deploy + +on: + push: + branches: [ main ] + +jobs: + build_and_push: + runs-on: docker + steps: + # 1. Checkout + - run: git clone $FORGEJO_REPO_URL repo && cd repo + + # 2. Build Frontend Docker Image + - run: | + cd frontend + docker build -t diametrfq/website:latest . + docker save diametrfq/website:latest -o /tmp/frontend.tar + + # 3. Build Backend Docker Image + - run: | + cd backend + docker build -t diametrfq/website-backend:latest . + docker save diametrfq/website-backend:latest -o /tmp/backend.tar + + # 4. Push Images to Docker Hub + - run: | + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + docker load --input /tmp/frontend.tar + docker push diametrfq/website:latest + docker load --input /tmp/backend.tar + docker push diametrfq/website-backend:latest + + # 5. Deploy to Server + - run: | + scp -r ./docker-compose.yml ./configs ./nginx.prod.conf $HOSTING_NAME@$HOSTING_SERVER:/myPath + ssh $HOSTING_NAME@$HOSTING_SERVER " + cd /myPath + export GRAFANA_ADMIN_PASSWORD=$GRAFANA_ADMIN_PASSWORD + export SPOTIFY_CLIENT_ID=$SPOTIFY_CLIENT_ID + export SPOTIFY_CLIENT_SECRET=$SPOTIFY_CLIENT_SECRET + export SPOTIFY_REFRESH_TOKEN=$SPOTIFY_REFRESH_TOKEN + echo '$DOCKER_PASSWORD' | docker login -u '$DOCKER_USERNAME' --password-stdin + docker-compose pull + docker-compose up -d --force-recreate --remove-orphans + docker system prune -af + " diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 6e5b16b..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,140 +0,0 @@ -name: Build, Push, and Deploy - -on: - pull_request: - branches: - - main - -env: - DOCKER_BUILD_RECORD_RETENTION_DAYS: 1 - BUILDX_CACHE_MAX_SIZE: 5GB - ACTIONS_CACHE_KEY_PREFIX: v1 - -jobs: - build_frontend_image: - name: 1. Build Frontend Image - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build image and save as artifact - uses: docker/build-push-action@v5 - with: - context: ./frontend - push: false - load: true - tags: diametrfq/website:latest - cache-from: | - type=gha,scope=frontend-build-${{ hashFiles('frontend/**') }} - type=gha,scope=frontend-build - cache-to: | - type=gha,mode=max,scope=frontend-build-${{ hashFiles('frontend/**') }} - type=gha,mode=min,scope=frontend-build - - name: Save image to tar - run: docker save diametrfq/website:latest -o /tmp/frontend.tar - - name: Upload image artifact - uses: actions/upload-artifact@v4 - with: - name: frontend-image-${{ github.run_number }} - path: /tmp/frontend.tar - - build_backend_image: - name: 2. Build Backend Image - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build image and save as artifact - uses: docker/build-push-action@v5 - with: - context: ./backend - push: false - load: true - tags: diametrfq/website-backend:latest - cache-from: | - type=gha,scope=backend-build-${{ hashFiles('backend/**') }} - type=gha,scope=backend-build - cache-to: | - type=gha,mode=max,scope=backend-build-${{ hashFiles('backend/**') }} - type=gha,mode=min,scope=backend-build - - name: Save image to tar - run: docker save diametrfq/website-backend:latest -o /tmp/backend.tar - - name: Upload image artifact - uses: actions/upload-artifact@v4 - with: - name: backend-image-${{ github.run_number }} - path: /tmp/backend.tar - - push_images: - name: 3. Push Images to Docker Hub - runs-on: ubuntu-latest - needs: [build_frontend_image, build_backend_image] - steps: - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - name: Download frontend image artifact - uses: actions/download-artifact@v4 - with: - name: frontend-image-${{ github.run_number }} - path: /tmp - - name: Download backend image artifact - uses: actions/download-artifact@v4 - with: - name: backend-image-${{ github.run_number }} - path: /tmp - - name: Load and Push Frontend Image - run: | - docker load --input /tmp/frontend.tar - docker push diametrfq/website:latest & - - name: Load and Push Backend Image - run: | - docker load --input /tmp/backend.tar - docker push diametrfq/website-backend:latest & - - name: Wait for all pushes to complete - run: wait - - deploy_to_server: - name: 4. Deploy to Server - runs-on: ubuntu-latest - needs: [push_images] - steps: - - uses: actions/checkout@v4 - - name: Transfer Files to Server - uses: appleboy/scp-action@v0.1.4 - with: - host: ${{ secrets.HOSTING_SERVER }} - username: ${{ secrets.HOSTING_NAME }} - password: ${{ secrets.HOSTING_PASSWORD }} - source: "./docker-compose.yml,./configs,./nginx.prod.conf" - target: "/myPath" - - name: Deploy to Server - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.HOSTING_SERVER }} - username: ${{ secrets.HOSTING_NAME }} - password: ${{ secrets.HOSTING_PASSWORD }} - script: | - cd /myPath - export GRAFANA_ADMIN_PASSWORD=${{ secrets.GRAFANA_ADMIN_PASSWORD }} - export SPOTIFY_CLIENT_ID=${{ secrets.SPOTIFY_CLIENT_ID }} - export SPOTIFY_CLIENT_SECRET=${{ secrets.SPOTIFY_CLIENT_SECRET }} - export SPOTIFY_REFRESH_TOKEN=${{ secrets.SPOTIFY_REFRESH_TOKEN }} - - echo "Logging in to Docker Hub..." - echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin - - echo "Pulling latest images..." - docker-compose pull - - echo "Starting services..." - docker-compose up -d --force-recreate --remove-orphans - - echo "Cleaning up old images..." - docker system prune -af diff --git a/.gitignore b/.gitignore index f065485..6eada34 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ **.local** **.dev** -getPrompt.js +gp file_index.json \ No newline at end of file From 4dacc0fbc91224d9e9db452b290a4b10b7a4d3fc Mon Sep 17 00:00:00 2001 From: diametrfq Date: Thu, 8 Jan 2026 02:46:28 +0300 Subject: [PATCH 2/2] feat: Implement Telegram post fetching and display with Next.js 15 upgrade, i18n, and new backend services. --- {.forgejo => .github}/workflows/deploy.yml | 0 .../src/endpoints/api/telegram/handlers.rs | 7 +- backend/src/endpoints/api/telegram/models.rs | 7 + .../src/endpoints/api/telegram/services.rs | 230 ++++------- backend/src/endpoints/app_state.rs | 9 +- frontend/app/[locale]/layout.tsx | 24 +- .../telegram/components/TelegramPosts.tsx | 42 +- frontend/app/i18n.ts | 13 - frontend/i18n.ts | 11 + frontend/i18n/request.ts | 17 + frontend/i18n/request.ts.bak | 23 ++ frontend/next.config.ts | 67 +--- frontend/package-lock.json | 367 ++++++++---------- frontend/package.json | 10 +- frontend/{middleware.ts => proxy.ts} | 8 +- frontend/tsconfig.json | 4 +- 16 files changed, 365 insertions(+), 474 deletions(-) rename {.forgejo => .github}/workflows/deploy.yml (100%) delete mode 100644 frontend/app/i18n.ts create mode 100644 frontend/i18n.ts create mode 100644 frontend/i18n/request.ts create mode 100644 frontend/i18n/request.ts.bak rename frontend/{middleware.ts => proxy.ts} (74%) diff --git a/.forgejo/workflows/deploy.yml b/.github/workflows/deploy.yml similarity index 100% rename from .forgejo/workflows/deploy.yml rename to .github/workflows/deploy.yml diff --git a/backend/src/endpoints/api/telegram/handlers.rs b/backend/src/endpoints/api/telegram/handlers.rs index f9f175a..48d934c 100644 --- a/backend/src/endpoints/api/telegram/handlers.rs +++ b/backend/src/endpoints/api/telegram/handlers.rs @@ -6,7 +6,10 @@ use crate::endpoints::app_state::AppState; #[get("")] pub async fn get_telegram_posts_handler(state: web::Data) -> HttpResponse { - let result = services::fetch_telegram_posts(state.rss_fetcher.as_ref()).await; + let result = services::fetch_telegram_posts( + state.rss_fetcher.as_ref(), + &state.telegram_cache // <-- Добавили этот аргумент + ).await; match result { Ok(posts) => match serde_json::to_string(&posts) { @@ -26,4 +29,4 @@ pub async fn get_telegram_posts_handler(state: web::Data) -> HttpRespo HttpResponse::InternalServerError().finish() } } -} +} \ No newline at end of file diff --git a/backend/src/endpoints/api/telegram/models.rs b/backend/src/endpoints/api/telegram/models.rs index c4167ad..f6fa59a 100644 --- a/backend/src/endpoints/api/telegram/models.rs +++ b/backend/src/endpoints/api/telegram/models.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::time::Instant; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Post { @@ -9,3 +10,9 @@ pub struct Post { #[serde(rename = "imageUrl", skip_serializing_if = "Option::is_none")] pub image_url: Option, } + +#[derive(Debug, Clone)] +pub struct TelegramCache { + pub posts: Vec, + pub last_updated: Instant, +} \ No newline at end of file diff --git a/backend/src/endpoints/api/telegram/services.rs b/backend/src/endpoints/api/telegram/services.rs index e00b462..813eba1 100644 --- a/backend/src/endpoints/api/telegram/services.rs +++ b/backend/src/endpoints/api/telegram/services.rs @@ -1,11 +1,14 @@ use super::errors::{AppError, AppResult}; -use super::models::Post; +use super::models::{Post, TelegramCache}; use async_trait::async_trait; use bytes::Bytes; use rss::Channel; use scraper::Html; +use std::time::{Duration, Instant}; +use tokio::sync::Mutex; const TELEGRAM_CHANNEL: &str = "diametrpd"; +const CACHE_TTL_SECONDS: u64 = 600; #[async_trait] pub trait RssFetcher { @@ -34,34 +37,71 @@ impl RssFetcher for RealRssFetcher { } } -pub async fn fetch_telegram_posts(fetcher: &(dyn RssFetcher + Sync)) -> AppResult> { - let feed_url = format!("https://rsshub.app/telegram/channel/{}", TELEGRAM_CHANNEL); - let content = fetcher.fetch_rss_content(&feed_url).await?; - - let channel = Channel::read_from(&content[..]).map_err(|e| { - log::error!("Failed to parse RSS feed: {}", e); - AppError::ServiceErrorWithFallback - })?; - - let posts: Vec = channel - .items() - .iter() - .map(|item| { - let raw_html_snippet = item - .description() - .unwrap_or_else(|| item.content().unwrap_or("")) - .to_string(); - let plain_text_snippet = html_to_plaintext(&raw_html_snippet); - Post { - title: item.title().unwrap_or("Без заголовка").to_string(), - link: item.link().unwrap_or("#").to_string(), - content_snippet: plain_text_snippet, - image_url: extract_image_url(item), +pub async fn fetch_telegram_posts( + fetcher: &(dyn RssFetcher + Sync), + cache_mutex: &Mutex>, +) -> AppResult> { + + { + let cache_guard = cache_mutex.lock().await; + if let Some(cache) = &*cache_guard { + if cache.last_updated.elapsed() < Duration::from_secs(CACHE_TTL_SECONDS) { + log::info!("Returning Telegram posts from CACHE"); + return Ok(cache.posts.clone()); } - }) - .collect(); + } + } - Ok(posts) + log::info!("Cache expired or empty, fetching from RSS..."); + let feed_url = format!("https://rsshub.app/telegram/channel/{}", TELEGRAM_CHANNEL); + + let fetch_result = fetcher.fetch_rss_content(&feed_url).await; + + match fetch_result { + Ok(content) => { + let channel = Channel::read_from(&content[..]).map_err(|e| { + log::error!("Failed to parse RSS feed: {}", e); + AppError::ServiceErrorWithFallback + })?; + + let posts: Vec = channel + .items() + .iter() + .map(|item| { + let raw_html_snippet = item + .description() + .unwrap_or_else(|| item.content().unwrap_or("")) + .to_string(); + let plain_text_snippet = html_to_plaintext(&raw_html_snippet); + Post { + title: item.title().unwrap_or("Без заголовка").to_string(), + link: item.link().unwrap_or("#").to_string(), + content_snippet: plain_text_snippet, + image_url: extract_image_url(item), + } + }) + .collect(); + + { + let mut cache_guard = cache_mutex.lock().await; + *cache_guard = Some(TelegramCache { + posts: posts.clone(), + last_updated: Instant::now(), + }); + } + log::info!("Telegram posts updated successfully"); + Ok(posts) + } + Err(e) => { + log::warn!("Failed to fetch new posts: {}. Trying fallback to stale cache.", e); + let cache_guard = cache_mutex.lock().await; + if let Some(cache) = &*cache_guard { + log::info!("Returning STALE Telegram posts from cache"); + return Ok(cache.posts.clone()); + } + Err(e) + } + } } fn html_to_plaintext(html_content: &str) -> String { @@ -99,138 +139,4 @@ fn extract_image_url(item: &rss::Item) -> Option { } } None -} - -#[cfg(test)] -mod tests { - use super::*; - use bytes::Bytes; - use std::io; - - struct MockRssFetcher { - response: AppResult, - } - - #[async_trait] - impl RssFetcher for MockRssFetcher { - async fn fetch_rss_content(&self, _url: &str) -> AppResult { - self.response - .as_ref() - .map(|b| b.clone()) - .map_err(|e| AppError::IoError(io::Error::new(io::ErrorKind::Other, e.to_string()))) - } - } - - #[tokio::test] - async fn test_fetch_posts_success_path() { - let fake_rss = r#" - - - - Test Channel - Post 1http://a.com/1Desc 1 - Post 2http://a.com/2C

]]>
- -
-
- "#; - - let mock_fetcher = MockRssFetcher { - response: Ok(Bytes::from(fake_rss)), - }; - - let result = fetch_telegram_posts(&mock_fetcher).await; - assert!(result.is_ok(), "Function should return Ok on valid RSS"); - - let posts = result.unwrap(); - assert_eq!(posts.len(), 3, "Should parse all 3 items"); - - assert_eq!(posts[0].title, "Post 1"); - assert_eq!(posts[0].content_snippet, "Desc 1"); - - assert_eq!(posts[1].content_snippet, "C"); - assert_eq!(posts[1].image_url, Some("http://a.com/img.jpg".to_string())); - - assert_eq!(posts[2].title, "Без заголовка"); - assert_eq!(posts[2].link, "#"); - } - - #[tokio::test] - async fn test_fetch_posts_on_parsing_error() { - let fake_response = "this is not xml"; - let mock_fetcher = MockRssFetcher { - response: Ok(Bytes::from(fake_response)), - }; - - let result = fetch_telegram_posts(&mock_fetcher).await; - - assert!(result.is_err()); - match result.unwrap_err() { - AppError::ServiceErrorWithFallback => (), // Успех! - other => panic!( - "Expected ServiceErrorWithFallback on parsing error, but got {:?}", - other - ), - } - } - - #[tokio::test] - async fn test_fetch_posts_on_network_error() { - let mock_fetcher = MockRssFetcher { - response: Err(AppError::InternalError( - "Simulated network failure".to_string(), - )), - }; - - let result = fetch_telegram_posts(&mock_fetcher).await; - assert!(result.is_err()); - } - - #[test] - fn test_html_to_plaintext_conversion() { - let html = "

Hello world & friends

\n!
"; - assert_eq!(html_to_plaintext(html), "Hello world & friends !"); - assert_eq!(html_to_plaintext(""), ""); - } - - #[test] - fn test_image_url_extraction() { - // --- Test 1: Image in --- - let mut item1 = rss::Item::default(); - item1.set_description(String::from( - "

text

", - )); - let result1 = extract_image_url(&item1); - assert!(result1.is_some(), "Test 1 failed"); - assert_eq!(result1.unwrap(), "http://test.com/image.png"); - - // --- Test 2: Image in --- - let mut item2 = rss::Item::default(); - item2.set_content(String::from("")); - let result2 = extract_image_url(&item2); - assert!( - result2.is_some(), - "Test 2 failed: Should find an image in content" - ); - assert_eq!(result2.unwrap(), "https://another.com/image.gif"); - - // --- Test 3: Image from --- - let mut item3 = rss::Item::default(); - item3.set_content(String::from("")); - let mut enclosure = rss::Enclosure::default(); - enclosure.set_url("http://priority.com/enclosure.jpg".to_string()); - enclosure.set_mime_type("image/jpeg".to_string()); - item3.set_enclosure(enclosure); - let result3 = extract_image_url(&item3); - assert!(result3.is_some(), "Test 3 failed"); - assert_eq!( - result3.unwrap(), - "http://priority.com/enclosure.jpg", - "Enclosure should have priority" - ); - - // --- Test 4: No image --- - let item_no_image = rss::Item::default(); - assert!(extract_image_url(&item_no_image).is_none(), "Test 4 failed"); - } -} +} \ No newline at end of file diff --git a/backend/src/endpoints/app_state.rs b/backend/src/endpoints/app_state.rs index 691d438..eb6643a 100644 --- a/backend/src/endpoints/app_state.rs +++ b/backend/src/endpoints/app_state.rs @@ -1,6 +1,9 @@ use crate::endpoints::api::{ spotify::services::SpotifyService, - telegram::services::{RealRssFetcher, RssFetcher}, + telegram::{ + models::TelegramCache, + services::{RealRssFetcher, RssFetcher}, + }, }; use std::sync::Arc; use tokio::sync::Mutex; @@ -8,6 +11,7 @@ use tokio::sync::Mutex; pub struct AppState { pub spotify_service: Mutex, pub rss_fetcher: Arc, + pub telegram_cache: Mutex>, } impl AppState { @@ -15,6 +19,7 @@ impl AppState { Self { spotify_service: Mutex::new(SpotifyService::new()), rss_fetcher: Arc::new(RealRssFetcher), + telegram_cache: Mutex::new(None), } } -} +} \ No newline at end of file diff --git a/frontend/app/[locale]/layout.tsx b/frontend/app/[locale]/layout.tsx index 73988de..4445fdf 100644 --- a/frontend/app/[locale]/layout.tsx +++ b/frontend/app/[locale]/layout.tsx @@ -16,7 +16,7 @@ import "@fontsource/material-symbols-outlined"; type Props = { children: React.ReactNode; - params: { locale: string }; + params: Promise<{ locale: string }>; }; export async function generateMetadata({ params }: Props): Promise { @@ -40,11 +40,10 @@ export function generateStaticParams() { } export default async function LocaleLayout({ children, params }: Props) { - // КЛЮЧЕВОЕ ИЗМЕНЕНИЕ: НЕ деструктурируем в сигнатуре. const { locale } = await params; unstable_setRequestLocale(locale); - const messages = await getMessages(); + const messages = await getMessages({ locale }); return ( @@ -60,15 +59,16 @@ export default async function LocaleLayout({ children, params }: Props) { __html: ` (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date(); - for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}\\n - k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})\\n - (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");\\n - ym(102356747, "init", {\\n - clickmap:true,\\n - trackLinks:true,\\n - accurateTrackBounce:true,\\n - webvisor:true\\n - });\\n + for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} + k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) + (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); + + ym(102356747, "init", { + clickmap:true, + trackLinks:true, + accurateTrackBounce:true, + webvisor:true + }); ` }} /> diff --git a/frontend/app/[locale]/telegram/components/TelegramPosts.tsx b/frontend/app/[locale]/telegram/components/TelegramPosts.tsx index 2332b76..47a06f7 100644 --- a/frontend/app/[locale]/telegram/components/TelegramPosts.tsx +++ b/frontend/app/[locale]/telegram/components/TelegramPosts.tsx @@ -1,7 +1,9 @@ 'use client'; + import { useEffect, useState } from 'react'; import PostList from './PostList'; import styles from '../styles/page.module.css'; +import { Skeleton } from '@/components/ui/skeleton'; interface Post { title: string; @@ -10,6 +12,26 @@ interface Post { imageUrl?: string; } +const PostSkeleton = () => { + return ( +
+
+ +
+ +
+ + +
+ + + +
+
+
+ ); +}; + const TelegramPosts: React.FC = () => { const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(true); @@ -25,30 +47,34 @@ const TelegramPosts: React.FC = () => { }) .then((data) => { setPosts(data); - setLoading(false); }) .catch((err) => { console.error('Ошибка загрузки:', err); setError('Не удалось загрузить посты.'); + }) + .finally(() => { setLoading(false); }); }, []); - if (loading) { - return
Загрузка постов...
; - } - if (error) { - return
{error}
; + return
{error}
; } return (

Последние посты из Telegram

- {posts.length > 0 ? ( + + {loading ? ( +
+ {[...Array(3)].map((_, index) => ( + + ))} +
+ ) : posts.length > 0 ? ( ) : ( -

Постов пока нет.

+

Постов пока нет.

)}
); diff --git a/frontend/app/i18n.ts b/frontend/app/i18n.ts deleted file mode 100644 index 2cfb23f..0000000 --- a/frontend/app/i18n.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {notFound} from 'next/navigation'; -import {getRequestConfig} from 'next-intl/server'; -import {locales as appLocales, type locale as LocaleType} from '@/types/i18n'; - -export default getRequestConfig(async ({locale}) => { - if (!appLocales.includes(locale as LocaleType)) notFound(); - - return { - locale, - messages: (await import(`../locales/${locale}.json`)).default, - timeZone: 'Europe/Moscow' - }; -}); \ No newline at end of file diff --git a/frontend/i18n.ts b/frontend/i18n.ts new file mode 100644 index 0000000..6a50986 --- /dev/null +++ b/frontend/i18n.ts @@ -0,0 +1,11 @@ +import { getRequestConfig } from 'next-intl/server'; + +export default getRequestConfig(async ({ requestLocale }) => { + let locale = await requestLocale; + // Ensure locale is defined, default to 'ru' or 'en' if necessary, though dynamic routing usually handles it. + if (!locale) locale = 'ru'; + + return { + messages: (await import(`./locales/${locale}.json`)).default + }; +}); diff --git a/frontend/i18n/request.ts b/frontend/i18n/request.ts new file mode 100644 index 0000000..a202b3b --- /dev/null +++ b/frontend/i18n/request.ts @@ -0,0 +1,17 @@ +import { getRequestConfig } from 'next-intl/server'; +import { locales } from '../types/i18n'; + +export default getRequestConfig(async ({ requestLocale }) => { + let locale = await requestLocale; + + // Validate that the incoming `locale` parameter is valid + // @ts-ignore + if (!locale || !locales.includes(locale)) { + locale = 'ru'; // Default fallback + } + + return { + locale, + messages: (await import(`../locales/${locale}.json`)).default + }; +}); diff --git a/frontend/i18n/request.ts.bak b/frontend/i18n/request.ts.bak new file mode 100644 index 0000000..501448d --- /dev/null +++ b/frontend/i18n/request.ts.bak @@ -0,0 +1,23 @@ +import {getRequestConfig} from 'next-intl/server'; +import {locales} from '../types/i18n'; // Импортируем твои локали + console.log('await import(`../locales/${locale}.json`)', await import(`../locales/${locale}.json`)); + +export default getRequestConfig(async ({requestLocale}) => { + // В документации пример статический, но у тебя роутинг [locale], + // поэтому нам нужно получить локаль из requestLocale. + let locale = await requestLocale; + + // Проверяем, валидна ли локаль. Если нет — берем 'en'. + // @ts-ignore - чтобы TS не ругался на string vs 'en'|'ru' + if (!locale || !locales.includes(locale)) { + locale = 'en'; + } + + console.log('await import(`../locales/${locale}.json`)', await import(`../locales/${locale}.json`)); + + return { + locale, + // Путь к JSON файлам. Из папки i18n выходим назад (..) в locales + messages: (await import(`../locales/${locale}.json`)).default + }; +}); \ No newline at end of file diff --git a/frontend/next.config.ts b/frontend/next.config.ts index c1a81e9..504dec9 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -1,70 +1,9 @@ -import type { NextConfig } from "next"; import createNextIntlPlugin from 'next-intl/plugin'; -const withNextIntl = createNextIntlPlugin('./app/i18n.ts'); - -/** @type {import('next').NextConfig} */ -const nextConfig: NextConfig = { - output: 'standalone', - images: { - remotePatterns: [ - { - protocol: 'https', - hostname: 'i.scdn.co', - port: '', - pathname: '/image/**', - }, - { - protocol: 'https', - hostname: 'www.codewars.com', - }, - { - protocol: 'https', - hostname: 'streak-stats.demolab.com', - }, - { - protocol: 'https', - hostname: 'github-readme-stats.vercel.app', - }, - { - protocol: 'https', - hostname: 'upload.wikimedia.org', - }, - { - protocol: 'https', - hostname: 'static-00.iconduck.com', - }, - { - protocol: 'https', - hostname: 'cdn.pixabay.com', - }, - { - protocol: 'https', - hostname: 'i.scdn.co', - }, - { - protocol: 'https', - hostname: 'cdn-icons-png.flaticon.com', - }, - { - protocol: 'https', - hostname: 'upload.wikimedia.org', - }, - { - protocol: 'https', - hostname: 'static-00.iconduck.com', - }, - { - protocol: 'https', - hostname: 'cdn.worldvectorlogo.com', - }, - { - protocol: 'https', - hostname: 'cdn*.cdn-telegram.org', - }, - ], - }, +const withNextIntl = createNextIntlPlugin(); +const nextConfig = { + reactStrictMode: true }; export default withNextIntl(nextConfig); \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 59f4957..f8fa203 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "@fontsource/material-symbols-outlined": "^5.2.12", - "@next/third-parties": "^15.3.3", + "@next/third-parties": "15.1.11", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-collapsible": "^1.1.2", "@radix-ui/react-dialog": "^1.1.5", @@ -21,10 +21,10 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.474.0", - "next": "^15.3.3", + "next": "15.1.11", "next-intl": "^3.26.3", "next-themes": "^0.4.4", - "react": "^19.0.0", + "react": "^19.2.3", "react-dom": "^19.0.0", "react-fast-marquee": "^1.6.5", "react-redux": "^9.2.0", @@ -39,7 +39,7 @@ "@types/react": "^19", "@types/react-dom": "^19", "eslint": "^9", - "eslint-config-next": "15.1.6", + "eslint-config-next": "15.1.11", "postcss": "^8", "tailwindcss": "^3.4.1" } @@ -57,9 +57,9 @@ } }, "node_modules/@emnapi/runtime": { - "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==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", "license": "MIT", "optional": true, "dependencies": { @@ -359,9 +359,9 @@ } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz", - "integrity": "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", "cpu": [ "arm64" ], @@ -377,13 +377,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.1.0" + "@img/sharp-libvips-darwin-arm64": "1.0.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz", - "integrity": "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", "cpu": [ "x64" ], @@ -399,13 +399,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.1.0" + "@img/sharp-libvips-darwin-x64": "1.0.4" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "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==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", "cpu": [ "arm64" ], @@ -419,9 +419,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "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==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", "cpu": [ "x64" ], @@ -435,9 +435,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "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==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", "cpu": [ "arm" ], @@ -451,9 +451,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "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==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", "cpu": [ "arm64" ], @@ -466,26 +466,10 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "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" - ], - "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.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==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", "cpu": [ "s390x" ], @@ -499,9 +483,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "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==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", "cpu": [ "x64" ], @@ -515,9 +499,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "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==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", "cpu": [ "arm64" ], @@ -531,9 +515,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "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==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", "cpu": [ "x64" ], @@ -547,9 +531,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz", - "integrity": "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", "cpu": [ "arm" ], @@ -565,13 +549,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.1.0" + "@img/sharp-libvips-linux-arm": "1.0.5" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz", - "integrity": "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", "cpu": [ "arm64" ], @@ -587,13 +571,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.1.0" + "@img/sharp-libvips-linux-arm64": "1.0.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz", - "integrity": "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", "cpu": [ "s390x" ], @@ -609,13 +593,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.1.0" + "@img/sharp-libvips-linux-s390x": "1.0.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz", - "integrity": "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", "cpu": [ "x64" ], @@ -631,13 +615,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.1.0" + "@img/sharp-libvips-linux-x64": "1.0.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz", - "integrity": "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", "cpu": [ "arm64" ], @@ -653,13 +637,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz", - "integrity": "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", "cpu": [ "x64" ], @@ -675,20 +659,20 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.1.0" + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz", - "integrity": "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", "cpu": [ "wasm32" ], "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.4.3" + "@emnapi/runtime": "^1.2.0" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -697,29 +681,10 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz", - "integrity": "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==", - "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.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz", - "integrity": "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", "cpu": [ "ia32" ], @@ -736,9 +701,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz", - "integrity": "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", "cpu": [ "x64" ], @@ -820,15 +785,15 @@ } }, "node_modules/@next/env": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.3.tgz", - "integrity": "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==", + "version": "15.1.11", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.11.tgz", + "integrity": "sha512-yp++FVldfLglEG5LoS2rXhGypPyoSOyY0kxZQJ2vnlYJeP8o318t5DrDu5Tqzr03qAhDWllAID/kOCsXNLcwKw==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "15.1.6", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.1.6.tgz", - "integrity": "sha512-+slMxhTgILUntZDGNgsKEYHUvpn72WP1YTlkmEhS51vnVd7S9jEEy0n9YAMcI21vUG4akTw9voWH02lrClt/yw==", + "version": "15.1.11", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.1.11.tgz", + "integrity": "sha512-jpAu+46v5FF/TO8YUdOBHn/Wr4SCiU4IgjQ45S9Nn3vR4nZVS2SR+m9lpxcCv/xqMUoYuYFQZUP0H/ptw0W6+w==", "dev": true, "license": "MIT", "dependencies": { @@ -836,9 +801,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.3.tgz", - "integrity": "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg==", + "version": "15.1.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.9.tgz", + "integrity": "sha512-sQF6MfW4nk0PwMYYq8xNgqyxZJGIJV16QqNDgaZ5ze9YoVzm4/YNx17X0exZudayjL9PF0/5RGffDtzXapch0Q==", "cpu": [ "arm64" ], @@ -852,9 +817,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.3.tgz", - "integrity": "sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw==", + "version": "15.1.9", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.9.tgz", + "integrity": "sha512-fp0c1rB6jZvdSDhprOur36xzQvqelAkNRXM/An92sKjjtaJxjlqJR8jiQLQImPsClIu8amQn+ZzFwl1lsEf62w==", "cpu": [ "x64" ], @@ -868,9 +833,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.3.tgz", - "integrity": "sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw==", + "version": "15.1.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.9.tgz", + "integrity": "sha512-77rYykF6UtaXvxh9YyRIKoaYPI6/YX6cy8j1DL5/1XkjbfOwFDfTEhH7YGPqG/ePl+emBcbDYC2elgEqY2e+ag==", "cpu": [ "arm64" ], @@ -884,9 +849,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.3.tgz", - "integrity": "sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA==", + "version": "15.1.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.9.tgz", + "integrity": "sha512-uZ1HazKcyWC7RA6j+S/8aYgvxmDqwnG+gE5S9MhY7BTMj7ahXKunpKuX8/BA2M7OvINLv7LTzoobQbw928p3WA==", "cpu": [ "arm64" ], @@ -900,9 +865,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.3.tgz", - "integrity": "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw==", + "version": "15.1.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.9.tgz", + "integrity": "sha512-gQIX1d3ct2RBlgbbWOrp+SHExmtmFm/HSW1Do5sSGMDyzbkYhS2sdq5LRDJWWsQu+/MqpgJHqJT6ORolKp/U1g==", "cpu": [ "x64" ], @@ -916,9 +881,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.3.tgz", - "integrity": "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw==", + "version": "15.1.9", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.9.tgz", + "integrity": "sha512-fJOwxAbCeq6Vo7pXZGDP6iA4+yIBGshp7ie2Evvge7S7lywyg7b/SGqcvWq/jYcmd0EbXdb7hBfdqSQwTtGTPg==", "cpu": [ "x64" ], @@ -932,9 +897,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.3.tgz", - "integrity": "sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ==", + "version": "15.1.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.9.tgz", + "integrity": "sha512-crfbUkAd9PVg9nGfyjSzQbz82dPvc4pb1TeP0ZaAdGzTH6OfTU9kxidpFIogw0DYIEadI7hRSvuihy2NezkaNQ==", "cpu": [ "arm64" ], @@ -948,9 +913,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.3.tgz", - "integrity": "sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw==", + "version": "15.1.9", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.9.tgz", + "integrity": "sha512-SBB0oA4E2a0axUrUwLqXlLkSn+bRx9OWU6LheqmRrO53QEAJP7JquKh3kF0jRzmlYOWFZtQwyIWJMEJMtvvDcQ==", "cpu": [ "x64" ], @@ -964,9 +929,9 @@ } }, "node_modules/@next/third-parties": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/third-parties/-/third-parties-15.3.3.tgz", - "integrity": "sha512-kwhDkK/3klTvW6SuNkmIMSqzEk9Rnc7PkpGeAi3x0mcbPJhFTwdC/qTEd/HZt53J2yFv73YohOBk6dUG3TEIkQ==", + "version": "15.1.11", + "resolved": "https://registry.npmjs.org/@next/third-parties/-/third-parties-15.1.11.tgz", + "integrity": "sha512-U9Nn+8H4dfE6KTmML34zu+yj96NgDqdOaql29JVjmRa+rD6woxEX7H1G4TA8VoF8eNAkMw4m2z7wgfeQ7N8OjA==", "license": "MIT", "dependencies": { "third-party-capital": "1.0.20" @@ -2567,9 +2532,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001696", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz", - "integrity": "sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==", + "version": "1.0.30001762", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", + "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", "funding": [ { "type": "opencollective", @@ -2887,9 +2852,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "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": { @@ -3222,13 +3187,13 @@ } }, "node_modules/eslint-config-next": { - "version": "15.1.6", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.1.6.tgz", - "integrity": "sha512-Wd1uy6y7nBbXUSg9QAuQ+xYEKli5CgUhLjz1QHW11jLDis5vK5XB3PemL6jEmy7HrdhaRFDz+GTZ/3FoH+EUjg==", + "version": "15.1.11", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.1.11.tgz", + "integrity": "sha512-RK5q3f8CKMTwNXULOqd2TAsz+7kA5+5fy5YK7T6SeczLFOuOUcuJOGlYUbyoeU6+UKQrpFsYgCz71hI1F9q5Cg==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "15.1.6", + "@next/eslint-plugin-next": "15.1.11", "@rushstack/eslint-patch": "^1.10.3", "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", @@ -4204,9 +4169,9 @@ } }, "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", "license": "MIT", "optional": true }, @@ -4952,12 +4917,12 @@ } }, "node_modules/next": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/next/-/next-15.3.3.tgz", - "integrity": "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw==", + "version": "15.1.11", + "resolved": "https://registry.npmjs.org/next/-/next-15.1.11.tgz", + "integrity": "sha512-UiVJaOGhKST58AadwbFUZThlNBmYhKqaCs8bVtm4plTxsgKq0mJ0zTsp7t7j/rzsbAEj9WcAMdZCztjByi4EoQ==", "license": "MIT", "dependencies": { - "@next/env": "15.3.3", + "@next/env": "15.1.11", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", @@ -4972,15 +4937,15 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.3.3", - "@next/swc-darwin-x64": "15.3.3", - "@next/swc-linux-arm64-gnu": "15.3.3", - "@next/swc-linux-arm64-musl": "15.3.3", - "@next/swc-linux-x64-gnu": "15.3.3", - "@next/swc-linux-x64-musl": "15.3.3", - "@next/swc-win32-arm64-msvc": "15.3.3", - "@next/swc-win32-x64-msvc": "15.3.3", - "sharp": "^0.34.1" + "@next/swc-darwin-arm64": "15.1.9", + "@next/swc-darwin-x64": "15.1.9", + "@next/swc-linux-arm64-gnu": "15.1.9", + "@next/swc-linux-arm64-musl": "15.1.9", + "@next/swc-linux-x64-gnu": "15.1.9", + "@next/swc-linux-x64-musl": "15.1.9", + "@next/swc-win32-arm64-msvc": "15.1.9", + "@next/swc-win32-x64-msvc": "15.1.9", + "sharp": "^0.33.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -5573,9 +5538,9 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", - "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5939,9 +5904,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.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "devOptional": true, "license": "ISC", "bin": { @@ -6001,16 +5966,16 @@ } }, "node_modules/sharp": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.2.tgz", - "integrity": "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", "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.6.3" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -6019,27 +5984,25 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.2", - "@img/sharp-darwin-x64": "0.34.2", - "@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.2", - "@img/sharp-linux-arm64": "0.34.2", - "@img/sharp-linux-s390x": "0.34.2", - "@img/sharp-linux-x64": "0.34.2", - "@img/sharp-linuxmusl-arm64": "0.34.2", - "@img/sharp-linuxmusl-x64": "0.34.2", - "@img/sharp-wasm32": "0.34.2", - "@img/sharp-win32-arm64": "0.34.2", - "@img/sharp-win32-ia32": "0.34.2", - "@img/sharp-win32-x64": "0.34.2" + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" } }, "node_modules/shebang-command": { @@ -6152,9 +6115,9 @@ } }, "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", "license": "MIT", "optional": true, "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 75071ee..7f86915 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@fontsource/material-symbols-outlined": "^5.2.12", - "@next/third-parties": "^15.3.3", + "@next/third-parties": "15.1.11", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-collapsible": "^1.1.2", "@radix-ui/react-dialog": "^1.1.5", @@ -22,10 +22,10 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.474.0", - "next": "^15.3.3", + "next": "15.1.11", "next-intl": "^3.26.3", "next-themes": "^0.4.4", - "react": "^19.0.0", + "react": "^19.2.3", "react-dom": "^19.0.0", "react-fast-marquee": "^1.6.5", "react-redux": "^9.2.0", @@ -40,8 +40,8 @@ "@types/react": "^19", "@types/react-dom": "^19", "eslint": "^9", - "eslint-config-next": "15.1.6", + "eslint-config-next": "15.1.11", "postcss": "^8", "tailwindcss": "^3.4.1" } -} +} \ No newline at end of file diff --git a/frontend/middleware.ts b/frontend/proxy.ts similarity index 74% rename from frontend/middleware.ts rename to frontend/proxy.ts index b13364c..f1fe8ac 100644 --- a/frontend/middleware.ts +++ b/frontend/proxy.ts @@ -1,18 +1,20 @@ import createMiddleware from 'next-intl/middleware'; import { locales, type locale as LocaleType } from './types/i18n'; -export default createMiddleware({ +const middleware = createMiddleware({ locales, defaultLocale: 'en' as LocaleType, localePrefix: 'always' }); +export function proxy(request: any) { + return middleware(request); +} + export const config = { matcher: [ '/', - '/(ru|en)/:path*', - '/((?!api|_next|.*\\..*).*)' ] }; \ No newline at end of file diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 88f2072..a859c87 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -57,7 +57,9 @@ "**/*.tsx", "frontend/.next/types/**/*.ts", "frontend/next-env.d.ts", - ".next/types/**/*.ts" + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "i18n/request.ts.bak" ], "exclude": [ "node_modules"