From 8fc82a3b90b7464147612f471c96fd2396095239 Mon Sep 17 00:00:00 2001 From: home Date: Sat, 21 Feb 2026 16:36:58 +0300 Subject: [PATCH] =?UTF-8?q?feat(sidebar):=20=D1=83=D0=B7=D0=BA=D0=BE=D0=B5?= =?UTF-8?q?=20=D0=BC=D0=B5=D0=BD=D1=8E,=20=D1=81=D1=83=D0=B1=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=8E=20=D0=B8=D1=81=D1=82=D0=BE=D1=80=D0=B8=D0=B9=20?= =?UTF-8?q?=D1=81=20hover,=20=D1=8D=D1=84=D1=84=D0=B5=D0=BA=D1=82=20text-f?= =?UTF-8?q?ade?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Сужено боковое меню (56px), убрана иконка Home - Субменю историй при наведении: полная высота, на всю ширину, z-9999 - Класс text-fade для плавного обрезания длинного текста - Убраны скругления в субменю - Chatwoot, изменения в posts-mcs и прочие обновления Co-authored-by: Cursor --- .env.example | 3 + apps/chatwoot/.env.example | 31 + apps/chatwoot/README.md | 50 + apps/chatwoot/docker-compose.yaml | 78 + apps/frontend/src/app/api/discover/route.ts | 114 +- apps/frontend/src/app/discover/page.tsx | 125 +- apps/frontend/src/app/globals.css | 7 + apps/frontend/src/app/layout.tsx | 6 +- apps/frontend/src/app/library/layout.tsx | 2 +- apps/frontend/src/app/library/page.tsx | 146 +- apps/frontend/src/components/ChatWindow.tsx | 5 +- .../src/components/Discover/MajorNewsCard.tsx | 12 +- .../src/components/Discover/SmallNewsCard.tsx | 6 +- apps/frontend/src/components/EmptyChat.tsx | 32 +- apps/frontend/src/components/Layout.tsx | 2 +- apps/frontend/src/components/MessageBox.tsx | 10 +- .../components/MessageInputActions/Attach.tsx | 9 +- .../MessageInputActions/AttachSmall.tsx | 10 +- .../MessageInputActions/ChatModelSelector.tsx | 18 +- .../MessageInputActions/Optimization.tsx | 4 +- .../MessageInputActions/Sources.tsx | 4 +- .../src/components/NewsArticleWidget.tsx | 18 +- .../Sections/Models/AddModelDialog.tsx | 8 +- .../Sections/Models/AddProviderDialog.tsx | 8 +- .../Sections/Models/DeleteProviderDialog.tsx | 8 +- .../Sections/Models/UpdateProviderDialog.tsx | 8 +- .../components/Settings/SettingsDialogue.tsx | 19 +- .../src/components/Settings/SettingsField.tsx | 11 - apps/frontend/src/components/Sidebar.tsx | 238 +- .../frontend/src/components/WeatherWidget.tsx | 26 +- apps/frontend/src/components/ui/Select.tsx | 8 +- .../frontend/src/lib/localization/context.tsx | 10 + .../lib/localization/embeddedTranslations.ts | 60 + apps/posts-mcs/.dockerignore | 5 - apps/posts-mcs/.gitignore | 5 - apps/posts-mcs/Dockerfile | 14 - apps/posts-mcs/README.md | 70 - apps/posts-mcs/docker-compose.yaml | 42 + apps/posts-mcs/drizzle.config.ts | 11 - apps/posts-mcs/entrypoint.sh | 5 - apps/posts-mcs/package-lock.json | 3145 ----------------- apps/posts-mcs/package.json | 26 - apps/posts-mcs/searxng-engine-example.yml | 18 - apps/posts-mcs/src/db/index.ts | 13 - apps/posts-mcs/src/db/schema.ts | 41 - apps/posts-mcs/src/index.ts | 41 - apps/posts-mcs/src/init-db.ts | 26 - apps/posts-mcs/src/lib/content.ts | 22 - apps/posts-mcs/src/lib/scheduler.ts | 25 - apps/posts-mcs/src/routes/publications.ts | 226 -- apps/posts-mcs/src/routes/search.ts | 63 - apps/posts-mcs/tsconfig.json | 13 - package.json | 2 + 53 files changed, 894 insertions(+), 4015 deletions(-) create mode 100644 apps/chatwoot/.env.example create mode 100644 apps/chatwoot/README.md create mode 100644 apps/chatwoot/docker-compose.yaml delete mode 100644 apps/posts-mcs/.dockerignore delete mode 100644 apps/posts-mcs/.gitignore delete mode 100644 apps/posts-mcs/Dockerfile delete mode 100644 apps/posts-mcs/README.md create mode 100644 apps/posts-mcs/docker-compose.yaml delete mode 100644 apps/posts-mcs/drizzle.config.ts delete mode 100644 apps/posts-mcs/entrypoint.sh delete mode 100644 apps/posts-mcs/package-lock.json delete mode 100644 apps/posts-mcs/package.json delete mode 100644 apps/posts-mcs/searxng-engine-example.yml delete mode 100644 apps/posts-mcs/src/db/index.ts delete mode 100644 apps/posts-mcs/src/db/schema.ts delete mode 100644 apps/posts-mcs/src/index.ts delete mode 100644 apps/posts-mcs/src/init-db.ts delete mode 100644 apps/posts-mcs/src/lib/content.ts delete mode 100644 apps/posts-mcs/src/lib/scheduler.ts delete mode 100644 apps/posts-mcs/src/routes/publications.ts delete mode 100644 apps/posts-mcs/src/routes/search.ts delete mode 100644 apps/posts-mcs/tsconfig.json diff --git a/.env.example b/.env.example index b77d412..4c41a9c 100644 --- a/.env.example +++ b/.env.example @@ -22,4 +22,7 @@ LLM_EMBEDDING_MODEL=nomic-embed-text # Запустите свой: docker run -d -p 4000:8080 searxng/searxng # SEARXNG_API_URL=http://localhost:4000 # SEARXNG_FALLBACK_URL= # через запятую, если основной недоступен +# Ghost — вкладка Dooseek. Локально: port 2369 (или 2368) +# GHOST_URL=http://localhost:2369 +# GHOST_CONTENT_API_KEY=ключ из Admin → Integrations # DATA_DIR=./data diff --git a/apps/chatwoot/.env.example b/apps/chatwoot/.env.example new file mode 100644 index 0000000..89ff28d --- /dev/null +++ b/apps/chatwoot/.env.example @@ -0,0 +1,31 @@ +# Chatwoot — минимальная конфигурация +# Скопируйте в .env и заполните обязательные поля + +# === Обязательно === +# Сгенерировать: openssl rand -hex 64 +SECRET_KEY_BASE= + +# Пароль PostgreSQL (обязательно) +POSTGRES_PASSWORD= + +# URL фронтенда (где открывать Chatwoot) +FRONTEND_URL=http://localhost:3001 + +# === PostgreSQL === +POSTGRES_HOST=postgres +POSTGRES_USERNAME=postgres +RAILS_ENV=production + +# === Redis === +REDIS_URL=redis://redis:6379 +# Для production задайте REDIS_PASSWORD и REDIS_URL=redis://:пароль@redis:6379 +REDIS_PASSWORD= + +# === Опционально === +# Регистрация новых аккаунтов (true/false) +ENABLE_ACCOUNT_SIGNUP=true + +# SMTP — для локальной разработки используйте MailHog (docker compose включает его) +# SMTP_ADDRESS=mailhog +# SMTP_PORT=1025 +# MAILER_SENDER_EMAIL=chatwoot@localhost diff --git a/apps/chatwoot/README.md b/apps/chatwoot/README.md new file mode 100644 index 0000000..147477b --- /dev/null +++ b/apps/chatwoot/README.md @@ -0,0 +1,50 @@ +# Chatwoot — self-hosted live chat + +Live chat для клиентской поддержки. Данные на вашем сервере. + +## Быстрый старт + +### 1. Подготовка + +```bash +cd chatwoot +cp .env.example .env +``` + +### 2. Заполнить .env + +Обязательно задать: + +- **SECRET_KEY_BASE** — сгенерировать: `openssl rand -hex 64` +- **POSTGRES_PASSWORD** — пароль для PostgreSQL + +### 3. Запуск + +```bash +# Инициализация БД (выполнить один раз) +docker compose run --rm rails bundle exec rails db:chatwoot_prepare + +# Запуск +docker compose up -d +``` + +### 4. Доступ + +- **Интерфейс:** http://localhost:3001 +- Создайте аккаунт при первом входе (если `ENABLE_ACCOUNT_SIGNUP=true`) + +## Встраивание виджета + +После создания инбокса в панели Chatwoot скопируйте код виджета и вставьте на сайт перед ``. + +## Полезные команды + +```bash +# Остановить +docker compose down + +# Обновить до новой версии +docker compose pull +docker compose run --rm rails bundle exec rails db:chatwoot_prepare +docker compose up -d +``` diff --git a/apps/chatwoot/docker-compose.yaml b/apps/chatwoot/docker-compose.yaml new file mode 100644 index 0000000..046fc9d --- /dev/null +++ b/apps/chatwoot/docker-compose.yaml @@ -0,0 +1,78 @@ +# Chatwoot — self-hosted live chat +# Документация: https://developers.chatwoot.com/self-hosted + +x-app: &app + image: chatwoot/chatwoot:latest + env_file: .env + volumes: + - storage_data:/app/storage + +services: + rails: + <<: *app + depends_on: + - postgres + - redis + - mailhog + ports: + - "127.0.0.1:3001:3000" + environment: + - NODE_ENV=production + - RAILS_ENV=production + - INSTALLATION_ENV=docker + entrypoint: docker/entrypoints/rails.sh + command: ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"] + restart: unless-stopped + + sidekiq: + <<: *app + depends_on: + - postgres + - redis + - mailhog + environment: + - NODE_ENV=production + - RAILS_ENV=production + - INSTALLATION_ENV=docker + command: ["bundle", "exec", "sidekiq", "-C", "config/sidekiq.yml"] + restart: unless-stopped + + postgres: + image: pgvector/pgvector:pg16 + restart: unless-stopped + volumes: + - postgres_data:/var/lib/postgresql/data + environment: + - POSTGRES_DB=chatwoot + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + mailhog: + image: mailhog/mailhog:latest + restart: unless-stopped + ports: + - "1025:1025" + - "8025:8025" + + redis: + image: redis:alpine + restart: unless-stopped + command: ["sh", "-c", "redis-server $${REDIS_PASSWORD:+--requirepass \"$$REDIS_PASSWORD\"}"] + env_file: .env + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 + +volumes: + storage_data: + postgres_data: + redis_data: diff --git a/apps/frontend/src/app/api/discover/route.ts b/apps/frontend/src/app/api/discover/route.ts index f6d18e2..4fd2010 100644 --- a/apps/frontend/src/app/api/discover/route.ts +++ b/apps/frontend/src/app/api/discover/route.ts @@ -2,14 +2,34 @@ import { searchSearxng, type SearxngSearchResult } from '@/lib/searxng'; import configManager from '@/lib/config'; import { getSearxngURL } from '@/lib/config/serverRegistry'; +const GHOST_URL = process.env.GHOST_URL?.trim() ?? ''; +const GHOST_CONTENT_API_KEY = process.env.GHOST_CONTENT_API_KEY?.trim() ?? ''; +const PLACEHOLDER_IMAGE = 'https://placehold.co/400x225/e5e7eb/6b7280?text=Post'; + type Region = 'america' | 'eu' | 'russia' | 'china'; -type Topic = 'tech' | 'finance' | 'art' | 'sports' | 'entertainment'; +type Topic = 'tech' | 'finance' | 'art' | 'sports' | 'entertainment' | 'gooseek'; + +interface GhostPost { + title: string; + excerpt?: string | null; + custom_excerpt?: string | null; + meta_description?: string | null; + plaintext?: string | null; + html?: string | null; + feature_image?: string | null; + url: string; +} + +function stripHtml(html: string): string { + return html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim(); +} const SOURCES_BY_REGION: Record< Region, Record > = { america: { + gooseek: { query: [], links: [] }, tech: { query: ['technology news', 'latest tech', 'AI', 'science and innovation'], links: ['techcrunch.com', 'wired.com', 'theverge.com', 'arstechnica.com'], @@ -32,6 +52,7 @@ const SOURCES_BY_REGION: Record< }, }, eu: { + gooseek: { query: [], links: [] }, tech: { query: ['technology news', 'tech', 'AI', 'innovation'], links: ['techcrunch.com', 'bbc.com', 'theguardian.com', 'reuters.com', 'euronews.com'], @@ -54,6 +75,7 @@ const SOURCES_BY_REGION: Record< }, }, russia: { + gooseek: { query: [], links: [] }, tech: { query: ['technology news', 'tech', 'IT', 'innovation'], links: ['tass.com', 'ria.ru', 'interfax.com', 'kommersant.ru', 'vedomosti.ru'], @@ -76,6 +98,7 @@ const SOURCES_BY_REGION: Record< }, }, china: { + gooseek: { query: [], links: [] }, tech: { query: ['technology news', 'tech', 'AI', 'innovation'], links: ['scmp.com', 'xinhuanet.com', 'chinadaily.com.cn', 'reuters.com'], @@ -137,8 +160,91 @@ const COUNTRY_TO_REGION: Record = { DK: 'eu', }; +async function fetchDooseekPosts(): Promise< + { title: string; content: string; url: string; thumbnail: string }[] +> { + if (!GHOST_URL || !GHOST_CONTENT_API_KEY) { + throw new Error( + 'Ghost не настроен. Укажите GHOST_URL и GHOST_CONTENT_API_KEY в .env', + ); + } + const base = GHOST_URL.replace(/\/$/, ''); + const apiUrl = `${base}/ghost/api/content/posts/?key=${GHOST_CONTENT_API_KEY}&limit=50&fields=title,excerpt,custom_excerpt,meta_description,html,feature_image,url&formats=html`; + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 15_000); + try { + const res = await fetch(apiUrl, { + signal: controller.signal, + headers: { Accept: 'application/json' }, + }); + clearTimeout(timeoutId); + if (!res.ok) { + if (res.status === 401) { + throw new Error( + 'Неверный Ghost Content API Key. Получите ключ в Ghost Admin → Settings → Integrations → Add custom integration.', + ); + } + throw new Error(`Ghost API: HTTP ${res.status}`); + } + const data = await res.json(); + const posts: GhostPost[] = data.posts ?? []; + return posts.map((p) => { + const excerpt = + p.custom_excerpt?.trim() || + p.meta_description?.trim() || + p.excerpt?.trim() || + p.plaintext?.trim() || + (p.html ? stripHtml(p.html) : ''); + const content = excerpt + ? excerpt.slice(0, 300) + (excerpt.length > 300 ? '…' : '') + : (p.title ? `${p.title}. Читать далее →` : 'Читать далее →'); + return { + title: p.title || 'Без названия', + content, + url: p.url, + thumbnail: p.feature_image?.trim() || PLACEHOLDER_IMAGE, + }; + }); + } catch (e) { + clearTimeout(timeoutId); + throw e; + } +} + export const GET = async (req: Request) => { try { + const params = new URL(req.url).searchParams; + + const mode: 'normal' | 'preview' = + (params.get('mode') as 'normal' | 'preview') || 'normal'; + const topic: Topic = (params.get('topic') as Topic) || 'tech'; + + if (topic === 'gooseek') { + try { + const blogs = await fetchDooseekPosts(); + return Response.json({ blogs }, { status: 200 }); + } catch (e) { + const msg = + e instanceof Error ? e.message : String(e); + const isConnect = + msg.includes('ECONNREFUSED') || + msg.includes('fetch failed') || + msg.includes('Failed to fetch') || + msg.includes('AbortError'); + return Response.json( + { + message: + !GHOST_URL || !GHOST_CONTENT_API_KEY + ? 'Ghost не настроен. Укажите GHOST_URL и GHOST_CONTENT_API_KEY в .env' + : isConnect + ? 'Не удалось подключиться к Ghost. Проверьте GHOST_URL и доступность сайта.' + : `Ошибка загрузки постов: ${msg}`, + }, + { status: isConnect ? 503 : 500 }, + ); + } + } + const searxngURL = getSearxngURL(); if (!searxngURL?.trim()) { return Response.json( @@ -149,12 +255,6 @@ export const GET = async (req: Request) => { { status: 503 }, ); } - - const params = new URL(req.url).searchParams; - - const mode: 'normal' | 'preview' = - (params.get('mode') as 'normal' | 'preview') || 'normal'; - const topic: Topic = (params.get('topic') as Topic) || 'tech'; const regionParam = params.get('region') as Region | null; let region: Region = 'america'; diff --git a/apps/frontend/src/app/discover/page.tsx b/apps/frontend/src/app/discover/page.tsx index 0663da2..9752085 100644 --- a/apps/frontend/src/app/discover/page.tsx +++ b/apps/frontend/src/app/discover/page.tsx @@ -112,7 +112,9 @@ const Page = () => { throw new Error(data.message || 'Failed to load articles'); } - data.blogs = data.blogs.filter((blog: Discover) => blog.thumbnail); + if (topic !== 'gooseek') { + data.blogs = data.blogs.filter((blog: Discover) => blog.thumbnail); + } setDiscover(data.blogs); } catch (err: unknown) { @@ -131,9 +133,7 @@ const Page = () => { useEffect(() => { if (activeTopic === 'gooseek') { - setLoading(false); - setDiscover(null); - setSetupRequired(false); + fetchArticles('gooseek'); return; } fetchArticles(activeTopic); @@ -170,26 +170,95 @@ const Page = () => { {loading ? ( -
- +
+ {/* Mobile: SmallNewsCard — rounded-3xl, aspect-video, p-4, h3 mb-2 + p */} +
+
+ {[1, 2, 3, 4].map((i) => ( +
+
+
+
+
+
+
+
+
+ ))} +
+
+ {/* Desktop: точно как реальный layout — 1st Major isLeft=false (текст слева, картинка справа) */} +
+ {/* 1st MajorNewsCard isLeft=FALSE: content LEFT, image RIGHT */} +
+
+
+
+
+
+
+
+
+
+ {/* 3× SmallNewsCard */} +
+ {[1, 2, 3].map((i) => ( +
+
+
+
+
+
+
+
+
+ ))} +
+
+ {/* 2nd MajorNewsCard isLeft=TRUE: image LEFT, content RIGHT */} +
+
+
+
+
+
+
+
+
+ {/* 3rd MajorNewsCard isLeft=FALSE: content LEFT, image RIGHT */} +
+
+
+
+
+
+
+
+ {/* 3× SmallNewsCard */} +
+ {[1, 2, 3].map((i) => ( +
+
+
+
+
+
+
+
+
+ ))} +
+
- ) : activeTopic === 'gooseek' ? ( -
) : setupRequired ? (
@@ -205,7 +274,7 @@ const Page = () => {

- ) : ( + ) : discover && discover.length > 0 ? (
@@ -342,7 +411,13 @@ const Page = () => { })()}
- )} + ) : discover && discover.length === 0 ? ( +
+

+ No articles found for this topic. +

+
+ ) : null}
); diff --git a/apps/frontend/src/app/globals.css b/apps/frontend/src/app/globals.css index 24ee05a..c4ed7a4 100644 --- a/apps/frontend/src/app/globals.css +++ b/apps/frontend/src/app/globals.css @@ -80,6 +80,13 @@ line-clamp: 2; overflow: hidden; } + + .text-fade { + overflow: hidden; + white-space: nowrap; + mask-image: linear-gradient(to right, black 75%, transparent 100%); + -webkit-mask-image: linear-gradient(to right, black 75%, transparent 100%); + } } @media screen and (-webkit-min-device-pixel-ratio: 0) { diff --git a/apps/frontend/src/app/layout.tsx b/apps/frontend/src/app/layout.tsx index b7ab23c..3945456 100644 --- a/apps/frontend/src/app/layout.tsx +++ b/apps/frontend/src/app/layout.tsx @@ -41,11 +41,9 @@ export default function RootLayout({ {setupComplete ? ( - -
-
+
} > diff --git a/apps/frontend/src/app/library/layout.tsx b/apps/frontend/src/app/library/layout.tsx index 835edf6..750090d 100644 --- a/apps/frontend/src/app/library/layout.tsx +++ b/apps/frontend/src/app/library/layout.tsx @@ -2,7 +2,7 @@ import { Metadata } from 'next'; import React from 'react'; export const metadata: Metadata = { - title: 'Library - GooSeek', + title: 'History - GooSeek', }; const Layout = ({ children }: { children: React.ReactNode }) => { diff --git a/apps/frontend/src/app/library/page.tsx b/apps/frontend/src/app/library/page.tsx index 199f14c..e2d4aca 100644 --- a/apps/frontend/src/app/library/page.tsx +++ b/apps/frontend/src/app/library/page.tsx @@ -2,9 +2,17 @@ import DeleteChat from '@/components/DeleteChat'; import { formatTimeDifference } from '@/lib/utils'; -import { BookOpenText, ClockIcon, FileText, Globe2Icon } from 'lucide-react'; +import { + ClockIcon, + FileText, + Globe2Icon, + MessagesSquare, + Search, + Filter, +} from 'lucide-react'; import Link from 'next/link'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; +import { useTranslation } from '@/lib/localization/context'; export interface Chat { id: string; @@ -14,9 +22,18 @@ export interface Chat { files: { fileId: string; name: string }[]; } +const SOURCE_KEYS = ['web', 'academic', 'discussions'] as const; +type SourceKey = (typeof SOURCE_KEYS)[number]; + +type FilesFilter = 'all' | 'with' | 'without'; + const Page = () => { + const { t } = useTranslation(); const [chats, setChats] = useState([]); const [loading, setLoading] = useState(true); + const [searchQuery, setSearchQuery] = useState(''); + const [sourceFilter, setSourceFilter] = useState('all'); + const [filesFilter, setFilesFilter] = useState('all'); useEffect(() => { const fetchChats = async () => { @@ -30,23 +47,41 @@ const Page = () => { }); const data = await res.json(); - - setChats(data.chats); + setChats(data.chats ?? []); setLoading(false); }; fetchChats(); }, []); + const filteredChats = useMemo(() => { + return chats.filter((chat) => { + const matchesSearch = + !searchQuery.trim() || + chat.title.toLowerCase().includes(searchQuery.trim().toLowerCase()); + + const matchesSource = + sourceFilter === 'all' || + chat.sources.some((s) => s === sourceFilter); + + const matchesFiles = + filesFilter === 'all' || + (filesFilter === 'with' && chat.files.length > 0) || + (filesFilter === 'without' && chat.files.length === 0); + + return matchesSearch && matchesSource && matchesFiles; + }); + }, [chats, searchQuery, sourceFilter, filesFilter]); + return (
- +

- Library + {t('nav.messageHistory')}

Past chats, sources, and uploads. @@ -56,38 +91,78 @@ const Page = () => {
- - {loading - ? 'Loading…' + + {loading && chats.length === 0 + ? '—' : `${chats.length} ${chats.length === 1 ? 'chat' : 'chats'}`}
- {loading ? ( -
-
+
+ - setSearchQuery(e.target.value)} + placeholder={t('app.searchPlaceholder')} + className="w-full pl-10 pr-4 py-2.5 text-sm bg-light-secondary dark:bg-dark-secondary border border-light-200 dark:border-dark-200 rounded-xl placeholder:text-black/40 dark:placeholder:text-white/40 text-black dark:text-white focus:outline-none focus:border-light-300 dark:focus:border-dark-300 transition-colors" /> - +
+
+ + + +
+
+ )} + + {loading && chats.length === 0 ? ( +
+
+ {[1, 2, 3, 4].map((i) => ( +
+
+
+
+
+
+
+ ))} +
) : chats.length === 0 ? (
- +

No chats found. @@ -99,10 +174,27 @@ const Page = () => { to see it listed here.

+ ) : filteredChats.length === 0 ? ( +
+

+ {t('library.noResults')} +

+ +
) : (
- {chats.map((chat, index) => { + {filteredChats.map((chat, index) => { const sourcesLabel = chat.sources.length === 0 ? null diff --git a/apps/frontend/src/components/ChatWindow.tsx b/apps/frontend/src/components/ChatWindow.tsx index 4d0737d..f9bf11c 100644 --- a/apps/frontend/src/components/ChatWindow.tsx +++ b/apps/frontend/src/components/ChatWindow.tsx @@ -7,7 +7,6 @@ import NextError from 'next/error'; import { useChat } from '@/lib/hooks/useChat'; import SettingsButtonMobile from './Settings/SettingsButtonMobile'; import { Block } from '@/lib/types'; -import Loader from './ui/Loader'; export interface BaseMessage { chatId: string; @@ -69,8 +68,8 @@ const ChatWindow = () => {
) ) : ( -
- +
+
); }; diff --git a/apps/frontend/src/components/Discover/MajorNewsCard.tsx b/apps/frontend/src/components/Discover/MajorNewsCard.tsx index 364531e..8c676b2 100644 --- a/apps/frontend/src/components/Discover/MajorNewsCard.tsx +++ b/apps/frontend/src/components/Discover/MajorNewsCard.tsx @@ -18,11 +18,7 @@ const MajorNewsCard = ({
{item.title}
@@ -52,11 +48,7 @@ const MajorNewsCard = ({
{item.title}
diff --git a/apps/frontend/src/components/Discover/SmallNewsCard.tsx b/apps/frontend/src/components/Discover/SmallNewsCard.tsx index f1f8e36..f7755d3 100644 --- a/apps/frontend/src/components/Discover/SmallNewsCard.tsx +++ b/apps/frontend/src/components/Discover/SmallNewsCard.tsx @@ -10,11 +10,7 @@ const SmallNewsCard = ({ item }: { item: Discover }) => (
{item.title}
diff --git a/apps/frontend/src/components/EmptyChat.tsx b/apps/frontend/src/components/EmptyChat.tsx index b4ab7f4..31f6518 100644 --- a/apps/frontend/src/components/EmptyChat.tsx +++ b/apps/frontend/src/components/EmptyChat.tsx @@ -46,7 +46,7 @@ const EmptyChat = () => {
-
+
{['G', 'o', 'o', 'S', 'e', 'e', 'k'].map((letter, i) => ( @@ -54,7 +54,7 @@ const EmptyChat = () => { key={i} className="inline-block" style={{ - color: ['#6B7280', '#EA580C', '#9CA3AF', '#4B5563', '#EA580C', '#A8A29E', '#57534E'][i], + color: ['#4285F4', '#FC3F1D', '#34A853', '#FBBC05', '#FC3F1D', '#4285F4', '#34A853'][i], }} > {letter} @@ -65,22 +65,22 @@ const EmptyChat = () => {

{t('empty.subtitle')}

+ {(showWeather || showNews) && ( +
+ {showWeather && ( +
+ +
+ )} + {showNews && ( +
+ +
+ )} +
+ )}
- {(showWeather || showNews) && ( -
- {showWeather && ( -
- -
- )} - {showNews && ( -
- -
- )} -
- )}
); diff --git a/apps/frontend/src/components/Layout.tsx b/apps/frontend/src/components/Layout.tsx index 00f0fff..534ba1b 100644 --- a/apps/frontend/src/components/Layout.tsx +++ b/apps/frontend/src/components/Layout.tsx @@ -1,6 +1,6 @@ const Layout = ({ children }: { children: React.ReactNode }) => { return ( -
+
{children}
); diff --git a/apps/frontend/src/components/MessageBox.tsx b/apps/frontend/src/components/MessageBox.tsx index 4167640..45589bc 100644 --- a/apps/frontend/src/components/MessageBox.tsx +++ b/apps/frontend/src/components/MessageBox.tsx @@ -179,7 +179,7 @@ const MessageBox = ({ (b) => b.type === 'research' && b.data.subSteps.length > 0, ) && (
- + {t('chat.brainstorming')} @@ -191,13 +191,7 @@ const MessageBox = ({
{sources.length > 0 && (
- +

{t('chat.answer')}

diff --git a/apps/frontend/src/components/MessageInputActions/Attach.tsx b/apps/frontend/src/components/MessageInputActions/Attach.tsx index b9a7f37..6bb1f82 100644 --- a/apps/frontend/src/components/MessageInputActions/Attach.tsx +++ b/apps/frontend/src/components/MessageInputActions/Attach.tsx @@ -9,7 +9,6 @@ import { CopyPlus, File, Link, - LoaderCircle, Paperclip, Plus, Trash, @@ -56,8 +55,8 @@ const Attach = () => { }; return loading ? ( -
- +
+ Uploading…
) : files.length > 0 ? ( @@ -72,7 +71,7 @@ const Attach = () => { {open && ( { animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.9 }} transition={{ duration: 0.1, ease: 'easeOut' }} - className="origin-top-right bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col" + className="origin-bottom-right bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col" >

diff --git a/apps/frontend/src/components/MessageInputActions/AttachSmall.tsx b/apps/frontend/src/components/MessageInputActions/AttachSmall.tsx index 2e72368..3c23c59 100644 --- a/apps/frontend/src/components/MessageInputActions/AttachSmall.tsx +++ b/apps/frontend/src/components/MessageInputActions/AttachSmall.tsx @@ -4,7 +4,7 @@ import { PopoverPanel, Transition, } from '@headlessui/react'; -import { File, LoaderCircle, Paperclip, Plus, Trash } from 'lucide-react'; +import { File, Paperclip, Plus, Trash } from 'lucide-react'; import { Fragment, useRef, useState } from 'react'; import { useChat } from '@/lib/hooks/useChat'; import { AnimatePresence } from 'motion/react'; @@ -47,8 +47,8 @@ const AttachSmall = () => { }; return loading ? ( -
- +
+ Uploading…
) : files.length > 0 ? ( @@ -63,7 +63,7 @@ const AttachSmall = () => { {open && ( { animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.9 }} transition={{ duration: 0.1, ease: 'easeOut' }} - className="origin-bottom-left bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col" + className="origin-bottom-right bg-light-primary dark:bg-dark-primary border rounded-md border-light-200 dark:border-dark-200 w-full max-h-[200px] md:max-h-none overflow-y-auto flex flex-col" >

diff --git a/apps/frontend/src/components/MessageInputActions/ChatModelSelector.tsx b/apps/frontend/src/components/MessageInputActions/ChatModelSelector.tsx index 391f40b..80c9839 100644 --- a/apps/frontend/src/components/MessageInputActions/ChatModelSelector.tsx +++ b/apps/frontend/src/components/MessageInputActions/ChatModelSelector.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Cpu, Loader2, Search } from 'lucide-react'; +import { Cpu, Search } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react'; import { useEffect, useMemo, useState } from 'react'; @@ -90,7 +90,7 @@ const ModelSelector = () => { {open && ( { animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.9 }} transition={{ duration: 0.1, ease: 'easeOut' }} - className="origin-top-right bg-light-primary dark:bg-dark-primary max-h-[300px] sm:max-w-none border rounded-lg border-light-200 dark:border-dark-200 w-full flex flex-col shadow-lg overflow-hidden" + className="origin-bottom-right bg-light-primary dark:bg-dark-primary max-h-[300px] sm:max-w-none border rounded-lg border-light-200 dark:border-dark-200 w-full flex flex-col shadow-lg overflow-hidden" >
@@ -118,11 +118,13 @@ const ModelSelector = () => {
{isLoading ? ( -
- +
+ {[1, 2, 3, 4].map((i) => ( +
+ ))}
) : filteredProviders.length === 0 ? (
diff --git a/apps/frontend/src/components/MessageInputActions/Optimization.tsx b/apps/frontend/src/components/MessageInputActions/Optimization.tsx index ef19c29..dc19fd0 100644 --- a/apps/frontend/src/components/MessageInputActions/Optimization.tsx +++ b/apps/frontend/src/components/MessageInputActions/Optimization.tsx @@ -64,7 +64,7 @@ const Optimization = () => { {open && ( { animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.9 }} transition={{ duration: 0.1, ease: 'easeOut' }} - className="origin-top-left flex flex-col space-y-2 bg-light-primary dark:bg-dark-primary border rounded-lg border-light-200 dark:border-dark-200 w-full p-2 max-h-[200px] md:max-h-none overflow-y-auto" + className="origin-bottom-left flex flex-col space-y-2 bg-light-primary dark:bg-dark-primary border rounded-lg border-light-200 dark:border-dark-200 w-full p-2 max-h-[200px] md:max-h-none overflow-y-auto" > {OptimizationModes.map((mode, i) => ( { {open && ( {sourcesList.map((source, i) => (
{ }, []); return ( -
+
{loading ? (
-
-
-
-
+
+
+
+
) : error ? ( @@ -43,7 +43,7 @@ const NewsArticleWidget = () => { href={`/?q=${encodeURIComponent(`Summary: ${article.url}`)}&title=${encodeURIComponent(article.title)}`} className="flex flex-row items-stretch w-full h-full relative overflow-hidden group" > -
+
{ alt={article.title} />
-
-
+
+
{article.title}
-

+

{article.content}

diff --git a/apps/frontend/src/components/Settings/Sections/Models/AddModelDialog.tsx b/apps/frontend/src/components/Settings/Sections/Models/AddModelDialog.tsx index ffb2ca8..50d7c96 100644 --- a/apps/frontend/src/components/Settings/Sections/Models/AddModelDialog.tsx +++ b/apps/frontend/src/components/Settings/Sections/Models/AddModelDialog.tsx @@ -1,5 +1,5 @@ import { Dialog, DialogPanel } from '@headlessui/react'; -import { Loader2, Plus } from 'lucide-react'; +import { Plus } from 'lucide-react'; import { useState } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import { ConfigModelProvider } from '@/lib/config/types'; @@ -142,11 +142,7 @@ const AddModel = ({ disabled={loading} className="px-4 py-2 rounded-lg text-[13px] bg-[#EA580C] text-white font-medium disabled:opacity-85 hover:opacity-85 active:scale-95 transition duration-200" > - {loading ? ( - - ) : ( - 'Add Model' - )} + {loading ? 'Adding…' : 'Add Model'}
diff --git a/apps/frontend/src/components/Settings/Sections/Models/AddProviderDialog.tsx b/apps/frontend/src/components/Settings/Sections/Models/AddProviderDialog.tsx index 40818ae..3cc5f34 100644 --- a/apps/frontend/src/components/Settings/Sections/Models/AddProviderDialog.tsx +++ b/apps/frontend/src/components/Settings/Sections/Models/AddProviderDialog.tsx @@ -4,7 +4,7 @@ import { DialogPanel, DialogTitle, } from '@headlessui/react'; -import { Loader2, Plus } from 'lucide-react'; +import { Plus } from 'lucide-react'; import { useMemo, useState } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import { @@ -196,11 +196,7 @@ const AddProvider = ({ disabled={loading} className="px-4 py-2 rounded-lg text-[13px] bg-[#EA580C] text-white font-medium disabled:opacity-85 hover:opacity-85 active:scale-95 transition duration-200" > - {loading ? ( - - ) : ( - 'Add Connection' - )} + {loading ? 'Adding…' : 'Add Connection'}
diff --git a/apps/frontend/src/components/Settings/Sections/Models/DeleteProviderDialog.tsx b/apps/frontend/src/components/Settings/Sections/Models/DeleteProviderDialog.tsx index c9a4c72..7537067 100644 --- a/apps/frontend/src/components/Settings/Sections/Models/DeleteProviderDialog.tsx +++ b/apps/frontend/src/components/Settings/Sections/Models/DeleteProviderDialog.tsx @@ -1,5 +1,5 @@ import { Dialog, DialogPanel } from '@headlessui/react'; -import { Loader2, Trash2 } from 'lucide-react'; +import { Trash2 } from 'lucide-react'; import { useState } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import { ConfigModelProvider } from '@/lib/config/types'; @@ -100,11 +100,7 @@ const DeleteProvider = ({ onClick={handleDelete} className="px-4 py-2 rounded-lg text-sm bg-red-500 text-white font-medium disabled:opacity-85 hover:opacity-85 active:scale-95 transition duration-200" > - {loading ? ( - - ) : ( - 'Delete' - )} + {loading ? 'Deleting…' : 'Delete'}
diff --git a/apps/frontend/src/components/Settings/Sections/Models/UpdateProviderDialog.tsx b/apps/frontend/src/components/Settings/Sections/Models/UpdateProviderDialog.tsx index a685d81..b8988d2 100644 --- a/apps/frontend/src/components/Settings/Sections/Models/UpdateProviderDialog.tsx +++ b/apps/frontend/src/components/Settings/Sections/Models/UpdateProviderDialog.tsx @@ -1,5 +1,5 @@ import { Dialog, DialogPanel } from '@headlessui/react'; -import { Loader2, Pencil } from 'lucide-react'; +import { Pencil } from 'lucide-react'; import { useEffect, useState } from 'react'; import { AnimatePresence, motion } from 'framer-motion'; import { @@ -168,11 +168,7 @@ const UpdateProvider = ({ disabled={loading} className="px-4 py-2 rounded-lg text-[13px] bg-[#EA580C] text-white font-medium disabled:opacity-85 hover:opacity-85 active:scale-95 transition duration-200" > - {loading ? ( - - ) : ( - 'Update Connection' - )} + {loading ? 'Updating…' : 'Update Connection'}
diff --git a/apps/frontend/src/components/Settings/SettingsDialogue.tsx b/apps/frontend/src/components/Settings/SettingsDialogue.tsx index e1b6461..d183ed0 100644 --- a/apps/frontend/src/components/Settings/SettingsDialogue.tsx +++ b/apps/frontend/src/components/Settings/SettingsDialogue.tsx @@ -12,7 +12,6 @@ import Preferences from './Sections/Preferences'; import { motion } from 'framer-motion'; import { useEffect, useState } from 'react'; import { toast } from 'sonner'; -import Loader from '../ui/Loader'; import { cn } from '@/lib/utils'; import Models from './Sections/Models/Section'; import SearchSection from './Sections/Search'; @@ -121,8 +120,22 @@ const SettingsDialogue = ({ > {isLoading ? ( -
- +
+
+
+
+ {[1, 2, 3, 4].map((i) => ( +
+ ))} +
+
+
+
+
+
) : (
diff --git a/apps/frontend/src/components/Settings/SettingsField.tsx b/apps/frontend/src/components/Settings/SettingsField.tsx index 34c72f9..2f0a6bf 100644 --- a/apps/frontend/src/components/Settings/SettingsField.tsx +++ b/apps/frontend/src/components/Settings/SettingsField.tsx @@ -9,7 +9,6 @@ import { useState } from 'react'; import Select from '../ui/Select'; import { toast } from 'sonner'; import { useTheme } from 'next-themes'; -import { Loader2 } from 'lucide-react'; import { Switch } from '@headlessui/react'; const emitClientConfigChanged = () => { @@ -160,11 +159,6 @@ const SettingsInput = ({ type="text" disabled={loading} /> - {loading && ( - - - - )}
@@ -237,11 +231,6 @@ const SettingsTextarea = ({ rows={4} disabled={loading} /> - {loading && ( - - - - )}
diff --git a/apps/frontend/src/components/Sidebar.tsx b/apps/frontend/src/components/Sidebar.tsx index 3031f7a..aee368c 100644 --- a/apps/frontend/src/components/Sidebar.tsx +++ b/apps/frontend/src/components/Sidebar.tsx @@ -2,108 +2,244 @@ import { cn } from '@/lib/utils'; import { - BookOpenText, - Home, - Search, - SquarePen, - Settings, + MessagesSquare, Plus, - ArrowLeft, + Search, } from 'lucide-react'; import Link from 'next/link'; import { useSelectedLayoutSegments } from 'next/navigation'; -import React, { useState, type ReactNode } from 'react'; +import React, { useEffect, useRef, useState, type ReactNode } from 'react'; +import { createPortal } from 'react-dom'; import { useTranslation } from '@/lib/localization/context'; import Layout from './Layout'; -import { - Description, - Dialog, - DialogPanel, - DialogTitle, -} from '@headlessui/react'; import SettingsButton from './Settings/SettingsButton'; +interface ChatItem { + id: string; + title: string; + createdAt: string; +} + const VerticalIconContainer = ({ children }: { children: ReactNode }) => { return
{children}
; }; +interface HistorySubmenuProps { + onMouseEnter: () => void; + onMouseLeave: () => void; +} + +const HistorySubmenu = ({ onMouseEnter, onMouseLeave }: HistorySubmenuProps) => { + const { t } = useTranslation(); + const [chats, setChats] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchChats = async () => { + try { + const res = await fetch('/api/chats'); + const data = await res.json(); + setChats((data.chats ?? []).reverse()); + } catch { + setChats([]); + } finally { + setLoading(false); + } + }; + fetchChats(); + }, []); + + return ( +
+ {loading ? ( +
+ {t('common.loading')} +
+ ) : chats.length === 0 ? ( +
+ — +
+ ) : ( + + )} +
+ ); +}; + const Sidebar = ({ children }: { children: React.ReactNode }) => { const segments = useSelectedLayoutSegments(); - const [isOpen, setIsOpen] = useState(true); const { t } = useTranslation(); + const [historyOpen, setHistoryOpen] = useState(false); + const historyRef = useRef(null); + const hideTimeoutRef = useRef | null>(null); + const [submenuStyle, setSubmenuStyle] = useState({ top: 0, left: 0 }); - const navLinks = [ - { - icon: Home, - href: '/', - active: segments.length === 0 || segments.includes('c'), - label: t('nav.home'), - }, - { - icon: Search, - href: '/discover', - active: segments.includes('discover'), - label: t('nav.discover'), - }, - { - icon: BookOpenText, - href: '/library', - active: segments.includes('library'), - label: t('nav.library'), - }, - ]; + const discoverLink = { + icon: Search, + href: '/discover', + active: segments.includes('discover'), + label: t('nav.discover'), + }; + + const libraryLink = { + icon: MessagesSquare, + href: '/library', + active: segments.includes('library'), + label: t('nav.messageHistory'), + }; + + const navLinks = [discoverLink, libraryLink]; + + const handleHistoryMouseEnter = () => { + if (hideTimeoutRef.current) { + clearTimeout(hideTimeoutRef.current); + hideTimeoutRef.current = null; + } + if (historyRef.current) { + const rect = historyRef.current.getBoundingClientRect(); + setSubmenuStyle({ top: 0, left: rect.right + 4 }); + } + setHistoryOpen(true); + }; + + const handleHistoryMouseLeave = () => { + hideTimeoutRef.current = setTimeout(() => setHistoryOpen(false), 150); + }; + + const cancelHide = () => { + if (hideTimeoutRef.current) { + clearTimeout(hideTimeoutRef.current); + hideTimeoutRef.current = null; + } + }; + + useEffect(() => { + return () => { + if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current); + }; + }, []); return (
-
-
+
+
- {navLinks.map((link, i) => ( + +
+ +
+

+ {discoverLink.label} +

+ + +
-

- {link.label} + {libraryLink.label}

- ))} + {historyOpen && + typeof document !== 'undefined' && + createPortal( +
+ +
, + document.body, + )} +
- +
+ +
@@ -123,7 +259,7 @@ const Sidebar = ({ children }: { children: React.ReactNode }) => {
)} -

{link.label}

+

{link.label}

))}
diff --git a/apps/frontend/src/components/WeatherWidget.tsx b/apps/frontend/src/components/WeatherWidget.tsx index c5e7f17..3ddeba0 100644 --- a/apps/frontend/src/components/WeatherWidget.tsx +++ b/apps/frontend/src/components/WeatherWidget.tsx @@ -158,16 +158,16 @@ const WeatherWidget = () => { }, []); return ( -
+
{error ? (
Weather unavailable
) : loading ? ( <> -
-
-
+
+
+
@@ -183,30 +183,30 @@ const WeatherWidget = () => { ) : ( <> -
+
{data.condition} - + {data.temperature}°{data.temperatureUnit}
-
+
- + {data.location} - - + + {data.windSpeed} {data.windSpeedUnit}
- + {data.condition} -
+
Humidity {data.humidity}% Now diff --git a/apps/frontend/src/components/ui/Select.tsx b/apps/frontend/src/components/ui/Select.tsx index 2f42ab1..b408453 100644 --- a/apps/frontend/src/components/ui/Select.tsx +++ b/apps/frontend/src/components/ui/Select.tsx @@ -1,5 +1,5 @@ import { cn } from '@/lib/utils'; -import { Loader2, ChevronDown } from 'lucide-react'; +import { ChevronDown } from 'lucide-react'; import { SelectHTMLAttributes, forwardRef } from 'react'; interface SelectProps extends SelectHTMLAttributes { @@ -34,11 +34,7 @@ export const Select = forwardRef( })} - {loading ? ( - - ) : ( - - )} +
); diff --git a/apps/frontend/src/lib/localization/context.tsx b/apps/frontend/src/lib/localization/context.tsx index 9613d3e..5c1d784 100644 --- a/apps/frontend/src/lib/localization/context.tsx +++ b/apps/frontend/src/lib/localization/context.tsx @@ -47,6 +47,7 @@ const defaultTranslations: Translations = { 'nav.home': 'Home', 'nav.discover': 'Discover', 'nav.library': 'Library', + 'nav.messageHistory': 'History', 'chat.related': 'Follow-up questions', 'chat.searchImages': 'Search images', 'chat.searchVideos': 'Search videos', @@ -75,6 +76,15 @@ const defaultTranslations: Translations = { 'chat.source': 'source', 'chat.document': 'document', 'chat.documents': 'documents', + 'library.filterSourceAll': 'All sources', + 'library.filterSourceWeb': 'Web', + 'library.filterSourceAcademic': 'Academic', + 'library.filterSourceSocial': 'Social', + 'library.filterFilesAll': 'All', + 'library.filterFilesWith': 'With files', + 'library.filterFilesWithout': 'No files', + 'library.noResults': 'No chats match your filters.', + 'library.clearFilters': 'Clear filters', }; const LocalizationContext = createContext(null); diff --git a/apps/frontend/src/lib/localization/embeddedTranslations.ts b/apps/frontend/src/lib/localization/embeddedTranslations.ts index fcf263c..7d6ee58 100644 --- a/apps/frontend/src/lib/localization/embeddedTranslations.ts +++ b/apps/frontend/src/lib/localization/embeddedTranslations.ts @@ -26,6 +26,7 @@ export const embeddedTranslations: Record< 'nav.home': 'Home', 'nav.discover': 'Discover', 'nav.library': 'Library', + 'nav.messageHistory': 'History', 'chat.related': 'Follow-up questions', 'chat.searchImages': 'Search images', 'chat.searchVideos': 'Search videos', @@ -54,6 +55,15 @@ export const embeddedTranslations: Record< 'chat.source': 'source', 'chat.document': 'document', 'chat.documents': 'documents', + 'library.filterSourceAll': 'All sources', + 'library.filterSourceWeb': 'Web', + 'library.filterSourceAcademic': 'Academic', + 'library.filterSourceSocial': 'Social', + 'library.filterFilesAll': 'All', + 'library.filterFilesWith': 'With files', + 'library.filterFilesWithout': 'No files', + 'library.noResults': 'No chats match your filters.', + 'library.clearFilters': 'Clear filters', }, ru: { 'app.title': 'GooSeek', @@ -74,6 +84,7 @@ export const embeddedTranslations: Record< 'nav.home': 'Главная', 'nav.discover': 'Обзор', 'nav.library': 'Библиотека', + 'nav.messageHistory': 'История', 'chat.related': 'Что ещё спросить', 'chat.searchImages': 'Поиск изображений', 'chat.searchVideos': 'Поиск видео', @@ -102,6 +113,15 @@ export const embeddedTranslations: Record< 'chat.source': 'источнику', 'chat.documents': 'документов', 'chat.document': 'документу', + 'library.filterSourceAll': 'Все источники', + 'library.filterSourceWeb': 'Веб', + 'library.filterSourceAcademic': 'Академия', + 'library.filterSourceSocial': 'Соцсети', + 'library.filterFilesAll': 'Все', + 'library.filterFilesWith': 'С файлами', + 'library.filterFilesWithout': 'Без файлов', + 'library.noResults': 'Нет чатов по вашим фильтрам.', + 'library.clearFilters': 'Сбросить фильтры', }, de: { 'app.title': 'GooSeek', @@ -122,6 +142,7 @@ export const embeddedTranslations: Record< 'nav.home': 'Start', 'nav.discover': 'Entdecken', 'nav.library': 'Bibliothek', + 'nav.messageHistory': 'Verlauf', 'chat.related': 'Weitere Fragen', 'chat.searchImages': 'Bilder suchen', 'chat.searchVideos': 'Videos suchen', @@ -150,6 +171,15 @@ export const embeddedTranslations: Record< 'chat.source': 'Quelle', 'chat.document': 'Dokument', 'chat.documents': 'Dokumente', + 'library.filterSourceAll': 'Alle Quellen', + 'library.filterSourceWeb': 'Web', + 'library.filterSourceAcademic': 'Akademisch', + 'library.filterSourceSocial': 'Sozial', + 'library.filterFilesAll': 'Alle', + 'library.filterFilesWith': 'Mit Dateien', + 'library.filterFilesWithout': 'Ohne Dateien', + 'library.noResults': 'Keine Chats entsprechen Ihren Filtern.', + 'library.clearFilters': 'Filter zurücksetzen', }, fr: { 'app.title': 'GooSeek', @@ -170,6 +200,7 @@ export const embeddedTranslations: Record< 'nav.home': 'Accueil', 'nav.discover': 'Découvrir', 'nav.library': 'Bibliothèque', + 'nav.messageHistory': 'Historique', 'chat.related': 'Questions de suivi', 'chat.searchImages': 'Rechercher des images', 'chat.searchVideos': 'Rechercher des vidéos', @@ -198,6 +229,15 @@ export const embeddedTranslations: Record< 'chat.source': 'source', 'chat.document': 'document', 'chat.documents': 'documents', + 'library.filterSourceAll': 'Toutes les sources', + 'library.filterSourceWeb': 'Web', + 'library.filterSourceAcademic': 'Académique', + 'library.filterSourceSocial': 'Réseaux', + 'library.filterFilesAll': 'Tous', + 'library.filterFilesWith': 'Avec fichiers', + 'library.filterFilesWithout': 'Sans fichiers', + 'library.noResults': 'Aucun chat ne correspond à vos filtres.', + 'library.clearFilters': 'Effacer les filtres', }, es: { 'app.title': 'GooSeek', @@ -218,6 +258,7 @@ export const embeddedTranslations: Record< 'nav.home': 'Inicio', 'nav.discover': 'Descubrir', 'nav.library': 'Biblioteca', + 'nav.messageHistory': 'Historial', 'chat.related': 'Preguntas de seguimiento', 'chat.searchImages': 'Buscar imágenes', 'chat.searchVideos': 'Buscar videos', @@ -246,6 +287,15 @@ export const embeddedTranslations: Record< 'chat.source': 'fuente', 'chat.document': 'documento', 'chat.documents': 'documentos', + 'library.filterSourceAll': 'Todas las fuentes', + 'library.filterSourceWeb': 'Web', + 'library.filterSourceAcademic': 'Académico', + 'library.filterSourceSocial': 'Social', + 'library.filterFilesAll': 'Todos', + 'library.filterFilesWith': 'Con archivos', + 'library.filterFilesWithout': 'Sin archivos', + 'library.noResults': 'Ningún chat coincide con sus filtros.', + 'library.clearFilters': 'Borrar filtros', }, uk: { 'app.title': 'GooSeek', @@ -266,6 +316,7 @@ export const embeddedTranslations: Record< 'nav.home': 'Головна', 'nav.discover': 'Огляд', 'nav.library': 'Бібліотека', + 'nav.messageHistory': 'Історія', 'chat.related': 'Що ще запитати', 'chat.searchImages': 'Пошук зображень', 'chat.searchVideos': 'Пошук відео', @@ -294,6 +345,15 @@ export const embeddedTranslations: Record< 'chat.source': 'джерелу', 'chat.document': 'документу', 'chat.documents': 'документів', + 'library.filterSourceAll': 'Усі джерела', + 'library.filterSourceWeb': 'Веб', + 'library.filterSourceAcademic': 'Академія', + 'library.filterSourceSocial': 'Соцмережі', + 'library.filterFilesAll': 'Усі', + 'library.filterFilesWith': 'З файлами', + 'library.filterFilesWithout': 'Без файлів', + 'library.noResults': 'Немає чатів за вашими фільтрами.', + 'library.clearFilters': 'Скинути фільтри', }, }; diff --git a/apps/posts-mcs/.dockerignore b/apps/posts-mcs/.dockerignore deleted file mode 100644 index 4ce293a..0000000 --- a/apps/posts-mcs/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -data -.env -*.db -.git diff --git a/apps/posts-mcs/.gitignore b/apps/posts-mcs/.gitignore deleted file mode 100644 index 8e336d5..0000000 --- a/apps/posts-mcs/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules/ -data/ -dist/ -.env -*.db diff --git a/apps/posts-mcs/Dockerfile b/apps/posts-mcs/Dockerfile deleted file mode 100644 index a022110..0000000 --- a/apps/posts-mcs/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM node:22-alpine - -WORKDIR /app - -COPY package*.json ./ -RUN npm ci - -COPY . . -RUN mkdir -p data && chmod +x entrypoint.sh - -EXPOSE 4001 -ENV PORT=4001 - -ENTRYPOINT ["./entrypoint.sh"] diff --git a/apps/posts-mcs/README.md b/apps/posts-mcs/README.md deleted file mode 100644 index 509e77e..0000000 --- a/apps/posts-mcs/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Publications Service — всё для публикаций - -Сервис публикаций в папке `posts-microservice`: CRUD, планирование, rich-контент (изображения, видео, аудио, таблицы и т.д.), календарь выпусков и API для SearXNG. - -## Запуск - -```bash -cd posts-microservice -npm install -npm run dev -``` - -Сервис: `http://localhost:4001` - -## API - -### Публикации - -| Метод | URL | Описание | -|-------|-----|----------| -| POST | `/api/publications` | Создать | -| GET | `/api/publications` | Список (`?status=`, `?q=`, `?limit=`, `?offset=`) | -| GET | `/api/publications/calendar` | Календарь (`?year=`, `?month=`) | -| GET | `/api/publications/:id` | По ID | -| GET | `/api/publications/slug/:slug` | По slug | -| PATCH | `/api/publications/:id` | Обновить | -| DELETE | `/api/publications/:id` | Удалить | - -### Поля публикации - -- `title` — заголовок -- `slug` — URL-slug (генерируется из title) -- `excerpt` — краткое описание -- `contentBlocks` — массив блоков (текст, изображения, видео, аудио, таблицы, embed) -- `previewImage` — URL превью -- `url` — ссылка на страницу -- `author` — автор -- `status` — `draft` | `scheduled` | `published` -- `scheduledAt` — время публикации (ISO) -- `publishedAt` — время фактической публикации - -### Блоки контента (`contentBlocks`) - -```json -[ - { "type": "text", "data": { "html": "

Текст

" } }, - { "type": "image", "data": { "src": "https://...", "alt": "...", "caption": "..." } }, - { "type": "video", "data": { "src": "https://...", "poster": "...", "caption": "..." } }, - { "type": "audio", "data": { "src": "https://...", "caption": "..." } }, - { "type": "table", "data": { "html": "...
", "caption": "..." } }, - { "type": "embed", "data": { "url": "https://...", "caption": "..." } }, - { "type": "heading", "data": { "level": 1, "text": "Заголовок" } }, - { "type": "divider" } -] -``` - -### Планирование - -- Публикация со `status: "scheduled"` и `scheduledAt` автоматически переходит в `published` при наступлении времени. -- Планировщик запускается каждую минуту. - -### SearXNG - -Эндпоинт `/search?q={query}&page={pageno}` отдаёт только опубликованные публикации в формате JSON engine SearXNG. - -Конфиг в `searxng-engine-example.yml`. - -## Алиасы - -- `/api/posts` → тот же API (для обратной совместимости) diff --git a/apps/posts-mcs/docker-compose.yaml b/apps/posts-mcs/docker-compose.yaml new file mode 100644 index 0000000..f5fa826 --- /dev/null +++ b/apps/posts-mcs/docker-compose.yaml @@ -0,0 +1,42 @@ +# Ghost + MySQL +# Требует: порт 2369, MySQL 8 + +services: + ghost: + image: ghost:latest + restart: unless-stopped + depends_on: + mysql: + condition: service_healthy + ports: + - "2369:2368" + environment: + database__client: mysql2 + database__connection__host: mysql + database__connection__user: ghost + database__connection__password: ghost + database__connection__database: ghost + url: http://localhost:2369 + volumes: + - ghost_content:/var/lib/ghost/content + + mysql: + image: mysql:8.0 + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: ghost + MYSQL_USER: ghost + MYSQL_PASSWORD: ghost + volumes: + - ghost_mysql:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"] + interval: 3s + timeout: 5s + retries: 15 + start_period: 30s + +volumes: + ghost_content: + ghost_mysql: diff --git a/apps/posts-mcs/drizzle.config.ts b/apps/posts-mcs/drizzle.config.ts deleted file mode 100644 index b07ef4c..0000000 --- a/apps/posts-mcs/drizzle.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { defineConfig } from 'drizzle-kit'; -import path from 'path'; - -export default defineConfig({ - dialect: 'sqlite', - schema: './src/db/schema.ts', - out: './drizzle', - dbCredentials: { - url: path.join(process.cwd(), 'data', 'posts.db'), - }, -}); diff --git a/apps/posts-mcs/entrypoint.sh b/apps/posts-mcs/entrypoint.sh deleted file mode 100644 index 4eb778a..0000000 --- a/apps/posts-mcs/entrypoint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -set -e -mkdir -p /app/data -npx tsx src/init-db.ts 2>/dev/null || true -exec npx tsx src/index.ts diff --git a/apps/posts-mcs/package-lock.json b/apps/posts-mcs/package-lock.json deleted file mode 100644 index 0d86b96..0000000 --- a/apps/posts-mcs/package-lock.json +++ /dev/null @@ -1,3145 +0,0 @@ -{ - "name": "posts-microservice", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "posts-microservice", - "version": "1.0.0", - "dependencies": { - "better-sqlite3": "^11.9.1", - "drizzle-orm": "^0.40.1", - "express": "^4.21.0" - }, - "devDependencies": { - "@types/better-sqlite3": "^7.6.12", - "@types/express": "^4.17.21", - "drizzle-kit": "^0.30.5", - "tsx": "^4.19.0", - "typescript": "^5.9.3" - } - }, - "node_modules/@drizzle-team/brocli": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@drizzle-team/brocli/-/brocli-0.10.2.tgz", - "integrity": "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@esbuild-kit/core-utils": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@esbuild-kit/core-utils/-/core-utils-3.3.2.tgz", - "integrity": "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==", - "deprecated": "Merged into tsx: https://tsx.is", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.18.20", - "source-map-support": "^0.5.21" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" - } - }, - "node_modules/@esbuild-kit/esm-loader": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.6.5.tgz", - "integrity": "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==", - "deprecated": "Merged into tsx: https://tsx.is", - "dev": true, - "license": "MIT", - "dependencies": { - "@esbuild-kit/core-utils": "^3.3.2", - "get-tsconfig": "^4.7.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", - "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", - "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", - "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", - "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", - "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", - "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", - "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", - "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", - "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", - "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", - "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", - "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", - "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", - "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", - "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", - "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", - "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", - "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", - "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", - "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", - "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", - "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@petamoriken/float16": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.3.tgz", - "integrity": "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/better-sqlite3": { - "version": "7.6.13", - "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", - "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", - "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "^1" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.8", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", - "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", - "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/better-sqlite3": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz", - "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "bindings": "^1.5.0", - "prebuild-install": "^7.1.1" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/drizzle-kit": { - "version": "0.30.6", - "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.30.6.tgz", - "integrity": "sha512-U4wWit0fyZuGuP7iNmRleQyK2V8wCuv57vf5l3MnG4z4fzNTjY/U13M8owyQ5RavqvqxBifWORaR3wIUzlN64g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@drizzle-team/brocli": "^0.10.2", - "@esbuild-kit/esm-loader": "^2.5.5", - "esbuild": "^0.19.7", - "esbuild-register": "^3.5.0", - "gel": "^2.0.0" - }, - "bin": { - "drizzle-kit": "bin.cjs" - } - }, - "node_modules/drizzle-orm": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.40.1.tgz", - "integrity": "sha512-aPNhtiJiPfm3qxz1czrnIDkfvkSdKGXYeZkpG55NPTVI186LmK2fBLMi4dsHpPHlJrZeQ92D322YFPHADBALew==", - "license": "Apache-2.0", - "peerDependencies": { - "@aws-sdk/client-rds-data": ">=3", - "@cloudflare/workers-types": ">=4", - "@electric-sql/pglite": ">=0.2.0", - "@libsql/client": ">=0.10.0", - "@libsql/client-wasm": ">=0.10.0", - "@neondatabase/serverless": ">=0.10.0", - "@op-engineering/op-sqlite": ">=2", - "@opentelemetry/api": "^1.4.1", - "@planetscale/database": ">=1", - "@prisma/client": "*", - "@tidbcloud/serverless": "*", - "@types/better-sqlite3": "*", - "@types/pg": "*", - "@types/sql.js": "*", - "@vercel/postgres": ">=0.8.0", - "@xata.io/client": "*", - "better-sqlite3": ">=7", - "bun-types": "*", - "expo-sqlite": ">=14.0.0", - "gel": ">=2", - "knex": "*", - "kysely": "*", - "mysql2": ">=2", - "pg": ">=8", - "postgres": ">=3", - "sql.js": ">=1", - "sqlite3": ">=5" - }, - "peerDependenciesMeta": { - "@aws-sdk/client-rds-data": { - "optional": true - }, - "@cloudflare/workers-types": { - "optional": true - }, - "@electric-sql/pglite": { - "optional": true - }, - "@libsql/client": { - "optional": true - }, - "@libsql/client-wasm": { - "optional": true - }, - "@neondatabase/serverless": { - "optional": true - }, - "@op-engineering/op-sqlite": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@planetscale/database": { - "optional": true - }, - "@prisma/client": { - "optional": true - }, - "@tidbcloud/serverless": { - "optional": true - }, - "@types/better-sqlite3": { - "optional": true - }, - "@types/pg": { - "optional": true - }, - "@types/sql.js": { - "optional": true - }, - "@vercel/postgres": { - "optional": true - }, - "@xata.io/client": { - "optional": true - }, - "better-sqlite3": { - "optional": true - }, - "bun-types": { - "optional": true - }, - "expo-sqlite": { - "optional": true - }, - "gel": { - "optional": true - }, - "knex": { - "optional": true - }, - "kysely": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "pg": { - "optional": true - }, - "postgres": { - "optional": true - }, - "prisma": { - "optional": true - }, - "sql.js": { - "optional": true - }, - "sqlite3": { - "optional": true - } - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/env-paths": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", - "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" - } - }, - "node_modules/esbuild-register": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", - "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "esbuild": ">=0.12 <1" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" - }, - "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gel": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/gel/-/gel-2.2.0.tgz", - "integrity": "sha512-q0ma7z2swmoamHQusey8ayo8+ilVdzDt4WTxSPzq/yRqvucWRfymRVMvNgmSC0XK7eNjjEZEcplxpgaNojKdmQ==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "@petamoriken/float16": "^3.8.7", - "debug": "^4.3.4", - "env-paths": "^3.0.0", - "semver": "^7.6.2", - "shell-quote": "^1.8.1", - "which": "^4.0.0" - }, - "bin": { - "gel": "dist/cli.mjs" - }, - "engines": { - "node": ">= 18.0.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-tsconfig": { - "version": "4.13.6", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", - "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT" - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/isexe": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", - "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", - "devOptional": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-abi": { - "version": "3.87.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz", - "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" - }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "devOptional": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^16.13.0 || >=18.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - } - } -} diff --git a/apps/posts-mcs/package.json b/apps/posts-mcs/package.json deleted file mode 100644 index e39d4b4..0000000 --- a/apps/posts-mcs/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "posts-microservice", - "version": "1.0.0", - "type": "module", - "description": "Сервис постинга для SearXNG - API для отображения своих постов вместо Bing", - "main": "src/index.ts", - "scripts": { - "dev": "npx tsx watch src/index.ts", - "start": "npx tsx src/index.ts", - "db:generate": "drizzle-kit generate", - "db:migrate": "drizzle-kit migrate", - "db:push": "drizzle-kit push" - }, - "dependencies": { - "better-sqlite3": "^11.9.1", - "drizzle-orm": "^0.40.1", - "express": "^4.21.0" - }, - "devDependencies": { - "@types/better-sqlite3": "^7.6.12", - "@types/express": "^4.17.21", - "drizzle-kit": "^0.30.5", - "tsx": "^4.19.0", - "typescript": "^5.9.3" - } -} diff --git a/apps/posts-mcs/searxng-engine-example.yml b/apps/posts-mcs/searxng-engine-example.yml deleted file mode 100644 index bc93b7d..0000000 --- a/apps/posts-mcs/searxng-engine-example.yml +++ /dev/null @@ -1,18 +0,0 @@ -# Добавьте этот engine в /etc/searxng/settings.yml в секцию engines: -# -# Ваши публикации будут отображаться в результатах поиска Perplexica -# Замените http://localhost:4001 на ваш URL (например http://posts:4001 в Docker) - -- name: my_publications - engine: json_engine - paging: true - search_url: http://localhost:4001/search?q={query}&page={pageno} - results_query: results - url_query: url - title_query: title - content_query: content - disabled: false - -# Чтобы отключить Bing и использовать только свои посты: -# - name: bing -# disabled: true diff --git a/apps/posts-mcs/src/db/index.ts b/apps/posts-mcs/src/db/index.ts deleted file mode 100644 index a4f3edf..0000000 --- a/apps/posts-mcs/src/db/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Database from 'better-sqlite3'; -import { drizzle } from 'drizzle-orm/better-sqlite3'; -import * as schema from './schema'; -import path from 'path'; -import fs from 'fs'; - -const dataDir = path.join(process.cwd(), 'data'); -if (!fs.existsSync(dataDir)) { - fs.mkdirSync(dataDir, { recursive: true }); -} - -const sqlite = new Database(path.join(dataDir, 'posts.db')); -export const db = drizzle(sqlite, { schema }); diff --git a/apps/posts-mcs/src/db/schema.ts b/apps/posts-mcs/src/db/schema.ts deleted file mode 100644 index 32ccef7..0000000 --- a/apps/posts-mcs/src/db/schema.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { sql } from 'drizzle-orm'; -import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'; - -// Типы блоков контента (изображения, видео, аудио, таблицы и т.д.) -export type ContentBlock = - | { type: 'text'; data: { html: string } } - | { type: 'image'; data: { src: string; alt?: string; caption?: string } } - | { type: 'video'; data: { src: string; poster?: string; caption?: string } } - | { type: 'audio'; data: { src: string; caption?: string } } - | { type: 'table'; data: { html: string; caption?: string } } - | { type: 'embed'; data: { url: string; caption?: string } } - | { type: 'divider' } - | { type: 'heading'; data: { level: 1 | 2 | 3; text: string } }; - -export const publications = sqliteTable('publications', { - id: integer('id').primaryKey({ autoIncrement: true }), - title: text('title').notNull(), - slug: text('slug').notNull().unique(), - // Простой текст для поиска; полный контент в contentBlocks - excerpt: text('excerpt'), - // JSON массив ContentBlock[] - contentBlocks: text('contentBlocks', { mode: 'json' }) - .$type() - .default(sql`'[]'`), - // Превью изображение - previewImage: text('previewImage'), - url: text('url').notNull(), - author: text('author'), - status: text({ enum: ['draft', 'scheduled', 'published'] }).notNull().default('draft'), - publishedAt: text('publishedAt'), - scheduledAt: text('scheduledAt'), - createdAt: text('createdAt') - .notNull() - .$defaultFn(() => new Date().toISOString()), - updatedAt: text('updatedAt') - .notNull() - .$defaultFn(() => new Date().toISOString()), -}); - -export type Publication = typeof publications.$inferSelect; -export type NewPublication = typeof publications.$inferInsert; diff --git a/apps/posts-mcs/src/index.ts b/apps/posts-mcs/src/index.ts deleted file mode 100644 index 008f1f5..0000000 --- a/apps/posts-mcs/src/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import express from 'express'; -import publicationsRouter from './routes/publications.js'; -import searchRouter from './routes/search.js'; -import { runScheduledPublish } from './lib/scheduler.js'; - -const app = express(); -const PORT = process.env.PORT || 4001; - -app.use(express.json({ limit: '10mb' })); - -// API публикаций -app.use('/api/publications', publicationsRouter); - -// Алиас /api/posts -> publications (обратная совместимость) -app.use('/api/posts', (req, res, next) => { - const origJson = res.json.bind(res); - res.json = (body: unknown) => { - if (body && typeof body === 'object' && 'publications' in body) { - return origJson({ ...body, posts: (body as any).publications }); - } - return origJson(body); - }; - next(); -}, publicationsRouter); - -// SearXNG JSON Engine — поиск по опубликованным -app.use('/search', searchRouter); - -// Health -app.get('/health', (_, res) => res.json({ status: 'ok' })); - -// Планировщик: каждую минуту проверяет и публикует запланированные -setInterval(runScheduledPublish, 60_000); -runScheduledPublish(); - -app.listen(PORT, () => { - console.log(`Publications Service: http://localhost:${PORT}`); - console.log(` API: /api/publications`); - console.log(` Calendar: /api/publications/calendar`); - console.log(` SearXNG: /search?q=...`); -}); diff --git a/apps/posts-mcs/src/init-db.ts b/apps/posts-mcs/src/init-db.ts deleted file mode 100644 index 8095551..0000000 --- a/apps/posts-mcs/src/init-db.ts +++ /dev/null @@ -1,26 +0,0 @@ -import Database from 'better-sqlite3'; -import path from 'path'; -import fs from 'fs'; - -const dataDir = path.join(process.cwd(), 'data'); -if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true }); -const dbPath = path.join(dataDir, 'posts.db'); -const db = new Database(dbPath); -db.exec(` - CREATE TABLE IF NOT EXISTS publications ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - title TEXT NOT NULL, - slug TEXT NOT NULL UNIQUE, - excerpt TEXT, - contentBlocks TEXT DEFAULT '[]', - previewImage TEXT, - url TEXT NOT NULL, - author TEXT, - status TEXT NOT NULL DEFAULT 'draft', - publishedAt TEXT, - scheduledAt TEXT, - createdAt TEXT NOT NULL DEFAULT (datetime('now')), - updatedAt TEXT NOT NULL DEFAULT (datetime('now')) - ); -`); -db.close(); diff --git a/apps/posts-mcs/src/lib/content.ts b/apps/posts-mcs/src/lib/content.ts deleted file mode 100644 index adce433..0000000 --- a/apps/posts-mcs/src/lib/content.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { ContentBlock } from '../db/schema.js'; - -/** Извлекает поисковый текст из блоков контента */ -export function blocksToSearchText(blocks: ContentBlock[] | null): string { - if (!blocks || !Array.isArray(blocks)) return ''; - return blocks - .map((b) => { - if (b.type === 'text' && b.data?.html) return stripHtml(String(b.data.html)); - if (b.type === 'heading' && b.data?.text) return b.data.text; - if (b.type === 'image' && b.data?.caption) return b.data.caption; - if (b.type === 'video' && b.data?.caption) return b.data.caption; - if (b.type === 'audio' && b.data?.caption) return b.data.caption; - if (b.type === 'table' && b.data?.html) return stripHtml(String(b.data.html)); - return ''; - }) - .filter(Boolean) - .join(' '); -} - -function stripHtml(html: string): string { - return html.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim(); -} diff --git a/apps/posts-mcs/src/lib/scheduler.ts b/apps/posts-mcs/src/lib/scheduler.ts deleted file mode 100644 index 824b9f2..0000000 --- a/apps/posts-mcs/src/lib/scheduler.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { db } from '../db/index.js'; -import { publications } from '../db/schema.js'; -import { eq, sql } from 'drizzle-orm'; - -/** Переводит запланированные публикации в published, когда наступило время */ -export function runScheduledPublish() { - const now = new Date().toISOString(); - const rows = db - .select({ id: publications.id }) - .from(publications) - .where( - sql`${publications.status} = 'scheduled' AND ${publications.scheduledAt} IS NOT NULL AND ${publications.scheduledAt} <= ${now}`, - ) - .all(); - - for (const row of rows) { - db.update(publications) - .set({ status: 'published', publishedAt: now, updatedAt: now }) - .where(eq(publications.id, row.id)) - .run(); - } - if (rows.length > 0) { - console.log(`[scheduler] Опубликовано: ${rows.length}`); - } -} diff --git a/apps/posts-mcs/src/routes/publications.ts b/apps/posts-mcs/src/routes/publications.ts deleted file mode 100644 index dbeafd2..0000000 --- a/apps/posts-mcs/src/routes/publications.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { Router } from 'express'; -import { db } from '../db/index.js'; -import { publications } from '../db/schema.js'; -import { desc, eq, and } from 'drizzle-orm'; -import { blocksToSearchText } from '../lib/content.js'; -import type { ContentBlock } from '../db/schema.js'; - -const router = Router(); - -function slugify(s: string): string { - const slug = s - .toLowerCase() - .replace(/[^\p{L}\p{N}\s-]/gu, '') - .replace(/\s+/g, '-') - .replace(/-+/g, '-') - .trim(); - return slug || `post-${Date.now()}`; -} - -// Создать публикацию -router.post('/', (req, res) => { - try { - const { - title, - slug, - excerpt, - content, - contentBlocks, - previewImage, - url, - author, - status, - scheduledAt, - } = req.body; - - if (!title || !url) { - return res.status(400).json({ error: 'Необходимы поля: title, url' }); - } - - const finalSlug = slug || slugify(title); - const pubStatus = status || 'draft'; - const now = new Date().toISOString(); - const blocks: ContentBlock[] = - contentBlocks && Array.isArray(contentBlocks) - ? contentBlocks - : content - ? [{ type: 'text', data: { html: content } }] - : []; - - let publishedAt: string | null = null; - if (pubStatus === 'published') publishedAt = now; - if (pubStatus === 'scheduled' && scheduledAt) publishedAt = null; - - const result = db - .insert(publications) - .values({ - title, - slug: finalSlug, - excerpt: excerpt || (typeof content === 'string' ? content.slice(0, 300) : null), - contentBlocks: blocks, - previewImage: previewImage || null, - url, - author: author || null, - status: pubStatus, - publishedAt, - scheduledAt: scheduledAt || null, - }) - .run(); - - res.status(201).json({ id: result.lastInsertRowid, message: 'Публикация создана' }); - } catch (e) { - console.error(e); - res.status(500).json({ error: 'Ошибка создания публикации' }); - } -}); - -// Список публикаций (с фильтрами) -router.get('/', (req, res) => { - try { - const q = req.query.q as string | undefined; - const status = req.query.status as string | undefined; - const limit = Math.min(parseInt(req.query.limit as string) || 50, 100); - const offset = parseInt(req.query.offset as string) || 0; - - let baseQuery = db.select().from(publications).orderBy(desc(publications.createdAt)); - - const conditions = []; - if (status) { - conditions.push(eq(publications.status, status as 'draft' | 'scheduled' | 'published')); - } - - const whereClause = conditions.length ? and(...conditions) : undefined; - const items = (whereClause - ? baseQuery.where(whereClause) - : baseQuery - ) - .limit(limit) - .offset(offset) - .all(); - - let result = items; - if (q) { - const qLower = q.toLowerCase(); - result = items.filter( - (p) => - p.title?.toLowerCase().includes(qLower) || - (p.excerpt && p.excerpt.toLowerCase().includes(qLower)) || - p.url?.toLowerCase().includes(qLower) || - blocksToSearchText(p.contentBlocks).toLowerCase().includes(qLower), - ); - } - - res.json({ publications: result }); - } catch (e) { - console.error(e); - res.status(500).json({ error: 'Ошибка получения публикаций' }); - } -}); - -// Календарь: публикации по датам (для редакторского календаря) -router.get('/calendar', (req, res) => { - try { - const year = parseInt(req.query.year as string) || new Date().getFullYear(); - const month = parseInt(req.query.month as string); - - const items = db - .select({ - id: publications.id, - title: publications.title, - status: publications.status, - scheduledAt: publications.scheduledAt, - publishedAt: publications.publishedAt, - createdAt: publications.createdAt, - }) - .from(publications) - .all(); - - const byDate: Record = {}; - for (const p of items) { - const dateStr = - p.scheduledAt?.slice(0, 10) || p.publishedAt?.slice(0, 10) || p.createdAt?.slice(0, 10); - if (!dateStr) continue; - if (month !== undefined) { - const [, m] = dateStr.split('-').map(Number); - if (m !== month) continue; - } - const [y] = dateStr.split('-').map(Number); - if (y !== year) continue; - if (!byDate[dateStr]) byDate[dateStr] = []; - byDate[dateStr].push(p); - } - - res.json({ calendar: byDate }); - } catch (e) { - console.error(e); - res.status(500).json({ error: 'Ошибка календаря' }); - } -}); - -// Одна публикация по ID -router.get('/:id', (req, res) => { - const id = parseInt(req.params.id); - if (isNaN(id)) return res.status(400).json({ error: 'Неверный ID' }); - const row = db.select().from(publications).where(eq(publications.id, id)).get(); - if (!row) return res.status(404).json({ error: 'Публикация не найдена' }); - res.json(row); -}); - -// По slug -router.get('/slug/:slug', (req, res) => { - const row = db - .select() - .from(publications) - .where(eq(publications.slug, req.params.slug)) - .get(); - if (!row) return res.status(404).json({ error: 'Публикация не найдена' }); - res.json(row); -}); - -// Обновить -router.patch('/:id', (req, res) => { - const id = parseInt(req.params.id); - if (isNaN(id)) return res.status(400).json({ error: 'Неверный ID' }); - - const { - title, - slug, - excerpt, - contentBlocks, - previewImage, - url, - author, - status, - scheduledAt, - publishedAt, - } = req.body; - - const updates: Record = { - updatedAt: new Date().toISOString(), - }; - if (title !== undefined) updates.title = title; - if (slug !== undefined) updates.slug = slug; - if (excerpt !== undefined) updates.excerpt = excerpt; - if (contentBlocks !== undefined) updates.contentBlocks = contentBlocks; - if (previewImage !== undefined) updates.previewImage = previewImage; - if (url !== undefined) updates.url = url; - if (author !== undefined) updates.author = author; - if (status !== undefined) updates.status = status; - if (scheduledAt !== undefined) updates.scheduledAt = scheduledAt; - if (publishedAt !== undefined) updates.publishedAt = publishedAt; - - const result = db.update(publications).set(updates as any).where(eq(publications.id, id)).run(); - if (result.changes === 0) return res.status(404).json({ error: 'Публикация не найдена' }); - res.json({ message: 'Публикация обновлена' }); -}); - -// Удалить -router.delete('/:id', (req, res) => { - const id = parseInt(req.params.id); - if (isNaN(id)) return res.status(400).json({ error: 'Неверный ID' }); - const result = db.delete(publications).where(eq(publications.id, id)).run(); - if (result.changes === 0) return res.status(404).json({ error: 'Публикация не найдена' }); - res.json({ message: 'Публикация удалена' }); -}); - -export default router; diff --git a/apps/posts-mcs/src/routes/search.ts b/apps/posts-mcs/src/routes/search.ts deleted file mode 100644 index 2cb8c70..0000000 --- a/apps/posts-mcs/src/routes/search.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Router } from 'express'; -import { db } from '../db/index.js'; -import { publications } from '../db/schema.js'; -import { sql } from 'drizzle-orm'; -import { blocksToSearchText } from '../lib/content.js'; - -const router = Router(); - -/** Только опубликованные или запланированные (когда время наступило) */ -function getPublishedItems() { - const now = new Date().toISOString(); - const items = db - .select() - .from(publications) - .where( - sql`(${publications.status} = 'published' OR (${publications.status} = 'scheduled' AND ${publications.scheduledAt} <= ${now}))`, - ) - .all(); - return items.sort((a, b) => { - const da = a.publishedAt || a.scheduledAt || a.createdAt || ''; - const dbVal = b.publishedAt || b.scheduledAt || b.createdAt || ''; - return dbVal.localeCompare(da); - }); -} - -// SearXNG JSON Engine API -router.get('/', (req, res) => { - try { - const query = (req.query.q as string)?.trim() || ''; - const pageno = Math.max(1, parseInt((req.query.page || req.query.pageno) as string) || 1); - const pageSize = 10; - const offset = (pageno - 1) * pageSize; - - const allItems = getPublishedItems(); - let filtered = allItems; - if (query) { - const q = query.toLowerCase(); - filtered = allItems.filter( - (p) => - p.title?.toLowerCase().includes(q) || - (p.excerpt && p.excerpt.toLowerCase().includes(q)) || - p.url?.toLowerCase().includes(q) || - blocksToSearchText(p.contentBlocks).toLowerCase().includes(q), - ); - } - const items = filtered.slice(offset, offset + pageSize); - - const results = filtered.map((p) => ({ - url: p.url, - title: p.title, - content: (p.excerpt || blocksToSearchText(p.contentBlocks) || '').slice(0, 500), - ...(p.author && { author: p.author }), - ...(p.previewImage && { thumbnail: p.previewImage }), - })); - - res.json({ results }); - } catch (e) { - console.error(e); - res.status(500).json({ results: [] }); - } -}); - -export default router; diff --git a/apps/posts-mcs/tsconfig.json b/apps/posts-mcs/tsconfig.json deleted file mode 100644 index 7889f4b..0000000 --- a/apps/posts-mcs/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", - "esModuleInterop": true, - "strict": true, - "skipLibCheck": true, - "outDir": "dist", - "rootDir": "src" - }, - "include": ["src/**/*"] -} diff --git a/package.json b/package.json index 072cbe8..ffb9742 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "docker:build": "docker build -f docker/Dockerfile -t gooseek:latest .", "docker:up": "docker compose -f docker/docker-compose.yaml up -d", "docker:down": "docker compose -f docker/docker-compose.yaml down", + "chatwoot:up": "docker compose -f chatwoot/docker-compose.yaml up -d", + "chatwoot:down": "docker compose -f chatwoot/docker-compose.yaml down", "dev:geo": "npm run dev -w geo-device-service", "dev:locale": "npm run dev -w localization-service" },