diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index eee816d..a1e6577 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,19 +1,12 @@ 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 +on: + push: + branches: [ main ] jobs: - build_frontend_image: - name: 1. Build Frontend Image - runs-on: ubuntu-latest + build_and_push: + runs-on: docker steps: - name: Checkout repository uses: actions/checkout@v4 @@ -46,19 +39,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - - # НОВЫЙ ШАГ: Устанавливаем Node.js - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - cache: 'npm' # Включаем кеширование для npm - cache-dependency-path: backend/package-lock.json - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - # ИЗМЕНЕННЫЙ ШАГ: Логика кеширования и сборки для Node.js - name: Build image and save as artifact uses: docker/build-push-action@v5 with: @@ -66,9 +48,12 @@ jobs: push: false load: true tags: diametrfq/website-backend:latest - cache-from: type=gha,scope=backend-build-v1 - cache-to: type=gha,mode=max,scope=backend-build-v1 - + 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 @@ -100,9 +85,7 @@ jobs: - 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 push diametrfq/website:latest docker load --input /tmp/backend.tar docker push diametrfq/website-backend:latest & - name: Wait for all pushes to complete @@ -114,21 +97,14 @@ jobs: needs: [push_images] steps: - uses: actions/checkout@v4 - - # ----- НОВЫЕ ШАГИ ----- - - name: Create deployment archive - run: tar -czvf deploy.tar.gz docker-compose.yml configs - - # ----- ИЗМЕНЕННЫЙ ШАГ ----- - name: Transfer Files to Server - uses: appleboy/scp-action@master + uses: appleboy/scp-action@v0.1.4 with: host: ${{ secrets.HOSTING_SERVER }} username: ${{ secrets.HOSTING_NAME }} password: ${{ secrets.HOSTING_PASSWORD }} - source: "deploy.tar.gz" # Передаем только один файл + source: "./docker-compose.yml,./configs,./nginx.prod.conf" target: "/myPath" - - name: Deploy to Server uses: appleboy/ssh-action@master with: @@ -136,14 +112,7 @@ jobs: username: ${{ secrets.HOSTING_NAME }} password: ${{ secrets.HOSTING_PASSWORD }} script: | - mkdir -p /myPath cd /myPath - - echo "Unpacking deployment files..." - tar -xzvf deploy.tar.gz - - rm deploy.tar.gz - export GRAFANA_ADMIN_PASSWORD=${{ secrets.GRAFANA_ADMIN_PASSWORD }} export SPOTIFY_CLIENT_ID=${{ secrets.SPOTIFY_CLIENT_ID }} export SPOTIFY_CLIENT_SECRET=${{ secrets.SPOTIFY_CLIENT_SECRET }} @@ -154,9 +123,5 @@ jobs: 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 \ No newline at end of file + 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 diff --git a/backend/.gitignore b/backend/.gitignore index 1ab4358..2decc9e 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -9,4 +9,6 @@ npm-debug.log* # misc -.DS_Store \ No newline at end of file +.DS_Store + +/target \ No newline at end of file diff --git a/backend/src/endpoints/api/telegram/services.rs b/backend/src/endpoints/api/telegram/services.rs new file mode 100644 index 0000000..813eba1 --- /dev/null +++ b/backend/src/endpoints/api/telegram/services.rs @@ -0,0 +1,142 @@ +use super::errors::{AppError, AppResult}; +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 { + async fn fetch_rss_content(&self, url: &str) -> AppResult; +} + +pub struct RealRssFetcher; + +#[async_trait] +impl RssFetcher for RealRssFetcher { + async fn fetch_rss_content(&self, url: &str) -> AppResult { + let response = reqwest::get(url).await.map_err(|e| { + log::error!("Network error while fetching RSS: {}", e); + AppError::ServiceErrorWithFallback + })?; + + if !response.status().is_success() { + log::error!( + "External service responded with non-success status: {}", + response.status() + ); + return Err(AppError::ServiceErrorWithFallback); + } + + Ok(response.bytes().await?) + } +} + +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()); + } + } + } + + 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 { + if html_content.is_empty() { + return String::new(); + } + let document = Html::parse_fragment(html_content); + let text_content = document.root_element().text().collect::>().join(" "); + text_content + .split_whitespace() + .collect::>() + .join(" ") +} + +fn extract_image_url(item: &rss::Item) -> Option { + if let Some(enclosure) = item.enclosure() { + if enclosure.mime_type().starts_with("image/") { + return Some(enclosure.url().to_string()); + } + } + let content_to_search = item.description().or_else(|| item.content()).unwrap_or(""); + if content_to_search.is_empty() { + return None; + } + match regex::Regex::new(r#"]+src=["']([^"']+)["']"#) { + Ok(re) => { + if let Some(cap) = re.captures(content_to_search) { + if let Some(url_match) = cap.get(1) { + return Some(url_match.as_str().to_string()); + } + } + } + Err(e) => { + log::error!("Regex compilation error in extract_image_url: {}", e); + } + } + 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..2dc3d1f --- /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"