diff --git a/.gitignore b/.gitignore index b1d225e..5e1493e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,12 @@ # See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. # Compiled output -/dist /tmp /out-tsc /bazel-out +/dist +changes.txt +api.txt # Node /node_modules diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 77b3745..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 - "recommendations": ["angular.ng-template"] -} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 925af83..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "ng serve", - "type": "chrome", - "request": "launch", - "preLaunchTask": "npm: start", - "url": "http://localhost:4200/" - }, - { - "name": "ng test", - "type": "chrome", - "request": "launch", - "preLaunchTask": "npm: test", - "url": "http://localhost:9876/debug.html" - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 244306f..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "start", - "isBackground": true, - "problemMatcher": { - "owner": "typescript", - "pattern": "$tsc", - "background": { - "activeOnStart": true, - "beginsPattern": { - "regexp": "Changes detected" - }, - "endsPattern": { - "regexp": "bundle generation (complete|failed)" - } - } - } - }, - { - "type": "npm", - "script": "test", - "isBackground": true, - "problemMatcher": { - "owner": "typescript", - "pattern": "$tsc", - "background": { - "activeOnStart": true, - "beginsPattern": { - "regexp": "Changes detected" - }, - "endsPattern": { - "regexp": "bundle generation (complete|failed)" - } - } - } - } - ] -} diff --git a/BACKEND.md b/BACKEND.md new file mode 100644 index 0000000..bfdba2f --- /dev/null +++ b/BACKEND.md @@ -0,0 +1,214 @@ +# Fastcheck Backend — требования к серверу + +Документ для команды бэкенда. Описывает, что должен реализовать сервер `api.fastcheck.store`, чтобы веб-фронт (этот репозиторий) полностью заработал. + +--- + +## 1. Общие требования + +### 1.1 Транспорт +- **Протокол**: HTTPS обязателен (валидный TLS-сертификат, Let's Encrypt или иной). +- **Хост**: `api.fastcheck.store` (или другой — тогда поправить `FASTCHECK_API` в `src/app/api.ts`). +- **Формат тел запроса/ответа**: `application/json; charset=utf-8`. + +### 1.2 CORS — **критично** +Браузер фронта пойдёт с другого origin. Без правильных CORS-заголовков **ничего не заработает** (preflight упадёт, fetch вернёт network error — ровно то, что мы видим сейчас). + +Сервер должен на любой `OPTIONS` (preflight) и на ответы реальных запросов отдавать: + +``` +Access-Control-Allow-Origin: https://<домен-фронта> # либо * для dev +Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS +Access-Control-Allow-Headers: Content-Type, Authorization +Access-Control-Max-Age: 86400 +``` + +Если используются cookies/credentials — добавить `Access-Control-Allow-Credentials: true` и **нельзя** использовать `*` в `Allow-Origin`. + +`OPTIONS` должен отвечать `204 No Content` без тела. + +### 1.3 Авторизация +Заголовок передаётся как **JSON-строка**, а не Bearer: + +``` +Authorization: {"sessionID":"1AF3781BF6B94604B771AEA1D44FA63A"} +``` + +Парсинг на сервере: `JSON.parse(req.headers.authorization)` → `{ sessionID }`. +Если заголовок отсутствует или сессия невалидна — `404 { "message": "not authorized" }`. + +### 1.4 Ошибки +Любая ошибка — JSON `{ "message": "<человекочитаемое описание>" }` + HTTP-статус (4xx/5xx). Фронт показывает `message` пользователю. + +--- + +## 2. Эндпоинты + +База: `https://api.fastcheck.store` + +### 2.1 `GET /ping` +Healthcheck. Ответ: `200 { "message": "pong" }`. Без авторизации. + +--- + +### 2.2 `GET /websession` +Создаёт новую веб-сессию для QR-логина через Telegram-бот. + +**Запрос**: без тела, без авторизации. + +**Ответ** `200`: +```json +{ + "sessionId": "1AF3781BF6B94604B771AEA1D44FA63A", + "userId": "", + "expires": "sessionId", + "userSessionId": "", + "Status": false +} +``` + +`sessionId` фронт подставляет в QR-код и в deeplink на бот: +`https://t.me/DexarSupport_bot?start=` + +**TTL сессии**: рекомендуем 5–10 минут. По истечении `GET /websession/:id` должен вернуть `Status: false` навсегда (фронт сам пересоздаст). + +--- + +### 2.3 `GET /websession/:webSessionID` +Поллинг статуса логина. Фронт зовёт каждые **3 секунды**, пока попап открыт. + +**Ответ** `200` пока пользователь не залогинился: +```json +{ "sessionId": "...", "userId": "", "expires": "sessionId", "userSessionId": "", "Status": false } +``` + +**Ответ** `200` после того, как Telegram-бот подтвердил вход: +```json +{ + "sessionId": "1AF3781BF6B94604B771AEA1D44FA63A", + "userId": "kHaAe9roaC2uq63AKGE/8+Ti/t/iFro68QhEZ1dRGLo", + "expires": "sessionId", + "userSessionId": "8A94EFEFD003426A9B456C48CAC99BE6", + "Status": true +} +``` + +Если сессия не найдена/истекла — `404 { "message": "session expired" }`. + +--- + +### 2.4 `DELETE /websession/:webSessionID` +Logout / закрытие попапа. + +**Запрос**: +```json +{ "sessionId": "1AF3781BF6B94604B771AEA1D44FA63A" } +``` + +**Ответ** `200 {}`. Идемпотентно — повторный вызов не должен ломаться. + +--- + +### 2.5 `GET /fastcheck` +Проверка существования и срока действия чека (используется опционально перед оплатой). + +**Запрос** (тело в GET): +```json +{ "fastcheck": "1234-5678-0001" } +``` + +**Ответ** `200`: +```json +{ + "fastcheck": "1234-5678-0001", + "expiration": "2026-07-07T09:08:18Z", + "Status": true +} +``` + +Не существует / просрочен → `404 { "message": "not found" }`. + +--- + +### 2.6 `POST /fastcheck` — **создание чека** +Юзер уже залогинен, его `sessionID` есть на фронте. С этого аккаунта списывается `amount`, выпускается чек. + +**Заголовок**: `Authorization: {"sessionID":"..."}` обязателен. + +**Тело**: +```json +{ "amount": 158000, "currency": "RUB" } +``` + +`amount` — в минимальных единицах валюты (копейки для RUB). Уточнить с фронтом, если иначе. + +**Ответ** `200`: +```json +{ + "fastcheck": "1234-5678-0001", + "expiration": "2026-07-07T09:08:18Z", + "code": "5864", + "Status": true +} +``` + +**Ошибки**: +- `404 { "message": "not authorized" }` — нет/невалидная сессия. +- `400 { "message": "insufficient balance" }` — мало средств. +- `400 { "message": "invalid amount" }` — некорректная сумма/валюта. + +--- + +### 2.7 `POST /fastcheck` — **приём чека (оплата)** +Этот же путь, отличается шейпом тела (без `amount`, с `code`). + +**Заголовок**: `Authorization: {"sessionID":"..."}` обязателен (сессия получателя — того, кто оплачивает). + +**Тело**: +```json +{ "fastcheck": "1234-5678-0001", "code": "5864" } +``` + +**Ответ** `200 { "message": "ok" }` — чек погашен, средства зачислены получателю. + +**Ошибки**: +- `404 { "message": "not authorized" }` — сессия невалидна **или** код неверный, **или** чек уже использован, **или** просрочен. (Так в текущей доке. Если можно различать — лучше отдельные сообщения.) + +> ⚠️ Серверу важно различать два POST-кейса по наличию поля `amount` vs `code` в теле. Альтернатива (предпочтительнее на проде) — развести на разные пути: `POST /fastcheck` (создание) и `POST /fastcheck/accept` (приём). Если разведёте — скажите, фронт правится за 5 минут. + +--- + +## 3. Интеграция с Telegram-ботом + +Фронт сам бот не дёргает — это задача бэкенда. + +1. Юзер сканит QR / кликает deeplink → попадает в бот `@DexarSupport_bot` с параметром `?start=`. +2. Бот идентифицирует Telegram-аккаунт (по `from.id`) → находит/создаёт `userId` → биндит его к `sessionId` → ставит `Status: true`, заполняет `userId` и `userSessionId`. +3. Следующий поллинг с фронта вернёт `Status: true` — фронт переходит к `POST /fastcheck`. + +Если юзер впервые в боте — стандартный onboarding, потом всё то же самое. + +--- + +## 4. Чеклист «готово к проду» + +- [ ] HTTPS с валидным сертификатом на `api.fastcheck.store`. +- [ ] CORS разрешает домен фронта на всех 6 эндпоинтах + OPTIONS. +- [ ] `GET /ping` отвечает. +- [ ] Полный цикл: `GET /websession` → бот ставит `Status:true` → `GET /websession/:id` это видит. +- [ ] `POST /fastcheck` (create) с заголовком `Authorization` создаёт чек, списывает баланс. +- [ ] `POST /fastcheck` (accept) погашает чек только один раз, зачисляет получателю. +- [ ] `DELETE /websession/:id` корректно завершает сессию. +- [ ] Все ошибки в формате `{ "message": "..." }` + правильный HTTP-код. +- [ ] Сессии экспайрятся (5–10 мин для websession, разумный TTL для userSession). +- [ ] Rate-limit на `GET /websession/:id` (фронт поллит каждые 3 с) и на `POST /fastcheck`. + +--- + +## 5. Открытые вопросы (нужны ответы от бэкенда) + +1. **Единица `amount`**: рубли или копейки? +2. **Currency**: какие коды поддерживаете кроме `RUB`? (фронт уже умеет показывать, но шлёт пока только RUB) +3. **Merchant callback** для эквайринга: после успешного `POST /fastcheck (accept)` нужно ли серверу самому пинговать мерчант-вебхук, или это полностью на фронте через `?return_url=`? +4. **Различение ошибок accept**: можно ли вместо общего `404 not authorized` отдавать `not found` / `wrong code` / `already used` / `expired`? +5. **WebSession TTL** — сколько живёт? diff --git a/BACKEND_CHANGES.md b/BACKEND_CHANGES.md new file mode 100644 index 0000000..965ef6d --- /dev/null +++ b/BACKEND_CHANGES.md @@ -0,0 +1,179 @@ +# Fastcheck Backend — изменения сверх api.txt + +Документ с **дельтой** — что нужно добавить/изменить в спеке `public/api.txt`, +чтобы фронт полноценно заработал. Базовая спека остаётся в силе, здесь только +правки. + +> Полный референс с примерами — см. `BACKEND.md` в этом же репозитории. + +--- + +## 1. `POST /fastcheck` (создание) — расширить тело + +Добавить поля `orderId`, `note`, `returnUrl` (все опциональные): + +```diff +POST /fastcheck +HEADER: Authorization: {"sessionID": "..."} +Body: +{ + "amount": 158000, + "currency": "RUB", ++ "orderId": "merchant-order-uuid", // id заказа на стороне мерчанта ++ "note": "Оплата заказа №123", // комментарий, видит получатель ++ "returnUrl": "https://shop.example.com/thanks" // куда вернуть юзера после оплаты +} + +Response: +{ + "fastcheck": "1234-5678-0001", + "expiration": "2026-07-07T09:08:18Z", + "code": "5864", + "Status": true, ++ "orderId": "merchant-order-uuid" // эхо обратно +} +``` + +`note` также возвращать в `GET /fastcheck`, чтобы получатель видел причину +платежа перед приёмом. + +--- + +## 1.1. `GET /fastcheck` — добавить `amount` в ответ + +Фронт автоматически делает `GET /fastcheck` после ввода полного номера +(`xxxx-xxxx-xxxx`), чтобы показать получателю сумму до ввода кода. Сейчас в +`api.txt` ответ содержит только `fastcheck`, `expiration`, `Status` — суммы нет. + +Добавить: + +```diff +GET /fastcheck +Body: { "fastcheck": "1234-5678-0001" } +Response: +{ + "fastcheck": "1234-5678-0001", + "expiration": "2026-07-07T09:08:18Z", ++ "amount": 158000, ++ "currency": "RUB", ++ "note": "За кофе", + "Status": true +} +``` + +Также: GET с телом — нестандарт, многие HTTP-клиенты его выкидывают. **Принимать +`?fastcheck=...` как query-параметр** (фронт шлёт оба варианта одновременно). + +--- + +## 2. Зафиксировать единицу `amount` + +В `api.txt` пример `"amount": 158000` неоднозначен. Зафиксировать: + +> `amount` — **целое число в основной единице валюты** (для RUB — рубли, +> не копейки). Минимум 1. + +Если бэкенд считает в копейках — сообщить, фронт изменит формат. + +--- + +## 3. Merchant webhook (новое) + +После успешного `POST /fastcheck` (accept), сервер шлёт `POST` на +`webhookUrl`, привязанный к `orderId`/мерчанту: + +``` +POST +Headers: + Content-Type: application/json + X-Fastcheck-Signature: + +Body: +{ + "event": "fastcheck.paid", + "fastcheck": "1234-5678-0001", + "orderId": "merchant-order-uuid", + "amount": 158000, + "currency": "RUB", + "paidAt": "2026-04-30T12:34:56Z" +} +``` + +Мерчант проверяет подпись и помечает заказ оплаченным. Ретраи (минимум +3 попытки с экспоненциальной задержкой) при не-2xx ответах. + +--- + +## 4. Развести create и accept на разные пути (рекомендация) + +Сейчас `POST /fastcheck` делает оба действия — отличается только формой тела +(`amount` vs `code`). Это хрупко. + +```diff +- POST /fastcheck (создание) +- POST /fastcheck (приём) ++ POST /fastcheck (создание) ++ POST /fastcheck/accept (приём) +``` + +Фронт правится в одну строку. Если оставляете один путь — оставляем как есть. + +--- + +## 5. Гранулярные ошибки `POST /fastcheck` (accept) + +В `api.txt` любая ошибка = `404 { "message": "not authorized" }`. Юзер не +понимает, что пошло не так. Различать: + +``` +401 { "message": "not authorized" } — нет/невалидная сессия +404 { "message": "fastcheck not found" } — нет такого номера +403 { "message": "wrong code" } — код неверный +410 { "message": "already used" } — чек уже погашен +410 { "message": "expired" } — просрочен +``` + +--- + +## 6. CORS + HTTPS + DNS (блокер) + +Сейчас `https://api.fastcheck.store` даёт `ERR_NAME_NOT_RESOLVED` — +домен не резолвится. Без этого тестировать нечего. + +Минимально: +- Поднять DNS A-запись на `api.fastcheck.store`. +- Валидный TLS-сертификат (Let's Encrypt подойдёт). +- На все эндпоинты + `OPTIONS` отвечать заголовками: + ``` + Access-Control-Allow-Origin: https://<домен-фронта> + Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS + Access-Control-Allow-Headers: Content-Type, Authorization + Access-Control-Max-Age: 86400 + ``` + `OPTIONS` → `204 No Content` без тела. + +Подробности — `BACKEND.md` §1.2. + +--- + +## Что **не меняется** + +- `GET /ping` +- `GET /websession`, `GET /websession/:id`, `DELETE /websession/:id` +- `GET /fastcheck` +- Формат заголовка `Authorization: {"sessionID":"..."}` +- Telegram-логин через бот `@DexarSupport_bot` с `?start=` + +--- + +## Чеклист для бэкенда + +- [ ] DNS + HTTPS + CORS (блокер) +- [ ] `orderId`, `note`, `returnUrl` в `POST /fastcheck` (create) +- [ ] `note` возвращается в `GET /fastcheck` +- [ ] `amount` (+ currency) возвращается в `GET /fastcheck` +- [ ] `GET /fastcheck` принимает `?fastcheck=` как query-param +- [ ] Зафиксировать `amount` в основной единице (рубли) +- [ ] Webhook на `fastcheck.paid` с HMAC-подписью +- [ ] Гранулярные ошибки accept +- [ ] (опц.) Развести create / accept на разные пути diff --git a/BACKEND_IMPLEMENTATION.md b/BACKEND_IMPLEMENTATION.md deleted file mode 100644 index 5a28721..0000000 --- a/BACKEND_IMPLEMENTATION.md +++ /dev/null @@ -1,426 +0,0 @@ -# FastCheck Backend Implementation Guide - -## QR Code Authentication Flow - -### Overview -The frontend displays a QR code that contains a session ID. When a user scans this QR code with the mobile app, the mobile app authenticates and links to that session. The frontend polls the backend every 2 seconds to check if the session has been authenticated. - -### Step-by-Step Implementation - ---- - -## 1. Create WebSession (QR Code Generation) - -### Frontend Request: -```typescript -GET https://api.fastcheck.store/websession -Headers: { - "Content-Type": "application/json" -} -``` - -### Backend Response: -```json -{ - "sessionId": "1AF3781BF6B94604B771AEA1D44FA63A", - "userId": "", - "expires": "2026-01-19T10:50:00Z", - "userSessionId": "", - "Status": false -} -``` - -### Backend Implementation: -```javascript -// Example Node.js/Express -app.get('/websession', (req, res) => { - // Generate unique session ID (UUID or similar) - const sessionId = generateUUID(); // e.g., "1AF3781BF6B94604B771AEA1D44FA63A" - - // Set expiration time (e.g., 5 minutes from now) - const expires = new Date(Date.now() + 5 * 60 * 1000).toISOString(); - - // Store session in database or cache (Redis recommended) - await sessionStore.create({ - sessionId: sessionId, - userId: null, - userSessionId: null, - status: false, - expiresAt: expires, - createdAt: new Date() - }); - - // Return session data - res.json({ - sessionId: sessionId, - userId: "", - expires: expires, - userSessionId: "", - Status: false - }); -}); -``` - -### What Frontend Does: -```typescript -// Frontend generates QR code data from session ID -const qrData = `fastcheck://login?session=${sessionId}`; -// Example: "fastcheck://login?session=1AF3781BF6B94604B771AEA1D44FA63A" -``` - -**QR Code Contains:** Deep link URL with session ID -- Format: `fastcheck://login?session={sessionId}` -- Mobile app will parse this URL and extract the sessionId -- Mobile app will then authenticate and update this session - ---- - -## 2. Check WebSession Status (Polling) - -### Frontend Request (Every 2 seconds): -```typescript -GET https://api.fastcheck.store/websession/1AF3781BF6B94604B771AEA1D44FA63A -Headers: { - "Content-Type": "application/json" -} -``` - -### Backend Response (Not Authenticated Yet): -```json -{ - "sessionId": "1AF3781BF6B94604B771AEA1D44FA63A", - "userId": "", - "expires": "2026-01-19T10:50:00Z", - "userSessionId": "", - "Status": false -} -``` - -### Backend Response (Authenticated): -```json -{ - "sessionId": "1AF3781BF6B94604B771AEA1D44FA63A", - "userId": "kHaAe9roaC2uq63AKGE/8+Ti/t/iFro68QhEZ1dRGLo", - "expires": "2026-01-19T12:00:00Z", - "userSessionId": "8A94EFEFD003426A9B456C48CAC99BE6", - "Status": true -} -``` - -### Backend Implementation: -```javascript -app.get('/websession/:sessionId', async (req, res) => { - const { sessionId } = req.params; - - // Retrieve session from database/cache - const session = await sessionStore.get(sessionId); - - if (!session) { - return res.status(404).json({ message: "Session not found" }); - } - - // Check if session expired - if (new Date() > new Date(session.expiresAt)) { - await sessionStore.delete(sessionId); - return res.status(404).json({ message: "Session expired" }); - } - - // Return session status - res.json({ - sessionId: session.sessionId, - userId: session.userId || "", - expires: session.expiresAt, - userSessionId: session.userSessionId || "", - Status: session.status || false - }); -}); -``` - ---- - -## 3. Mobile App Authenticates Session - -**This is what the MOBILE APP does** (not the web frontend): - -### Mobile App Flow: -1. User scans QR code: `fastcheck://login?session=1AF3781BF6B94604B771AEA1D44FA63A` -2. Mobile app extracts sessionId: `1AF3781BF6B94604B771AEA1D44FA63A` -3. Mobile app authenticates user (PIN, biometrics, etc.) -4. Mobile app sends authentication request to backend: - -```typescript -POST https://api.fastcheck.store/websession/authenticate -Headers: { - "Authorization": "Bearer {mobile_app_token}", - "Content-Type": "application/json" -} -Body: { - "sessionId": "1AF3781BF6B94604B771AEA1D44FA63A", - "userId": "kHaAe9roaC2uq63AKGE/8+Ti/t/iFro68QhEZ1dRGLo" -} -``` - -### Backend Implementation: -```javascript -app.post('/websession/authenticate', authenticateMobileApp, async (req, res) => { - const { sessionId, userId } = req.body; - const mobileUserId = req.user.id; // From mobile app authentication - - // Verify the mobile user matches - if (userId !== mobileUserId) { - return res.status(403).json({ message: "Unauthorized" }); - } - - // Update session with user information - const userSessionId = generateUUID(); - await sessionStore.update(sessionId, { - userId: userId, - userSessionId: userSessionId, - status: true, - authenticatedAt: new Date() - }); - - res.json({ message: "Session authenticated" }); -}); -``` - ---- - -## 4. Logout (Delete Session) - -### Frontend Request: -```typescript -DELETE https://api.fastcheck.store/websession/1AF3781BF6B94604B771AEA1D44FA63A -Headers: { - "Authorization": "{\"sessionID\": \"1AF3781BF6B94604B771AEA1D44FA63A\"}", - "Content-Type": "application/json" -} -``` - -### Backend Implementation: -```javascript -app.delete('/websession/:sessionId', async (req, res) => { - const { sessionId } = req.params; - - // Delete session from database/cache - await sessionStore.delete(sessionId); - - res.json({ message: "Session deleted" }); -}); -``` - ---- - -## 5. Authenticated API Requests - -After login, all API requests include the sessionId in the Authorization header: - -### Frontend Request: -```typescript -POST https://api.fastcheck.store/fastcheck -Headers: { - "Authorization": "{\"sessionID\": \"1AF3781BF6B94604B771AEA1D44FA63A\"}", - "Content-Type": "application/json" -} -Body: { - "amount": 150000, - "currency": "RUB" -} -``` - -### Backend Authentication Middleware: -```javascript -// Middleware to verify session -const authenticateSession = async (req, res, next) => { - try { - // Parse Authorization header - const authHeader = req.headers.authorization; - if (!authHeader) { - return res.status(401).json({ message: "not authorized" }); - } - - // Parse JSON from Authorization header - const { sessionID } = JSON.parse(authHeader); - - // Verify session exists and is authenticated - const session = await sessionStore.get(sessionID); - - if (!session || !session.status) { - return res.status(401).json({ message: "not authorized" }); - } - - // Check if session expired - if (new Date() > new Date(session.expiresAt)) { - await sessionStore.delete(sessionID); - return res.status(401).json({ message: "not authorized" }); - } - - // Attach user info to request - req.user = { - userId: session.userId, - userSessionId: session.userSessionId, - sessionId: sessionID - }; - - next(); - } catch (error) { - return res.status(401).json({ message: "not authorized" }); - } -}; - -// Use middleware on protected routes -app.post('/fastcheck', authenticateSession, async (req, res) => { - const { amount, currency } = req.body; - const userId = req.user.userId; - - // Create FastCheck logic... -}); -``` - ---- - -## QR Code Data Format - -### What the QR Code Contains: -``` -fastcheck://login?session=1AF3781BF6B94604B771AEA1D44FA63A -``` - -**Format breakdown:** -- **Scheme**: `fastcheck://` - Deep link scheme for mobile app -- **Path**: `login` - Indicates this is a login QR code -- **Parameter**: `session={sessionId}` - The web session ID - -### Frontend QR Code Implementation: -```typescript -// In login.component.ts -const sessionResponse = await createWebSession(); -const qrData = `fastcheck://login?session=${sessionResponse.sessionId}`; - -// QR code component displays this as a QR image - -``` - ---- - -## Database Schema Recommendations - -### WebSession Table: -```sql -CREATE TABLE web_sessions ( - session_id VARCHAR(64) PRIMARY KEY, - user_id VARCHAR(255), - user_session_id VARCHAR(64), - status BOOLEAN DEFAULT FALSE, - expires_at TIMESTAMP NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - authenticated_at TIMESTAMP, - INDEX idx_expires (expires_at), - INDEX idx_status (status) -); - --- Auto-delete expired sessions -CREATE EVENT cleanup_expired_sessions -ON SCHEDULE EVERY 1 HOUR -DO - DELETE FROM web_sessions WHERE expires_at < NOW(); -``` - -### Or use Redis (Recommended for sessions): -```javascript -// Redis structure -const sessionKey = `websession:${sessionId}`; -await redis.setex(sessionKey, 300, JSON.stringify({ - sessionId: sessionId, - userId: userId, - userSessionId: userSessionId, - status: true -})); -``` - ---- - -## Security Considerations - -1. **Session Expiration**: Sessions should expire after 5 minutes if not authenticated -2. **HTTPS Only**: All communication must be over HTTPS -3. **CORS Configuration**: Configure CORS to allow frontend domain -4. **Session Cleanup**: Regularly clean up expired sessions -5. **Rate Limiting**: Limit polling requests to prevent abuse -6. **Mobile App Authentication**: Mobile app must authenticate before linking session - ---- - -## Testing the Flow - -### 1. Test Session Creation: -```bash -curl -X GET https://api.fastcheck.store/websession -``` - -Expected: New session with Status: false - -### 2. Test Polling: -```bash -curl -X GET https://api.fastcheck.store/websession/{sessionId} -``` - -Expected: Same session, Status: false (until mobile app authenticates) - -### 3. Test Mobile Authentication (simulate): -```bash -curl -X POST https://api.fastcheck.store/websession/authenticate \ - -H "Authorization: Bearer {mobile_token}" \ - -H "Content-Type: application/json" \ - -d '{"sessionId": "{sessionId}", "userId": "{userId}"}' -``` - -Expected: Session updated with Status: true - -### 4. Test Polling After Auth: -```bash -curl -X GET https://api.fastcheck.store/websession/{sessionId} -``` - -Expected: Session with Status: true, userId populated - ---- - -## Frontend Polling Implementation (Already Done) - -```typescript -// In auth.service.ts -startPolling(sessionId: string): Observable { - return interval(2000).pipe( // Poll every 2 seconds - switchMap(() => this.checkWebSessionStatus(sessionId)), - tap(session => { - if (session.Status) { - this.setAuthenticated(session); - } - }), - takeWhile(session => !session.Status, true) // Stop when authenticated - ); -} -``` - ---- - -## Summary for Backend Team - -**Required Endpoints:** -1. ✅ `GET /websession` - Create session for QR -2. ✅ `GET /websession/:id` - Check session status (polled) -3. ⚠️ `POST /websession/authenticate` - Mobile app authenticates session (NEW) -4. ✅ `DELETE /websession/:id` - Logout - -**Required Logic:** -- Generate unique session IDs -- Store sessions with expiration -- Mobile app updates session status -- Web frontend polls until Status = true -- All authenticated APIs verify session in Authorization header - -**QR Code Data:** -- Format: `fastcheck://login?session={sessionId}` -- Mobile app parses and authenticates -- Web polls until mobile authenticates diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..f13696d --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,153 @@ +# Развёртывание (Deploy) + +## 1. Требования + +- **Node.js 20+** и **npm 10+** +- Доступ к серверу с веб-сервером (nginx / Apache / Caddy / IIS) или к статическому хостингу (Netlify, Vercel, GitHub Pages, S3 + CloudFront и т.п.) +- HTTPS (обязательно — backend принимает только HTTPS, а Telegram QR не будет работать на http) + +## 2. Сборка production-бандла + +```powershell +# в корне проекта +npm ci # чистая установка зависимостей +npm run build # production-сборка +``` + +Результат окажется в папке `dist/qr-vitanova/browser/` — это и есть набор статических файлов, который надо опубликовать. + +## 3. Конфигурация API + +Эндпоинты заданы в `src/app/api.ts`: + +- `FASTCHECK_API` — `https://api.fastcheck.store` +- `QR_API` — `https://qr.vitanova.network:567/qr` (legacy, на текущих страницах не используется) + +Имя Telegram-бота — в `src/app/pages/fastcheck-page/fastcheck-page.ts` (поле `telegramBot`, сейчас `DexarSupport_bot`). + +## 4. Публикация статики + +Скопируй содержимое `dist/qr-vitanova/browser/` в корень сайта. + +### Важно: SPA-routing + +У приложения два маршрута (`/` и `/new`), поэтому веб-сервер должен возвращать `index.html` для всех неизвестных путей, иначе обновление страницы на `/new` даст 404. + +#### nginx + +```nginx +server { + listen 443 ssl http2; + server_name pay.example.com; + + root /var/www/qr-vitanova; + index index.html; + + # SPA fallback + location / { + try_files $uri $uri/ /index.html; + } + + # Кэш для статики + location ~* \.(?:js|css|svg|woff2?|ico|png|jpg)$ { + expires 30d; + add_header Cache-Control "public, immutable"; + } + + # index.html — без кеша, чтобы быстро прилетал новый билд + location = /index.html { + add_header Cache-Control "no-cache"; + } + + ssl_certificate /etc/letsencrypt/live/pay.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/pay.example.com/privkey.pem; +} + +server { + listen 80; + server_name pay.example.com; + return 301 https://$host$request_uri; +} +``` + +#### Apache (`.htaccess`) + +```apache +RewriteEngine On +RewriteBase / +RewriteRule ^index\.html$ - [L] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule . /index.html [L] +``` + +#### IIS (`web.config`) + +```xml + + + + + + + + + + + + + + + + +``` + +## 5. CORS на backend + +`api.fastcheck.store` должен возвращать заголовки CORS, разрешающие домен фронта: + +``` +Access-Control-Allow-Origin: https://pay.example.com +Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS +Access-Control-Allow-Headers: Content-Type, Authorization +``` + +## 6. Параметры запуска страницы + +- `?session=` — необязательный, передаётся на `/new`, чтобы вставить `Authorization: {"sessionID": ...}` при `POST /fastcheck`. +- `?return_url=` — необязательный, на `/`. После успешного приёма фасчека (`POST /fastcheck` с `code`) страница редиректит на этот URL с параметрами `?fastcheck=...&status=ok` — это и есть merchant-callback. + +Пример: `https://pay.example.com/?return_url=https://shop.example.com/order/42` + +## 7. Деплой одной командой (пример через rsync) + +```powershell +npm run build +rsync -az --delete dist/qr-vitanova/browser/ user@server:/var/www/qr-vitanova/ +ssh user@server "sudo systemctl reload nginx" +``` + +## 8. Docker (опционально) + +`Dockerfile`: + +```dockerfile +FROM node:20-alpine AS build +WORKDIR /app +COPY package*.json ./ +RUN npm ci +COPY . . +RUN npm run build + +FROM nginx:1.27-alpine +COPY --from=build /app/dist/qr-vitanova/browser/ /usr/share/nginx/html/ +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 +``` + +## 9. Проверка после деплоя + +1. Открой `https://pay.example.com/` — должна быть форма фастчека. +2. Открой `https://pay.example.com/new` напрямую — должна открыться страница создания (не 404). +3. В DevTools → Network проверь, что запросы к `https://api.fastcheck.store/...` идут без CORS-ошибок. +4. Нажми «Оплатить» с заполненными полями — должен открыться popup с QR Telegram (`@DexarSupport_bot`). diff --git a/IMPLEMENTATION.md b/IMPLEMENTATION.md deleted file mode 100644 index d5a5797..0000000 --- a/IMPLEMENTATION.md +++ /dev/null @@ -1,200 +0,0 @@ -# FastCheck Application - Implementation Summary - -## ✅ Completed Features - -### 1. Project Structure -- ✅ Angular 21 standalone components architecture -- ✅ TypeScript models for type safety -- ✅ SCSS styling with modern design -- ✅ Modular service-based architecture - -### 2. Authentication System -- ✅ QR Code login component -- ✅ WebSession management -- ✅ Auto-polling every 2 seconds to check login status -- ✅ Session persistence in sessionStorage -- ✅ Route guards for protected pages - -### 3. Dashboard -- ✅ Balance display (mocked) -- ✅ Create FastCheck with custom amount -- ✅ Accept FastCheck with number (xxxx-xxxx-xxxx) and code (xxxx) -- ✅ FastCheck number auto-formatting -- ✅ Success/error handling -- ✅ Modal to display created check details - -### 4. Active Checks Page -- ✅ List all unused FastChecks -- ✅ Copy to clipboard functionality -- ✅ Display check details (number, code, amount, expiration) -- ✅ Security warnings - -### 5. Transaction History -- ✅ View all used/expired checks -- ✅ Distinguish between created and accepted checks -- ✅ Timestamps and status display - -## 📁 File Structure - -``` -FastCheck/ -├── public/ -│ ├── api.txt # Original API documentation -│ └── missing-apis.txt # Missing API specifications for backend -├── src/ -│ ├── app/ -│ │ ├── components/ -│ │ │ ├── login/ # QR login with polling -│ │ │ ├── dashboard/ # Main dashboard -│ │ │ ├── active-checks/ # Active checks list -│ │ │ └── history/ # Transaction history -│ │ ├── services/ -│ │ │ ├── api.service.ts # HTTP client wrapper -│ │ │ ├── auth.service.ts # Authentication & session management -│ │ │ └── fastcheck.service.ts # FastCheck operations -│ │ ├── models/ -│ │ │ ├── session.model.ts # Session interfaces -│ │ │ ├── fastcheck.model.ts # FastCheck interfaces -│ │ │ └── api.model.ts # API response interfaces -│ │ ├── guards/ -│ │ │ └── auth.guard.ts # Route protection -│ │ ├── app.routes.ts # Route configuration -│ │ ├── app.config.ts # App configuration -│ │ ├── app.ts # Root component -│ │ ├── app.html # Root template -│ │ └── app.scss # Global styles -│ ├── environments/ -│ │ └── environment.ts # Environment configuration -│ ├── index.html # Main HTML -│ ├── main.ts # Bootstrap -│ └── styles.scss # Global styles -├── package.json -└── README.md # Project documentation -``` - -## 🔧 Technologies Used - -- **Angular 21** - Modern standalone components -- **TypeScript** - Type-safe development -- **RxJS** - Reactive programming (polling, API calls) -- **SCSS** - Styling -- **angularx-qrcode** - QR code generation -- **HttpClient** - API communication - -## 🎨 Design Features - -- Modern gradient UI (purple/violet theme) -- Responsive layout -- Smooth animations and transitions -- Loading states and spinners -- Error handling with user-friendly messages -- Copy-to-clipboard functionality -- Modal dialogs for important information - -## 🔌 API Integration - -### Fully Integrated: -1. `GET /ping` - Server health check -2. `GET /websession` - Create login session -3. `GET /websession/:id` - Poll login status -4. `DELETE /websession/:id` - Logout -5. `POST /fastcheck` - Create new check (with Authorization) -6. `POST /fastcheck` - Accept check (with Authorization) -7. `GET /fastcheck` - Check status - -### Mocked (Need Backend Implementation): -1. `GET /balance` - Get user balance -2. `GET /fastcheck/active` - List active checks -3. `GET /fastcheck/history` - Transaction history - -See `public/missing-apis.txt` for complete API specifications. - -## 🚀 Running the Application - -```bash -# Navigate to project directory -cd F:\dx\remote\FastCheck\FastCheck - -# Install dependencies (already done) -npm install - -# Start development server -npm start - -# Open browser at http://localhost:4200 -``` - -## 📝 Next Steps for Backend Team - -1. **Implement Missing APIs:** - - Balance endpoint - - Active checks endpoint - - History endpoint - -2. **Bank Integration:** - - Payment gateway API - - Redirect URLs for payment flow - - Webhook for payment confirmation - - Balance top-up mechanism - -3. **Update Frontend When Ready:** - - Uncomment real API calls in `fastcheck.service.ts` - - Remove mock `of()` observables - - Test with real data - -## 🔐 Security Considerations - -- SessionID stored in sessionStorage (clears on tab close) -- Authorization header on all authenticated requests -- CORS must be configured on backend -- HTTPS required in production -- FastCheck codes are sensitive - handle securely - -## 📱 User Flow - -1. **Login:** - - User opens app → sees QR code - - Scans with mobile app - - Frontend polls every 2s - - Redirects to dashboard on success - -2. **Create FastCheck:** - - Enter amount - - Click create - - Get number + code in modal - - Save credentials securely - -3. **Accept FastCheck:** - - Enter number (auto-formatted) - - Enter code - - Submit - - Money added to balance - -4. **View Checks:** - - Active checks → unused checks with copy feature - - History → all used/expired transactions - -## 🐛 Known Limitations (Temporary) - -- Balance API is mocked (returns 150,000 RUB) -- Active checks are mocked (returns 2 sample checks) -- History is mocked (returns 2 sample transactions) -- Bank integration not implemented yet -- No actual QR scanning (need mobile app integration) - -## 📞 Contact - -Developer: sdarbinyan@4pay.ru -Project: FastCheck СБП Payment System -Company: 4Pay - -## ✨ Status - -**Development Server:** ✅ Running on http://localhost:4200 -**All Components:** ✅ Implemented -**Routing:** ✅ Configured with guards -**Styling:** ✅ Complete with modern UI -**Mock Data:** ✅ In place for testing -**Documentation:** ✅ Complete - -Ready for backend integration and testing! diff --git a/README.md b/README.md index 788f771..a129a1e 100644 --- a/README.md +++ b/README.md @@ -1,175 +1,59 @@ -# FastCheck - СБП Payment System +# QrVitanova -FastCheck is an online payment system that allows users to create and manage payment checks with СБП (Faster Payment System). +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.0.4. -## Features +## Development server -- ✅ QR Code Authentication -- ✅ Balance Management -- ✅ Create FastCheck with custom amount -- ✅ Accept FastCheck with number and PIN -- ✅ View Active Checks -- ✅ Transaction History -- ⏳ Bank Integration (To be implemented) - -## Tech Stack - -- **Framework**: Angular 21 -- **Language**: TypeScript -- **Styling**: SCSS -- **HTTP Client**: Angular HttpClient -- **QR Code**: angularx-qrcode -- **API**: RESTful API (api.fastcheck.store) - -## Getting Started - -### Prerequisites - -- Node.js (v18 or higher) -- npm (v10 or higher) - -### Installation +To start a local development server, run: ```bash -# Install dependencies -npm install - -# Start development server -npm start - -# The app will run on http://localhost:4200 +ng serve ``` -### Build +Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files. + +## Code scaffolding + +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: ```bash -# Production build -npm run build - -# Output will be in dist/ folder +ng generate component component-name ``` -## Project Structure +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: -``` -src/ -├── app/ -│ ├── components/ -│ │ ├── login/ # QR login with polling -│ │ ├── dashboard/ # Main dashboard -│ │ ├── active-checks/ # Active FastChecks list -│ │ └── history/ # Transaction history -│ ├── services/ -│ │ ├── api.service.ts # HTTP client wrapper -│ │ ├── auth.service.ts # Authentication logic -│ │ └── fastcheck.service.ts # FastCheck operations -│ ├── models/ # TypeScript interfaces -│ ├── guards/ # Route guards -│ └── app.routes.ts # Route configuration +```bash +ng generate --help ``` -## API Documentation +## Building -### Implemented APIs +To build the project run: -- ✅ `GET /ping` - Check server availability -- ✅ `GET /websession` - Create QR session -- ✅ `GET /websession/:id` - Check login status (polling) -- ✅ `DELETE /websession/:id` - Logout -- ✅ `POST /fastcheck` - Create new FastCheck -- ✅ `POST /fastcheck` - Accept FastCheck -- ✅ `GET /fastcheck` - Check FastCheck status - -### Missing APIs (Mocked in Frontend) - -See `public/missing-apis.txt` for complete specifications: - -- ❌ `GET /balance` - Get user balance -- ❌ `GET /fastcheck/active` - Get active checks -- ❌ `GET /fastcheck/history` - Get transaction history - -**Note**: These APIs are currently mocked in the frontend. The backend team needs to implement them. - -## Features Overview - -### 1. Authentication -- Scan QR code with mobile app -- Auto-polling every 2 seconds -- Session management with sessionStorage - -### 2. Dashboard -- View current balance -- Create new FastCheck -- Accept existing FastCheck -- FastCheck format: `xxxx-xxxx-xxxx` -- Code format: `xxxx` - -### 3. Active Checks -- View all unused FastChecks -- Copy number and code to clipboard -- See expiration dates - -### 4. Transaction History -- View used/expired checks -- Filter by created/accepted -- See timestamps - -### 5. Balance Top-Up (To be implemented) -- Bank integration needed -- Will redirect to bank payment page -- Auto-refresh balance after payment - -## Development Notes - -### Mock Data - -The following services return mock data: -- `getBalance()` - Returns 150,000 RUB -- `getActiveFastChecks()` - Returns 2 sample active checks -- `getFastCheckHistory()` - Returns 2 sample history records - -Replace the mocked `of()` observables with real API calls once backend is ready. - -### Environment Configuration - -Update `src/environments/environment.ts` for different API URLs: - -```typescript -export const environment = { - production: false, - apiUrl: 'https://api.fastcheck.store' -}; +```bash +ng build ``` -## Backend Requirements +This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed. -Backend team needs to implement: +## Running unit tests -1. **Balance API** - `GET /balance` -2. **Active Checks API** - `GET /fastcheck/active` -3. **History API** - `GET /fastcheck/history` -4. **Bank Integration** - Payment gateway integration +To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command: -See `public/missing-apis.txt` for detailed API specifications. +```bash +ng test +``` -## Security Notes +## Running end-to-end tests -- SessionId stored in sessionStorage (clears on tab close) -- All authenticated requests include Authorization header -- FastCheck codes are sensitive - handle securely -- Implement HTTPS in production +For end-to-end (e2e) testing, run: -## Browser Support +```bash +ng e2e +``` -- Chrome (latest) -- Firefox (latest) -- Safari (latest) -- Edge (latest) +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. -## License +## Additional Resources -Private - 4Pay - -## Contact - -For questions or issues, contact: sdarbinyan@4pay.ru +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/angular.json b/angular.json index 3c9ecd0..0171cc3 100644 --- a/angular.json +++ b/angular.json @@ -6,7 +6,7 @@ }, "newProjectRoot": "projects", "projects": { - "FastCheck": { + "qr_vitanova": { "projectType": "application", "schematics": { "@schematics/angular:component": { @@ -20,6 +20,10 @@ "build": { "builder": "@angular/build:application", "options": { + "outputPath": { + "base": "dist", + "browser": "" + }, "browser": "src/main.ts", "tsConfig": "tsconfig.app.json", "inlineStyleLanguage": "scss", @@ -43,8 +47,8 @@ }, { "type": "anyComponentStyle", - "maximumWarning": "4kB", - "maximumError": "8kB" + "maximumWarning": "10kB", + "maximumError": "16kB" } ], "outputHashing": "all" @@ -61,10 +65,11 @@ "builder": "@angular/build:dev-server", "configurations": { "production": { - "buildTarget": "FastCheck:build:production" + "buildTarget": "qr_vitanova:build:production" }, "development": { - "buildTarget": "FastCheck:build:development" + "buildTarget": "qr_vitanova:build:development", + "proxyConfig": "proxy.conf.json" } }, "defaultConfiguration": "development" diff --git a/package-lock.json b/package-lock.json index 829a05c..8ec2ed5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "fast-check", + "name": "qr-vitanova", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "fast-check", + "name": "qr-vitanova", "version": "0.0.0", "dependencies": { "@angular/common": "^21.0.0", @@ -14,7 +14,6 @@ "@angular/forms": "^21.0.0", "@angular/platform-browser": "^21.0.0", "@angular/router": "^21.0.0", - "angularx-qrcode": "^21.0.4", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, @@ -35,57 +34,57 @@ "license": "MIT" }, "node_modules/@algolia/abtesting": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.12.2.tgz", - "integrity": "sha512-oWknd6wpfNrmRcH0vzed3UPX0i17o4kYLM5OMITyMVM2xLgaRbIafoxL0e8mcrNNb0iORCJA0evnNDKRYth5WQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.14.1.tgz", + "integrity": "sha512-Dkj0BgPiLAaim9sbQ97UKDFHJE/880wgStAM18U++NaJ/2Cws34J5731ovJifr6E3Pv4T2CqvMXf8qLCC417Ew==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-abtesting": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.46.2.tgz", - "integrity": "sha512-oRSUHbylGIuxrlzdPA8FPJuwrLLRavOhAmFGgdAvMcX47XsyM+IOGa9tc7/K5SPvBqn4nhppOCEz7BrzOPWc4A==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.48.1.tgz", + "integrity": "sha512-LV5qCJdj+/m9I+Aj91o+glYszrzd7CX6NgKaYdTOj4+tUYfbS62pwYgUfZprYNayhkQpVFcrW8x8ZlIHpS23Vw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.46.2.tgz", - "integrity": "sha512-EPBN2Oruw0maWOF4OgGPfioTvd+gmiNwx0HmD9IgmlS+l75DatcBkKOPNJN+0z3wBQWUO5oq602ATxIfmTQ8bA==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.48.1.tgz", + "integrity": "sha512-/AVoMqHhPm14CcHq7mwB+bUJbfCv+jrxlNvRjXAuO+TQa+V37N8k1b0ijaRBPdmSjULMd8KtJbQyUyabXOu6Kg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.46.2.tgz", - "integrity": "sha512-Hj8gswSJNKZ0oyd0wWissqyasm+wTz1oIsv5ZmLarzOZAp3vFEda8bpDQ8PUhO+DfkbiLyVnAxsPe4cGzWtqkg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.48.1.tgz", + "integrity": "sha512-VXO+qu2Ep6ota28ktvBm3sG53wUHS2n7bgLWmce5jTskdlCD0/JrV4tnBm1l7qpla1CeoQb8D7ShFhad+UoSOw==", "dev": true, "license": "MIT", "engines": { @@ -93,151 +92,151 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.46.2.tgz", - "integrity": "sha512-6dBZko2jt8FmQcHCbmNLB0kCV079Mx/DJcySTL3wirgDBUH7xhY1pOuUTLMiGkqM5D8moVZTvTdRKZUJRkrwBA==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.48.1.tgz", + "integrity": "sha512-zl+Qyb0nLg+Y5YvKp1Ij+u9OaPaKg2/EPzTwKNiVyOHnQJlFxmXyUZL1EInczAZsEY8hVpPCLtNfhMhfxluXKQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.46.2.tgz", - "integrity": "sha512-1waE2Uqh/PHNeDXGn/PM/WrmYOBiUGSVxAWqiJIj73jqPqvfzZgzdakHscIVaDl6Cp+j5dwjsZ5LCgaUr6DtmA==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.48.1.tgz", + "integrity": "sha512-r89Qf9Oo9mKWQXumRu/1LtvVJAmEDpn8mHZMc485pRfQUMAwSSrsnaw1tQ3sszqzEgAr1c7rw6fjBI+zrAXTOw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.46.2.tgz", - "integrity": "sha512-EgOzTZkyDcNL6DV0V/24+oBJ+hKo0wNgyrOX/mePBM9bc9huHxIY2352sXmoZ648JXXY2x//V1kropF/Spx83w==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.48.1.tgz", + "integrity": "sha512-TPKNPKfghKG/bMSc7mQYD9HxHRUkBZA4q1PEmHgICaSeHQscGqL4wBrKkhfPlDV1uYBKW02pbFMUhsOt7p4ZpA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.46.2.tgz", - "integrity": "sha512-ZsOJqu4HOG5BlvIFnMU0YKjQ9ZI6r3C31dg2jk5kMWPSdhJpYL9xa5hEe7aieE+707dXeMI4ej3diy6mXdZpgA==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.48.1.tgz", + "integrity": "sha512-4Fu7dnzQyQmMFknYwTiN/HxPbH4DyxvQ1m+IxpPp5oslOgz8m6PG5qhiGbqJzH4HiT1I58ecDiCAC716UyVA8Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.46.2", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.46.2.tgz", - "integrity": "sha512-1Uw2OslTWiOFDtt83y0bGiErJYy5MizadV0nHnOoHFWMoDqWW0kQoMFI65pXqRSkVvit5zjXSLik2xMiyQJDWQ==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.48.1.tgz", + "integrity": "sha512-/RFq3TqtXDUUawwic/A9xylA2P3LDMO8dNhphHAUOU51b1ZLHrmZ6YYJm3df1APz7xLY1aht6okCQf+/vmrV9w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.46.2", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.46.2.tgz", - "integrity": "sha512-xk9f+DPtNcddWN6E7n1hyNNsATBCHIqAvVGG2EAGHJc4AFYL18uM/kMTiOKXE/LKDPyy1JhIerrh9oYb7RBrgw==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.48.1.tgz", + "integrity": "sha512-Of0jTeAZRyRhC7XzDSjJef0aBkgRcvRAaw0ooYRlOw57APii7lZdq+layuNdeL72BRq1snaJhoMMwkmLIpJScw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.46.2.tgz", - "integrity": "sha512-NApbTPj9LxGzNw4dYnZmj2BoXiAc8NmbbH6qBNzQgXklGklt/xldTvu+FACN6ltFsTzoNU6j2mWNlHQTKGC5+Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.48.1.tgz", + "integrity": "sha512-bE7JcpFXzxF5zHwj/vkl2eiCBvyR1zQ7aoUdO+GDXxGp0DGw7nI0p8Xj6u8VmRQ+RDuPcICFQcCwRIJT5tDJFw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.46.2.tgz", - "integrity": "sha512-ekotpCwpSp033DIIrsTpYlGUCF6momkgupRV/FA3m62SreTSZUKjgK6VTNyG7TtYfq9YFm/pnh65bATP/ZWJEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.48.1.tgz", + "integrity": "sha512-MK3wZ2koLDnvH/AmqIF1EKbJlhRS5j74OZGkLpxI4rYvNi9Jn/C7vb5DytBnQ4KUWts7QsmbdwHkxY5txQHXVw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2" + "@algolia/client-common": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.46.2.tgz", - "integrity": "sha512-gKE+ZFi/6y7saTr34wS0SqYFDcjHW4Wminv8PDZEi0/mE99+hSrbKgJWxo2ztb5eqGirQTgIh1AMVacGGWM1iw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.48.1.tgz", + "integrity": "sha512-2oDT43Y5HWRSIQMPQI4tA/W+TN/N2tjggZCUsqQV440kxzzoPGsvv9QP1GhQ4CoDa+yn6ygUsGp6Dr+a9sPPSg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2" + "@algolia/client-common": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.46.2.tgz", - "integrity": "sha512-ciPihkletp7ttweJ8Zt+GukSVLp2ANJHU+9ttiSxsJZThXc4Y2yJ8HGVWesW5jN1zrsZsezN71KrMx/iZsOYpg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.48.1.tgz", + "integrity": "sha512-xcaCqbhupVWhuBP1nwbk1XNvwrGljozutEiLx06mvqDf3o8cHyEgQSHS4fKJM+UAggaWVnnFW+Nne5aQ8SUJXg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.46.2" + "@algolia/client-common": "5.48.1" }, "engines": { "node": ">= 14.0.0" @@ -258,13 +257,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2101.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2101.0.tgz", - "integrity": "sha512-vnNAzWXwSRGTHk2K7woIQsj7WDYZp69Z3DBdlxkK0H08ymkJ/ELbhN0/AnIJNNtYCqEb57AH7Ro98n422beDuw==", + "version": "0.2102.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.8.tgz", + "integrity": "sha512-b7su7AHIO5F2I6InEu/Bx/oXvGjdCP7kos2tGX73he/lPrTuizooils62OgAzgJ2UeKscyRNUjBPieFCy6XvHQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.1.0", + "@angular-devkit/core": "21.2.8", "rxjs": "7.8.2" }, "bin": { @@ -277,16 +276,16 @@ } }, "node_modules/@angular-devkit/core": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.1.0.tgz", - "integrity": "sha512-dPfVy0CictDjWffRv4pGTPOFjdlJL3ZkGUqxzaosUjMbJW+Ai9cNn1VNr7zxYZ4kem3BxLBh1thzDsCPrkXlZA==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.8.tgz", + "integrity": "sha512-DyxCILaaic/hfcfiBjAC/SdKE1ybSQIrU62/K5Msn3gZtThZj/T7cG0VHfbmpEFcgYkrQ9caUt6MCg8OoOVDzw==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.17.1", + "ajv": "8.18.0", "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", - "picomatch": "4.0.3", + "picomatch": "4.0.4", "rxjs": "7.8.2", "source-map": "0.7.6" }, @@ -305,16 +304,16 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.1.0.tgz", - "integrity": "sha512-sVgTntCZCOV7mOpHzj6V14KOAoy4B9Ur9yHNRFZVgL2yD77TYRrJ0qwq+l7Im9fSjMCar6csjboqCvyAEpfV1g==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.8.tgz", + "integrity": "sha512-UTEMM1JXzzxufLsTGDsWth2E7+8e9PaFT7nbjUvJ2qevltACkiqAbHEpiD2ISzrSRIO3OirJ+cZtnzXO0FyoBQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.1.0", + "@angular-devkit/core": "21.2.8", "jsonc-parser": "3.3.1", "magic-string": "0.30.21", - "ora": "9.0.0", + "ora": "9.3.0", "rxjs": "7.8.2" }, "engines": { @@ -324,22 +323,22 @@ } }, "node_modules/@angular/build": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.1.0.tgz", - "integrity": "sha512-ftms4F/TlkRNhf/4ykFO12zTG0f9sIRZ4fGFnaOVGmnKYkPKZklWvMCPoaoIligHS2pqKye1a5JSiTgTeUDp9w==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.8.tgz", + "integrity": "sha512-t0PHT7ONDMLwcjC9GaClNF+gsUKN78ofBikw4huiu6np5Rwmxp8KKCrdoRx20lOiibSolXgjZ2Ny0xxjNdNdQA==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2101.0", - "@babel/core": "7.28.5", + "@angular-devkit/architect": "0.2102.8", + "@babel/core": "7.29.0", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", "@inquirer/confirm": "5.1.21", - "@vitejs/plugin-basic-ssl": "2.1.0", - "beasties": "0.3.5", + "@vitejs/plugin-basic-ssl": "2.1.4", + "beasties": "0.4.1", "browserslist": "^4.26.0", - "esbuild": "0.27.2", + "esbuild": "0.27.3", "https-proxy-agent": "7.0.6", "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", @@ -347,16 +346,16 @@ "magic-string": "0.30.21", "mrmime": "2.0.1", "parse5-html-rewriting-stream": "8.0.0", - "picomatch": "4.0.3", + "picomatch": "4.0.4", "piscina": "5.1.4", - "rolldown": "1.0.0-beta.58", - "sass": "1.97.1", - "semver": "7.7.3", + "rolldown": "1.0.0-rc.4", + "sass": "1.97.3", + "semver": "7.7.4", "source-map-support": "0.5.21", "tinyglobby": "0.2.15", - "undici": "7.18.0", - "vite": "7.3.0", - "watchpack": "2.5.0" + "undici": "7.24.4", + "vite": "7.3.2", + "watchpack": "2.5.1" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0", @@ -364,7 +363,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "lmdb": "3.4.4" + "lmdb": "3.5.1" }, "peerDependencies": { "@angular/compiler": "^21.0.0", @@ -374,7 +373,7 @@ "@angular/platform-browser": "^21.0.0", "@angular/platform-server": "^21.0.0", "@angular/service-worker": "^21.0.0", - "@angular/ssr": "^21.1.0", + "@angular/ssr": "^21.2.8", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^21.0.0", @@ -424,31 +423,30 @@ } }, "node_modules/@angular/cli": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.1.0.tgz", - "integrity": "sha512-kzk8du388x6EBybJeq5AB27qGm8oGC9HhvBJDbu8o+aBIOY+JwVON9m4SYLCzeT+EVK8sKA1NMVYi2CDerk6hA==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.8.tgz", + "integrity": "sha512-Y+/US12o+7X2774oeKPsEfHeeYM2SxwnyoXfcaLR8vrMn0zxUrhHebmlz9h83th4EJEuex1Qk0JtF7j5vcwrqQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2101.0", - "@angular-devkit/core": "21.1.0", - "@angular-devkit/schematics": "21.1.0", + "@angular-devkit/architect": "0.2102.8", + "@angular-devkit/core": "21.2.8", + "@angular-devkit/schematics": "21.2.8", "@inquirer/prompts": "7.10.1", "@listr2/prompt-adapter-inquirer": "3.0.5", - "@modelcontextprotocol/sdk": "1.25.2", - "@schematics/angular": "21.1.0", + "@modelcontextprotocol/sdk": "1.26.0", + "@schematics/angular": "21.2.8", "@yarnpkg/lockfile": "1.1.0", - "algoliasearch": "5.46.2", + "algoliasearch": "5.48.1", "ini": "6.0.0", "jsonc-parser": "3.3.1", "listr2": "9.0.5", "npm-package-arg": "13.0.2", - "pacote": "21.0.4", + "pacote": "21.3.1", "parse5-html-rewriting-stream": "8.0.0", - "resolve": "1.22.11", - "semver": "7.7.3", + "semver": "7.7.4", "yargs": "18.0.0", - "zod": "4.3.5" + "zod": "4.3.6" }, "bin": { "ng": "bin/ng.js" @@ -460,9 +458,9 @@ } }, "node_modules/@angular/common": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.1.0.tgz", - "integrity": "sha512-hL3Chp51TU9iBcIfkNtoBS1wuseP1gsyDW2IFtK5HUpAVhbso9B3fdCaDTFkU98A2unluo2YgzI6D/6IS6N+1g==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.9.tgz", + "integrity": "sha512-7spQcF3hPN/fjTx6Pwa32KRRdO0NcixnRuPV4lo50ejtXesjiLVR+fkaX38sawAyGoq89IuuYvUDrbLwCMypmQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -471,14 +469,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.1.0", + "@angular/core": "21.2.9", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.1.0.tgz", - "integrity": "sha512-UprCiJwEU1Ilw1dVk+yLgNiHlbH81obAuh92lRKozUQRgtSCpOfCQUM79q5r+VdmCPxDshr79U2Ke0fRaiJfAQ==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.9.tgz", + "integrity": "sha512-clsK1EsSPtAuqlRl4CciA/gsvsW7xe0eWcvHxtrMW6DYaUJ6X4AAuDxEEJ5cf/3Mpw4s8KssjIUPPtbrUIGLSQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -488,13 +486,13 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.1.0.tgz", - "integrity": "sha512-//BTtxJovsF0LaOWQkOVxWX4EVyNJaPus+IlwWxzmdRHpojIl1Zdyy9BJMVJOifvj3XQ16sZwR1PDWDI5DIWrg==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.9.tgz", + "integrity": "sha512-hTTW/OiqTXrwTneS18CMp47OX0XSbLYl2rIomLS3nXVJniSETH6S/k+LqQtGWWgLbzsd3PzUOOckHnvzpTBTsA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "7.28.5", + "@babel/core": "7.29.0", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^5.0.0", "convert-source-map": "^1.5.1", @@ -511,8 +509,8 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.1.0", - "typescript": ">=5.9 <6.0" + "@angular/compiler": "21.2.9", + "typescript": ">=5.9 <6.1" }, "peerDependenciesMeta": { "typescript": { @@ -521,9 +519,9 @@ } }, "node_modules/@angular/core": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.1.0.tgz", - "integrity": "sha512-QTl9s8GYNN0pt1k3GE6UVlfe6zWtfdykhfchinKq2YJywQ6LBM4UcZgoc56YkgscmyrRFYrr4JYUJjlzTF57+A==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.9.tgz", + "integrity": "sha512-uZLq2aedJ+0uEZxyf6a1Nc7y1aZ7akAW7K1Kon8JUDZOvI2IDbk0i00MzkELt8q9uSmSSqg9zNKuhjspFf0Pyw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -532,7 +530,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.1.0", + "@angular/compiler": "21.2.9", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, @@ -546,9 +544,9 @@ } }, "node_modules/@angular/forms": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.1.0.tgz", - "integrity": "sha512-1Qxsu2cQhraKe2dKzIVm7no1qWi76QsXVwY7+VGKRYG7p+fKaFmnr7oU5EbJL66TsFzCb8mDGxLGikS+YE+X/g==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.9.tgz", + "integrity": "sha512-qXLnzmsJoHMgV/gDU7AZgsKBhUH7k6im6V9YuY5UpHHl+nGKCWxtePAZRB0OH2AsqzLwER3Fv2S6+mtmb7651w==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -558,16 +556,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.1.0", - "@angular/core": "21.1.0", - "@angular/platform-browser": "21.1.0", + "@angular/common": "21.2.9", + "@angular/core": "21.2.9", + "@angular/platform-browser": "21.2.9", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.1.0.tgz", - "integrity": "sha512-Drkal25x+OuRQosAE/cL4uM5WDmgFehanCpsjQ1jGp6Rxoad6Q5Do1uQAE3qgMKHL1aqCPZ+uWzcVVG+Bn1ddg==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.9.tgz", + "integrity": "sha512-MjEtFvoFtsjsAeu2yzauqGgwwEHV4ml25c9vGFmw4OmSoNme4yp41f2DegwOkn1TTHL3OF3GE65ng2U2feJU4Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -576,9 +574,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "21.1.0", - "@angular/common": "21.1.0", - "@angular/core": "21.1.0" + "@angular/animations": "21.2.9", + "@angular/common": "21.2.9", + "@angular/core": "21.2.9" }, "peerDependenciesMeta": { "@angular/animations": { @@ -587,9 +585,9 @@ } }, "node_modules/@angular/router": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.1.0.tgz", - "integrity": "sha512-Sneu0ePuH+bf8ZslRX3iQk1iLziindLskdTeHV1ZCrXdT0ZScsZyI/gjxQKBtsIU9692D2DnFQRLGnzTBYVGVw==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.9.tgz", + "integrity": "sha512-ExqOEO6IUuNaI75ZcjAbOuzJKpvVze6hRdETyVf7Sny07+XSKv9t8DK9tBHmR7+67wz+zPIUgCXxsQXi8jJu0w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -598,30 +596,30 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.1.0", - "@angular/core": "21.1.0", - "@angular/platform-browser": "21.1.0", + "@angular/common": "21.2.9", + "@angular/core": "21.2.9", + "@angular/platform-browser": "21.2.9", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@asamuzakjp/css-color": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", - "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.2.tgz", + "integrity": "sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.4" + "@csstools/css-calc": "^3.0.0", + "@csstools/css-color-parser": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.5" } }, "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -629,9 +627,9 @@ } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.7.6", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", - "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -639,13 +637,13 @@ "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.4" + "lru-cache": "^11.2.6" } }, "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -660,9 +658,9 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", - "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { @@ -675,9 +673,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", - "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true, "license": "MIT", "engines": { @@ -685,21 +683,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -733,14 +731,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", - "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -875,27 +873,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -920,18 +918,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", - "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -939,9 +937,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { @@ -953,9 +951,9 @@ } }, "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", "dev": true, "funding": [ { @@ -969,13 +967,13 @@ ], "license": "MIT-0", "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.0.tgz", + "integrity": "sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==", "dev": true, "funding": [ { @@ -989,17 +987,17 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz", + "integrity": "sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==", "dev": true, "funding": [ { @@ -1013,21 +1011,21 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.2.0" }, "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", "dev": true, "funding": [ { @@ -1041,16 +1039,16 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" + "@csstools/css-tokenizer": "^4.0.0" } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.25.tgz", - "integrity": "sha512-g0Kw9W3vjx5BEBAF8c5Fm2NcB/Fs8jJXh85aXqwEXiL+tqtOut07TWgyaGzAAfTM+gKckrrncyeGEZPcaRgm2Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz", + "integrity": "sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==", "dev": true, "funding": [ { @@ -1063,14 +1061,19 @@ } ], "license": "MIT-0", - "engines": { - "node": ">=18" + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } } }, "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", "dev": true, "funding": [ { @@ -1084,47 +1087,50 @@ ], "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20.19.0" } }, "node_modules/@emnapi/core": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", - "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "@emnapi/wasi-threads": "1.1.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "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" ], @@ -1139,9 +1145,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "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" ], @@ -1156,9 +1162,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "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" ], @@ -1173,9 +1179,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "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" ], @@ -1190,9 +1196,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "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" ], @@ -1207,9 +1213,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "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" ], @@ -1224,9 +1230,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "cpu": [ "arm64" ], @@ -1241,9 +1247,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "cpu": [ "x64" ], @@ -1258,9 +1264,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "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" ], @@ -1275,9 +1281,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "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" ], @@ -1292,9 +1298,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "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" ], @@ -1309,9 +1315,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "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" ], @@ -1326,9 +1332,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "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" ], @@ -1343,9 +1349,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "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" ], @@ -1360,9 +1366,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "cpu": [ "riscv64" ], @@ -1377,9 +1383,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "cpu": [ "s390x" ], @@ -1394,9 +1400,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "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" ], @@ -1411,9 +1417,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "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" ], @@ -1428,9 +1434,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "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" ], @@ -1445,9 +1451,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "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" ], @@ -1462,9 +1468,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "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" ], @@ -1479,9 +1485,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "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" ], @@ -1496,9 +1502,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "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" ], @@ -1513,9 +1519,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "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" ], @@ -1530,9 +1536,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "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" ], @@ -1547,9 +1553,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "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" ], @@ -1564,9 +1570,9 @@ } }, "node_modules/@exodus/bytes": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.9.0.tgz", - "integrity": "sha512-lagqsvnk09NKogQaN/XrtlWeUF8SRhT12odMvbTIIaVObqzwAogL6jhR4DAp0gPuKoM1AOVrKUshJpRdpMFrww==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", + "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", "dev": true, "license": "MIT", "engines": { @@ -1581,10 +1587,28 @@ } } }, + "node_modules/@gar/promise-retry": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", + "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@harperfast/extended-iterable": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", + "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", "dev": true, "license": "MIT", "engines": { @@ -1944,29 +1968,6 @@ } } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -1981,9 +1982,9 @@ } }, "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", "dev": true, "license": "MIT", "engines": { @@ -2058,9 +2059,9 @@ } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.4.4.tgz", - "integrity": "sha512-XaKL705gDWd6XVls3ATDj13ZdML/LqSIxwgnYpG8xTzH2ifArx8fMMDdvqGE/Emd+W6R90W2fveZcJ0AyS8Y0w==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", + "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", "cpu": [ "arm64" ], @@ -2072,9 +2073,9 @@ ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.4.4.tgz", - "integrity": "sha512-GPHGEVcwJlkD01GmIr7B4kvbIcUDS2+kBadVEd7lU4can1RZaZQLDDBJRrrNfS2Kavvl0VLI/cMv7UASAXGrww==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", + "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", "cpu": [ "x64" ], @@ -2086,9 +2087,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.4.4.tgz", - "integrity": "sha512-cmev5/dZr5ACKri9f6GU6lZCXTjMhV72xujlbOhFCgFXrt4W0TxGsmY8kA1BITvH60JBKE50cSxsiulybAbrrw==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", + "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", "cpu": [ "arm" ], @@ -2100,9 +2101,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.4.4.tgz", - "integrity": "sha512-mALqr7DE42HsiwVTKpQWxacjHoJk+e9p00RWIJqTACh/hpucxp/0lK/XMh5XzWnU/TDCZLukq1+vNqnNumTP/Q==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", + "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", "cpu": [ "arm64" ], @@ -2114,9 +2115,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.4.4.tgz", - "integrity": "sha512-QjLs8OcmCNcraAcLoZyFlo0atzBJniQLLwhtR+ymQqS5kLYpV5RqwriL87BW+ZiR9ZiGgZx3evrz5vnWPtJ1fQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", + "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", "cpu": [ "x64" ], @@ -2128,9 +2129,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-arm64": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.4.4.tgz", - "integrity": "sha512-tr/pwHDlZ33forLGAr0tI04cRmP4SgF93yHbb+2zvZiDEyln5yMHhbKDySxY66aUOkhvBvTuHq9q/3YmTj6ZHQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", + "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", "cpu": [ "arm64" ], @@ -2142,9 +2143,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.4.4.tgz", - "integrity": "sha512-KRzfocJzB/mgoTCqnMawuLSKheHRVTqWfSmouIgYpFs6Hx4zvZSvsZKSCEb5gHmICy7qsx9l06jk3MFTtiFVAQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", + "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", "cpu": [ "x64" ], @@ -2156,13 +2157,13 @@ ] }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.25.2", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.2.tgz", - "integrity": "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==", + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", "dev": true, "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.7", + "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", @@ -2170,14 +2171,15 @@ "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "jose": "^6.1.1", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.0" + "zod-to-json-schema": "^3.25.1" }, "engines": { "node": ">=18" @@ -2603,20 +2605,22 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", - "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@npmcli/agent": { @@ -2637,9 +2641,9 @@ } }, "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -2660,18 +2664,18 @@ } }, "node_modules/@npmcli/git": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.1.tgz", - "integrity": "sha512-+XTFxK2jJF/EJJ5SoAzXk3qwIDfvFc5/g+bD274LZ7uY7LE8sTfG6Z8rOanPl2ZEvZWqNvmEdtXC25cE54VcoA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.2.tgz", + "integrity": "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==", "dev": true, "license": "ISC", "dependencies": { + "@gar/promise-retry": "^1.0.0", "@npmcli/promise-spawn": "^9.0.0", "ini": "^6.0.0", "lru-cache": "^11.2.1", "npm-pick-manifest": "^11.0.1", "proc-log": "^6.0.0", - "promise-retry": "^2.0.1", "semver": "^7.3.5", "which": "^6.0.0" }, @@ -2680,19 +2684,19 @@ } }, "node_modules/@npmcli/git/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=20" } }, "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -2700,13 +2704,13 @@ } }, "node_modules/@npmcli/git/node_modules/which": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", - "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", "dev": true, "license": "ISC", "dependencies": { - "isexe": "^3.1.1" + "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" @@ -2743,9 +2747,9 @@ } }, "node_modules/@npmcli/package-json": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.4.tgz", - "integrity": "sha512-0wInJG3j/K40OJt/33ax47WfWMzZTm6OQxB9cDhTt5huCP2a9g2GnlsxmfN+PulItNPIpPrZ+kfwwUil7eHcZQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.5.tgz", + "integrity": "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==", "dev": true, "license": "ISC", "dependencies": { @@ -2755,7 +2759,7 @@ "json-parse-even-better-errors": "^5.0.0", "proc-log": "^6.0.0", "semver": "^7.5.3", - "validate-npm-package-license": "^3.0.4" + "spdx-expression-parse": "^4.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -2775,23 +2779,23 @@ } }, "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=20" } }, "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", - "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", "dev": true, "license": "ISC", "dependencies": { - "isexe": "^3.1.1" + "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" @@ -2811,9 +2815,9 @@ } }, "node_modules/@npmcli/run-script": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.3.tgz", - "integrity": "sha512-ER2N6itRkzWbbtVmZ9WKaWxVlKlOeBFF1/7xx+KA5J1xKa4JjUwBdb6tDpk0v1qA+d+VDwHI9qmLcXSWcmi+Rw==", + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.4.tgz", + "integrity": "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==", "dev": true, "license": "ISC", "dependencies": { @@ -2821,43 +2825,16 @@ "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "node-gyp": "^12.1.0", - "proc-log": "^6.0.0", - "which": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/@npmcli/run-script/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", - "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "proc-log": "^6.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@oxc-project/types": { - "version": "0.106.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.106.0.tgz", - "integrity": "sha512-QdsH3rZq480VnOHSHgPYOhjL8O8LBdcnSjM408BpPCCUc0JYYZPG9Gafl9i3OcGk/7137o+gweb4cCv3WAUykg==", + "version": "0.113.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", + "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", "dev": true, "license": "MIT", "funding": { @@ -2865,9 +2842,9 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.4.tgz", - "integrity": "sha512-WYa2tUVV5HiArWPB3ydlOc4R2ivq0IDrlqhMi3l7mVsFEXNcTfxYFPIHXHXIh/ca/y/V5N4E1zecyxdIBjYnkQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2886,25 +2863,25 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.4", - "@parcel/watcher-darwin-arm64": "2.5.4", - "@parcel/watcher-darwin-x64": "2.5.4", - "@parcel/watcher-freebsd-x64": "2.5.4", - "@parcel/watcher-linux-arm-glibc": "2.5.4", - "@parcel/watcher-linux-arm-musl": "2.5.4", - "@parcel/watcher-linux-arm64-glibc": "2.5.4", - "@parcel/watcher-linux-arm64-musl": "2.5.4", - "@parcel/watcher-linux-x64-glibc": "2.5.4", - "@parcel/watcher-linux-x64-musl": "2.5.4", - "@parcel/watcher-win32-arm64": "2.5.4", - "@parcel/watcher-win32-ia32": "2.5.4", - "@parcel/watcher-win32-x64": "2.5.4" + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.4.tgz", - "integrity": "sha512-hoh0vx4v+b3BNI7Cjoy2/B0ARqcwVNrzN/n7DLq9ZB4I3lrsvhrkCViJyfTj/Qi5xM9YFiH4AmHGK6pgH1ss7g==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", "cpu": [ "arm64" ], @@ -2923,9 +2900,9 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.4.tgz", - "integrity": "sha512-kphKy377pZiWpAOyTgQYPE5/XEKVMaj6VUjKT5VkNyUJlr2qZAn8gIc7CPzx+kbhvqHDT9d7EqdOqRXT6vk0zw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", "cpu": [ "arm64" ], @@ -2944,9 +2921,9 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.4.tgz", - "integrity": "sha512-UKaQFhCtNJW1A9YyVz3Ju7ydf6QgrpNQfRZ35wNKUhTQ3dxJ/3MULXN5JN/0Z80V/KUBDGa3RZaKq1EQT2a2gg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", "cpu": [ "x64" ], @@ -2965,9 +2942,9 @@ } }, "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.4.tgz", - "integrity": "sha512-Dib0Wv3Ow/m2/ttvLdeI2DBXloO7t3Z0oCp4bAb2aqyqOjKPPGrg10pMJJAQ7tt8P4V2rwYwywkDhUia/FgS+Q==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", "cpu": [ "x64" ], @@ -2986,9 +2963,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.4.tgz", - "integrity": "sha512-I5Vb769pdf7Q7Sf4KNy8Pogl/URRCKu9ImMmnVKYayhynuyGYMzuI4UOWnegQNa2sGpsPSbzDsqbHNMyeyPCgw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", "cpu": [ "arm" ], @@ -3007,9 +2984,9 @@ } }, "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.4.tgz", - "integrity": "sha512-kGO8RPvVrcAotV4QcWh8kZuHr9bXi9a3bSZw7kFarYR0+fGliU7hd/zevhjw8fnvIKG3J9EO5G6sXNGCSNMYPQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", "cpu": [ "arm" ], @@ -3028,9 +3005,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.4.tgz", - "integrity": "sha512-KU75aooXhqGFY2W5/p8DYYHt4hrjHZod8AhcGAmhzPn/etTa+lYCDB2b1sJy3sWJ8ahFVTdy+EbqSBvMx3iFlw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", "cpu": [ "arm64" ], @@ -3049,9 +3026,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.4.tgz", - "integrity": "sha512-Qx8uNiIekVutnzbVdrgSanM+cbpDD3boB1f8vMtnuG5Zau4/bdDbXyKwIn0ToqFhIuob73bcxV9NwRm04/hzHQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", "cpu": [ "arm64" ], @@ -3070,9 +3047,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.4.tgz", - "integrity": "sha512-UYBQvhYmgAv61LNUn24qGQdjtycFBKSK3EXr72DbJqX9aaLbtCOO8+1SkKhD/GNiJ97ExgcHBrukcYhVjrnogA==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", "cpu": [ "x64" ], @@ -3091,9 +3068,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.4.tgz", - "integrity": "sha512-YoRWCVgxv8akZrMhdyVi6/TyoeeMkQ0PGGOf2E4omODrvd1wxniXP+DBynKoHryStks7l+fDAMUBRzqNHrVOpg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", "cpu": [ "x64" ], @@ -3112,9 +3089,9 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.4.tgz", - "integrity": "sha512-iby+D/YNXWkiQNYcIhg8P5hSjzXEHaQrk2SLrWOUD7VeC4Ohu0WQvmV+HDJokZVJ2UjJ4AGXW3bx7Lls9Ln4TQ==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", "cpu": [ "arm64" ], @@ -3133,9 +3110,9 @@ } }, "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.4.tgz", - "integrity": "sha512-vQN+KIReG0a2ZDpVv8cgddlf67J8hk1WfZMMP7sMeZmJRSmEax5xNDNWKdgqSe2brOKTQQAs3aCCUal2qBHAyg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", "cpu": [ "ia32" ], @@ -3154,9 +3131,9 @@ } }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.4.tgz", - "integrity": "sha512-3A6efb6BOKwyw7yk9ro2vus2YTt2nvcd56AuzxdMiVOxL9umDyN5PKkKfZ/gZ9row41SjVmTVQNWQhaRRGpOKw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", "cpu": [ "x64" ], @@ -3183,9 +3160,9 @@ "optional": true }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.58.tgz", - "integrity": "sha512-mWj5eE4Qc8TbPdGGaaLvBb9XfDPvE1EmZkJQgiGKwchkWH4oAJcRAKMTw7ZHnb1L+t7Ah41sBkAecaIsuUgsug==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", "cpu": [ "arm64" ], @@ -3200,9 +3177,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.58.tgz", - "integrity": "sha512-wFxUymI/5R8bH8qZFYDfAxAN9CyISEIYke+95oZPiv6EWo88aa5rskjVcCpKA532R+klFmdqjbbaD56GNmTF4Q==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", "cpu": [ "arm64" ], @@ -3217,9 +3194,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.58.tgz", - "integrity": "sha512-ybp3MkPj23VDV9PhtRwdU5qrGhlViWRV5BjKwO6epaSlUD5lW0WyY+roN3ZAzbma/9RrMTgZ/a/gtQq8YXOcqw==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", "cpu": [ "x64" ], @@ -3234,9 +3211,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.58.tgz", - "integrity": "sha512-Evxj3yh7FWvyklUYZa0qTVT9N2zX9TPDqGF056hl8hlCZ9/ndQ2xMv6uw9PD1VlLpukbsqL+/C6M0qwipL0QMg==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", "cpu": [ "x64" ], @@ -3251,9 +3228,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.58.tgz", - "integrity": "sha512-tYeXprDOrEgVHUbPXH6MPso4cM/c6RTkmJNICMQlYdki4hGMh92aj3yU6CKs+4X5gfG0yj5kVUw/L4M685SYag==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", + "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", "cpu": [ "arm" ], @@ -3268,9 +3245,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.58.tgz", - "integrity": "sha512-N78vmZzP6zG967Ohr+MasCjmKtis0geZ1SOVmxrA0/bklTQSzH5kHEjW5Qn+i1taFno6GEre1E40v0wuWsNOQw==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", "cpu": [ "arm64" ], @@ -3285,9 +3262,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.58.tgz", - "integrity": "sha512-l+p4QVtG72C7wI2SIkNQw/KQtSjuYwS3rV6AKcWrRBF62ClsFUcif5vLaZIEbPrCXu5OFRXigXFJnxYsVVZqdQ==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", "cpu": [ "arm64" ], @@ -3302,9 +3279,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.58.tgz", - "integrity": "sha512-urzJX0HrXxIh0FfxwWRjfPCMeInU9qsImLQxHBgLp5ivji1EEUnOfux8KxPPnRQthJyneBrN2LeqUix9DYrNaQ==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", "cpu": [ "x64" ], @@ -3319,9 +3296,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.58.tgz", - "integrity": "sha512-7ijfVK3GISnXIwq/1FZo+KyAUJjL3kWPJ7rViAL6MWeEBhEgRzJ0yEd9I8N9aut8Y8ab+EKFJyRNMWZuUBwQ0A==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", "cpu": [ "x64" ], @@ -3336,9 +3313,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.58.tgz", - "integrity": "sha512-/m7sKZCS+cUULbzyJTIlv8JbjNohxbpAOA6cM+lgWgqVzPee3U6jpwydrib328JFN/gF9A99IZEnuGYqEDJdww==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", "cpu": [ "arm64" ], @@ -3353,9 +3330,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.58.tgz", - "integrity": "sha512-6SZk7zMgv+y3wFFQ9qE5P9NnRHcRsptL1ypmudD26PDY+PvFCvfHRkJNfclWnvacVGxjowr7JOL3a9fd1wWhUw==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", + "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", "cpu": [ "wasm32" ], @@ -3370,9 +3347,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.58.tgz", - "integrity": "sha512-sFqfYPnBZ6xBhMkadB7UD0yjEDRvs7ipR3nCggblN+N4ODCXY6qhg/bKL39+W+dgQybL7ErD4EGERVbW9DAWvg==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", "cpu": [ "arm64" ], @@ -3387,9 +3364,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.58.tgz", - "integrity": "sha512-AnFWJdAqB8+IDPcGrATYs67Kik/6tnndNJV2jGRmwlbeNiQQ8GhRJU8ETRlINfII0pqi9k4WWLnb00p1QCxw/Q==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", "cpu": [ "x64" ], @@ -3404,16 +3381,16 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.58.tgz", - "integrity": "sha512-qWhDs6yFGR5xDfdrwiSa3CWGIHxD597uGE/A9xGqytBjANvh4rLCTTkq7szhMV4+Ygh+PMS90KVJ8xWG/TkX4w==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.4.tgz", + "integrity": "sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==", "dev": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", - "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", + "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", "cpu": [ "arm" ], @@ -3425,9 +3402,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", - "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", + "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", "cpu": [ "arm64" ], @@ -3439,9 +3416,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", - "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", + "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", "cpu": [ "arm64" ], @@ -3453,9 +3430,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", - "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", + "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", "cpu": [ "x64" ], @@ -3467,9 +3444,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", - "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", + "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", "cpu": [ "arm64" ], @@ -3481,9 +3458,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", - "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", + "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", "cpu": [ "x64" ], @@ -3495,9 +3472,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", - "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", + "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", "cpu": [ "arm" ], @@ -3509,9 +3486,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", - "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", + "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", "cpu": [ "arm" ], @@ -3523,9 +3500,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", - "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", + "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", "cpu": [ "arm64" ], @@ -3537,9 +3514,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", - "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", + "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", "cpu": [ "arm64" ], @@ -3551,9 +3528,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", - "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", + "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", "cpu": [ "loong64" ], @@ -3565,9 +3542,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", - "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", + "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", "cpu": [ "loong64" ], @@ -3579,9 +3556,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", - "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", + "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", "cpu": [ "ppc64" ], @@ -3593,9 +3570,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", - "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", + "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", "cpu": [ "ppc64" ], @@ -3607,9 +3584,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", - "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", + "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", "cpu": [ "riscv64" ], @@ -3621,9 +3598,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", - "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", + "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", "cpu": [ "riscv64" ], @@ -3635,9 +3612,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", - "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", + "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", "cpu": [ "s390x" ], @@ -3649,9 +3626,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", - "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", "cpu": [ "x64" ], @@ -3663,9 +3640,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", - "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", + "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", "cpu": [ "x64" ], @@ -3677,9 +3654,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", - "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", + "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", "cpu": [ "x64" ], @@ -3691,9 +3668,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", - "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", + "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", "cpu": [ "arm64" ], @@ -3705,9 +3682,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", - "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", + "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", "cpu": [ "arm64" ], @@ -3719,9 +3696,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", - "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", + "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", "cpu": [ "ia32" ], @@ -3733,9 +3710,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", - "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", + "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", "cpu": [ "x64" ], @@ -3747,9 +3724,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", - "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", + "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", "cpu": [ "x64" ], @@ -3761,14 +3738,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.1.0.tgz", - "integrity": "sha512-gXf3gO5SeU+tiPHxXeQvdbua4C4/V+KH43JH2PYPxaNCD2HGo1uV0pfyNSNgcVF21voKlbAQ13YRrNDh7z5Kig==", + "version": "21.2.8", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.8.tgz", + "integrity": "sha512-Kx3PmuZIXhwQqAqoERAXqDCORHFbKTMd+eflXwZfpKkrbWJTVPqKpL4R9RVdEr2E6/VEXDFrdL1whIvGd1xmDg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.1.0", - "@angular-devkit/schematics": "21.1.0", + "@angular-devkit/core": "21.2.8", + "@angular-devkit/schematics": "21.2.8", "jsonc-parser": "3.3.1" }, "engines": { @@ -3791,9 +3768,9 @@ } }, "node_modules/@sigstore/core": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.1.0.tgz", - "integrity": "sha512-o5cw1QYhNQ9IroioJxpzexmPjfCe7gzafd2RY3qnMpxr4ZEja+Jad/U8sgFpaue6bOaF+z7RVkyKVV44FN+N8A==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.0.tgz", + "integrity": "sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -3801,9 +3778,9 @@ } }, "node_modules/@sigstore/protobuf-specs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.0.tgz", - "integrity": "sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.1.tgz", + "integrity": "sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g==", "dev": true, "license": "Apache-2.0", "engines": { @@ -3811,27 +3788,27 @@ } }, "node_modules/@sigstore/sign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.1.0.tgz", - "integrity": "sha512-Vx1RmLxLGnSUqx/o5/VsCjkuN5L7y+vxEEwawvc7u+6WtX2W4GNa7b9HEjmcRWohw/d6BpATXmvOwc78m+Swdg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.1.1.tgz", + "integrity": "sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ==", "dev": true, "license": "Apache-2.0", "dependencies": { + "@gar/promise-retry": "^1.0.2", "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.1.0", + "@sigstore/core": "^3.2.0", "@sigstore/protobuf-specs": "^0.5.0", - "make-fetch-happen": "^15.0.3", - "proc-log": "^6.1.0", - "promise-retry": "^2.0.1" + "make-fetch-happen": "^15.0.4", + "proc-log": "^6.1.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@sigstore/tuf": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.1.tgz", - "integrity": "sha512-OPZBg8y5Vc9yZjmWCHrlWPMBqW5yd8+wFNl+thMdtcWz3vjVSoJQutF8YkrzI0SLGnkuFof4HSsWUhXrf219Lw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.2.tgz", + "integrity": "sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3924,9 +3901,9 @@ "license": "MIT" }, "node_modules/@vitejs/plugin-basic-ssl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz", - "integrity": "sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", + "integrity": "sha512-HXciTXN/sDBYWgeAD4V4s0DN0g72x5mlxQhHxtYu3Tt8BLa6MzcJZUyDVFCdtjNs3bfENVHVzOsmooTVuNgAAw==", "dev": true, "license": "MIT", "engines": { @@ -3937,31 +3914,31 @@ } }, "node_modules/@vitest/expect": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.17.tgz", - "integrity": "sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", + "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.0.0", + "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.17", - "@vitest/utils": "4.0.17", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/mocker": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.17.tgz", - "integrity": "sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", + "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.0.17", + "@vitest/spy": "4.1.5", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -3970,7 +3947,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -3982,26 +3959,26 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.17.tgz", - "integrity": "sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", + "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^3.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.17.tgz", - "integrity": "sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", + "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.0.17", + "@vitest/utils": "4.1.5", "pathe": "^2.0.3" }, "funding": { @@ -4009,13 +3986,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.17.tgz", - "integrity": "sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", + "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.17", + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -4024,9 +4002,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.17.tgz", - "integrity": "sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", + "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", "dev": true, "license": "MIT", "funding": { @@ -4034,19 +4012,27 @@ } }, "node_modules/@vitest/utils": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.17.tgz", - "integrity": "sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", + "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.0.17", - "tinyrainbow": "^3.0.3" + "@vitest/pretty-format": "4.1.5", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/utils/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -4089,9 +4075,9 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -4124,49 +4110,35 @@ } }, "node_modules/algoliasearch": { - "version": "5.46.2", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.46.2.tgz", - "integrity": "sha512-qqAXW9QvKf2tTyhpDA4qXv1IfBwD2eduSW6tUEBFIfCeE9gn9HQ9I5+MaKoenRuHrzk5sQoNh1/iof8mY7uD6Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.48.1.tgz", + "integrity": "sha512-Rf7xmeuIo7nb6S4mp4abW2faW8DauZyE2faBIKFaUfP3wnpOvNSbiI5AwVhqBNj0jPgBWEvhyCu0sLjN2q77Rg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/abtesting": "1.12.2", - "@algolia/client-abtesting": "5.46.2", - "@algolia/client-analytics": "5.46.2", - "@algolia/client-common": "5.46.2", - "@algolia/client-insights": "5.46.2", - "@algolia/client-personalization": "5.46.2", - "@algolia/client-query-suggestions": "5.46.2", - "@algolia/client-search": "5.46.2", - "@algolia/ingestion": "1.46.2", - "@algolia/monitoring": "1.46.2", - "@algolia/recommend": "5.46.2", - "@algolia/requester-browser-xhr": "5.46.2", - "@algolia/requester-fetch": "5.46.2", - "@algolia/requester-node-http": "5.46.2" + "@algolia/abtesting": "1.14.1", + "@algolia/client-abtesting": "5.48.1", + "@algolia/client-analytics": "5.48.1", + "@algolia/client-common": "5.48.1", + "@algolia/client-insights": "5.48.1", + "@algolia/client-personalization": "5.48.1", + "@algolia/client-query-suggestions": "5.48.1", + "@algolia/client-search": "5.48.1", + "@algolia/ingestion": "1.48.1", + "@algolia/monitoring": "1.48.1", + "@algolia/recommend": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { "node": ">= 14.0.0" } }, - "node_modules/angularx-qrcode": { - "version": "21.0.4", - "resolved": "https://registry.npmjs.org/angularx-qrcode/-/angularx-qrcode-21.0.4.tgz", - "integrity": "sha512-GZFa/X/3rHx/4peA4zNROkK6UaYqxJX0dgkEMk7dCcoYNwJM8/UkOkEUfcx+Btjr7iT4UEhf9twWhFjFp58wfw==", - "license": "MIT", - "dependencies": { - "qrcode": "1.5.4", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": "^21.0.0", - "@angular/core": "^21.0.0" - } - }, "node_modules/ansi-escapes": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", - "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", "dev": true, "license": "MIT", "dependencies": { @@ -4215,20 +4187,33 @@ "node": ">=12" } }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/baseline-browser-mapping": { - "version": "2.9.15", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.15.tgz", - "integrity": "sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==", + "version": "2.10.21", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.21.tgz", + "integrity": "sha512-Q+rUQ7Uz8AHM7DEaNdwvfFCTq7a43lNTzuS94eiWqwyxfV/wJv+oUivef51T91mmRY4d4A1u9rcSvkeufCVXlA==", "dev": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/beasties": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.3.5.tgz", - "integrity": "sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.1.tgz", + "integrity": "sha512-2Imdcw3LznDuxAbJM26RHniOLAzE6WgrK8OuvVXCQtNBS8rsnD9zsSEa3fHl4hHpUY7BYTlrpvtPVbvu9G6neg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4239,10 +4224,11 @@ "htmlparser2": "^10.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.49", - "postcss-media-query-parser": "^0.2.3" + "postcss-media-query-parser": "^0.2.3", + "postcss-safe-parser": "^7.0.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/bidi-js": { @@ -4287,10 +4273,23 @@ "dev": true, "license": "ISC" }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -4308,11 +4307,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -4339,9 +4338,9 @@ } }, "node_modules/cacache": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", - "integrity": "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==", + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.4.tgz", + "integrity": "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==", "dev": true, "license": "ISC", "dependencies": { @@ -4354,17 +4353,16 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", - "ssri": "^13.0.0", - "unique-filename": "^5.0.0" + "ssri": "^13.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, "node_modules/cacache/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -4402,19 +4400,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/caniuse-lite": { - "version": "1.0.30001765", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz", - "integrity": "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==", + "version": "1.0.30001790", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001790.tgz", + "integrity": "sha512-bOoxfJPyYo+ds6W0YfptaCWbFnJYjh2Y1Eow5lRv+vI2u8ganPZqNm1JwNh0t2ELQCqIWg4B3dWEusgAmsoyOw==", "dev": true, "funding": [ { @@ -4518,14 +4507,14 @@ } }, "node_modules/cli-truncate": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", - "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", "dev": true, "license": "MIT", "dependencies": { - "slice-ansi": "^7.1.0", - "string-width": "^8.0.0" + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" }, "engines": { "node": ">=20" @@ -4599,6 +4588,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -4611,6 +4601,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, "license": "MIT" }, "node_modules/colorette": { @@ -4621,9 +4612,9 @@ "license": "MIT" }, "node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "dev": true, "license": "MIT", "engines": { @@ -4672,9 +4663,9 @@ } }, "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "dev": true, "license": "MIT", "dependencies": { @@ -4683,6 +4674,10 @@ }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cross-spawn": { @@ -4718,14 +4713,14 @@ } }, "node_modules/css-tree": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", - "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, "license": "MIT", "dependencies": { - "mdn-data": "2.12.2", - "source-map-js": "^1.0.1" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" @@ -4761,9 +4756,9 @@ } }, "node_modules/cssstyle/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -4771,19 +4766,29 @@ } }, "node_modules/data-urls": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", - "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.1.tgz", + "integrity": "sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==", "dev": true, "license": "MIT", "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^15.1.0" }, "engines": { "node": ">=20" } }, + "node_modules/data-urls/node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -4802,15 +4807,6 @@ } } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/decimal.js": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", @@ -4839,12 +4835,6 @@ "node": ">=8" } }, - "node_modules/dijkstrajs": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", - "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", - "license": "MIT" - }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -4927,9 +4917,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "version": "1.5.343", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.343.tgz", + "integrity": "sha512-YHnQ3MXI08icvL9ZKnEBy05F2EQ8ob01UaMOuMbM8l+4UcAq6MPPbBTJBbsBUg3H8JeZNt+O4fjsoWth3p6IFg==", "dev": true, "license": "ISC" }, @@ -4950,31 +4940,6 @@ "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -5039,9 +5004,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, "license": "MIT" }, @@ -5059,9 +5024,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "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", @@ -5072,32 +5037,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" + "@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/escalade": { @@ -5138,9 +5103,9 @@ } }, "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "dev": true, "license": "MIT" }, @@ -5158,9 +5123,9 @@ } }, "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.8.tgz", + "integrity": "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==", "dev": true, "license": "MIT", "engines": { @@ -5229,11 +5194,14 @@ } }, "node_modules/express-rate-limit": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", - "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.2.tgz", + "integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==", "dev": true, "license": "MIT", + "dependencies": { + "ip-address": "10.1.0" + }, "engines": { "node": ">= 16" }, @@ -5308,19 +5276,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -5393,15 +5348,16 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "dev": true, "license": "MIT", "engines": { @@ -5451,18 +5407,18 @@ } }, "node_modules/glob": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "path-scurry": "^2.0.0" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5509,9 +5465,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", "dev": true, "license": "MIT", "dependencies": { @@ -5522,12 +5478,11 @@ } }, "node_modules/hono": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.4.tgz", - "integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==", + "version": "4.12.14", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz", + "integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } @@ -5546,9 +5501,9 @@ } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -5569,9 +5524,9 @@ } }, "node_modules/htmlparser2": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", - "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -5584,14 +5539,14 @@ "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", - "domutils": "^3.2.1", - "entities": "^6.0.0" + "domutils": "^3.2.2", + "entities": "^7.0.1" } }, "node_modules/htmlparser2/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -5688,22 +5643,12 @@ } }, "node_modules/immutable": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", - "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", "dev": true, "license": "MIT" }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -5741,22 +5686,6 @@ "node": ">= 0.10" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5873,9 +5802,9 @@ } }, "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz", + "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==", "dev": true, "license": "MIT", "funding": { @@ -6051,14 +5980,15 @@ } }, "node_modules/lmdb": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.4.4.tgz", - "integrity": "sha512-+Y2DqovevLkb6DrSQ6SXTYLEd6kvlRbhsxzgJrk7BUfOVA/mt21ak6pFDZDKxiAczHMWxrb02kXBTSTIA0O94A==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.1.tgz", + "integrity": "sha512-NYHA0MRPjvNX+vSw8Xxg6FLKxzAG+e7Pt8RqAQA/EehzHVXq9SxDqJIN3JL1hK0dweb884y8kIh6rkWvPyg9Wg==", "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, "dependencies": { + "@harperfast/extended-iterable": "^1.0.3", "msgpackr": "^1.11.2", "node-addon-api": "^6.1.0", "node-gyp-build-optional-packages": "5.2.2", @@ -6069,25 +5999,13 @@ "download-lmdb-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "3.4.4", - "@lmdb/lmdb-darwin-x64": "3.4.4", - "@lmdb/lmdb-linux-arm": "3.4.4", - "@lmdb/lmdb-linux-arm64": "3.4.4", - "@lmdb/lmdb-linux-x64": "3.4.4", - "@lmdb/lmdb-win32-arm64": "3.4.4", - "@lmdb/lmdb-win32-x64": "3.4.4" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" + "@lmdb/lmdb-darwin-arm64": "3.5.1", + "@lmdb/lmdb-darwin-x64": "3.5.1", + "@lmdb/lmdb-linux-arm": "3.5.1", + "@lmdb/lmdb-linux-arm64": "3.5.1", + "@lmdb/lmdb-linux-x64": "3.5.1", + "@lmdb/lmdb-win32-arm64": "3.5.1", + "@lmdb/lmdb-win32-x64": "3.5.1" } }, "node_modules/log-symbols": { @@ -6127,6 +6045,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, "node_modules/log-update/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -6184,13 +6119,15 @@ } }, "node_modules/make-fetch-happen": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.3.tgz", - "integrity": "sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==", + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.5.tgz", + "integrity": "sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==", "dev": true, "license": "ISC", "dependencies": { + "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", + "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", @@ -6199,7 +6136,6 @@ "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", - "promise-retry": "^2.0.1", "ssri": "^13.0.0" }, "engines": { @@ -6217,9 +6153,9 @@ } }, "node_modules/mdn-data": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "dev": true, "license": "CC0-1.0" }, @@ -6287,27 +6223,27 @@ } }, "node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -6326,29 +6262,29 @@ } }, "node_modules/minipass-fetch": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.0.tgz", - "integrity": "sha512-fiCdUALipqgPWrOVTz9fw0XhcazULXOSU6ie40DDbX1F49p1dBrSRBuswndTx1x3vEb/g0FT7vC4c4C2u/mh3A==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.2.tgz", + "integrity": "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==", "dev": true, "license": "MIT", "dependencies": { "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", + "minipass-sized": "^2.0.0", "minizlib": "^3.0.1" }, "engines": { "node": "^20.17.0 || >=22.9.0" }, "optionalDependencies": { - "encoding": "^0.1.13" + "iconv-lite": "^0.7.2" } }, "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { "minipass": "^3.0.0" }, @@ -6410,38 +6346,18 @@ "license": "ISC" }, "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz", + "integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "minipass": "^7.1.2" }, "engines": { "node": ">=8" } }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/minizlib": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", @@ -6473,9 +6389,9 @@ "license": "MIT" }, "node_modules/msgpackr": { - "version": "1.11.8", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.8.tgz", - "integrity": "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==", + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.10.tgz", + "integrity": "sha512-iCZNq+HszvF+fC3anCm4nBmWEnbeIAfpDs6IStAEKhQ2YSgkjzVG2FF9XJqwwQh5bH3N9OUTUt4QwVN6MLMLtA==", "dev": true, "license": "MIT", "optional": true, @@ -6554,21 +6470,21 @@ "optional": true }, "node_modules/node-gyp": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.1.0.tgz", - "integrity": "sha512-W+RYA8jBnhSr2vrTtlPYPc1K+CSjGpVDRZxcqJcERZ8ND3A1ThWPHRwctTx3qC3oW99jt726jhdz3Y6ky87J4g==", + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz", + "integrity": "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==", "dev": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^15.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", - "tar": "^7.5.2", + "tar": "^7.5.4", "tinyglobby": "^0.2.12", + "undici": "^6.25.0", "which": "^6.0.0" }, "bin": { @@ -6595,23 +6511,33 @@ } }, "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=20" + } + }, + "node_modules/node-gyp/node_modules/undici": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz", + "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" } }, "node_modules/node-gyp/node_modules/which": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", - "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", "dev": true, "license": "ISC", "dependencies": { - "isexe": "^3.1.1" + "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" @@ -6621,9 +6547,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "version": "2.0.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", + "integrity": "sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==", "dev": true, "license": "MIT" }, @@ -6696,9 +6622,9 @@ } }, "node_modules/npm-packlist": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.3.tgz", - "integrity": "sha512-zPukTwJMOu5X5uvm0fztwS5Zxyvmk38H/LfidkOMt3gbZVCyro2cD/ETzwzVPcWZA3JOyPznfUN/nkyFiyUbxg==", + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.4.tgz", + "integrity": "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==", "dev": true, "license": "ISC", "dependencies": { @@ -6832,9 +6758,9 @@ } }, "node_modules/ora": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-9.0.0.tgz", - "integrity": "sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz", + "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==", "dev": true, "license": "MIT", "dependencies": { @@ -6844,9 +6770,8 @@ "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", - "stdin-discarder": "^0.2.2", - "string-width": "^8.1.0", - "strip-ansi": "^7.1.2" + "stdin-discarder": "^0.3.1", + "string-width": "^8.1.0" }, "engines": { "node": ">=20" @@ -6863,33 +6788,6 @@ "license": "MIT", "optional": true }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/p-map": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", @@ -6903,19 +6801,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/pacote": { - "version": "21.0.4", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.4.tgz", - "integrity": "sha512-RplP/pDW0NNNDh3pnaoIWYPvNenS7UqMbXyvMqJczosiFWTeGGwJC2NQBLqKf4rGLFfwCOnntw1aEp9Jiqm1MA==", + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.3.1.tgz", + "integrity": "sha512-O0EDXi85LF4AzdjG74GUwEArhdvawi/YOHcsW6IijKNj7wm8IvEWNF5GnfuxNpQ/ZpO3L37+v8hqdVh8GgWYhg==", "dev": true, "license": "ISC", "dependencies": { @@ -6945,13 +6834,13 @@ } }, "node_modules/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", "dev": true, "license": "MIT", "dependencies": { - "entities": "^6.0.0" + "entities": "^8.0.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -6999,13 +6888,13 @@ } }, "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "dev": true, "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -7021,15 +6910,6 @@ "node": ">= 0.8" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -7040,17 +6920,10 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, "node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -7058,16 +6931,16 @@ "minipass": "^7.1.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -7075,9 +6948,9 @@ } }, "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", "dev": true, "license": "MIT", "funding": { @@ -7100,9 +6973,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -7135,19 +7008,10 @@ "node": ">=16.20.0" } }, - "node_modules/pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "dev": true, "funding": [ { @@ -7180,6 +7044,33 @@ "dev": true, "license": "MIT" }, + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, "node_modules/proc-log": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", @@ -7228,129 +7119,10 @@ "node": ">=6" } }, - "node_modules/qrcode": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", - "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", - "license": "MIT", - "dependencies": { - "dijkstrajs": "^1.0.1", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/qrcode/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/qrcode/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/qrcode/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "license": "ISC" - }, - "node_modules/qrcode/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/qrcode/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -7410,15 +7182,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -7429,33 +7192,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "license": "ISC" - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -7491,14 +7227,14 @@ "license": "MIT" }, "node_modules/rolldown": { - "version": "1.0.0-beta.58", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.58.tgz", - "integrity": "sha512-v1FCjMZCan7f+xGAHBi+mqiE4MlH7I+SXEHSQSJoMOGNNB2UYtvMiejsq9YuUOiZjNeUeV/a21nSFbrUR+4ZCQ==", + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.4.tgz", + "integrity": "sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.106.0", - "@rolldown/pluginutils": "1.0.0-beta.58" + "@oxc-project/types": "=0.113.0", + "@rolldown/pluginutils": "1.0.0-rc.4" }, "bin": { "rolldown": "bin/cli.mjs" @@ -7507,25 +7243,25 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-beta.58", - "@rolldown/binding-darwin-arm64": "1.0.0-beta.58", - "@rolldown/binding-darwin-x64": "1.0.0-beta.58", - "@rolldown/binding-freebsd-x64": "1.0.0-beta.58", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.58", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.58", - "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.58", - "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.58", - "@rolldown/binding-linux-x64-musl": "1.0.0-beta.58", - "@rolldown/binding-openharmony-arm64": "1.0.0-beta.58", - "@rolldown/binding-wasm32-wasi": "1.0.0-beta.58", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.58", - "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.58" + "@rolldown/binding-android-arm64": "1.0.0-rc.4", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.4", + "@rolldown/binding-darwin-x64": "1.0.0-rc.4", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.4", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.4", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.4", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.4", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.4", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.4", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.4", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.4", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.4", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.4" } }, "node_modules/rollup": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", - "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", + "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7539,31 +7275,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.1", - "@rollup/rollup-android-arm64": "4.55.1", - "@rollup/rollup-darwin-arm64": "4.55.1", - "@rollup/rollup-darwin-x64": "4.55.1", - "@rollup/rollup-freebsd-arm64": "4.55.1", - "@rollup/rollup-freebsd-x64": "4.55.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", - "@rollup/rollup-linux-arm-musleabihf": "4.55.1", - "@rollup/rollup-linux-arm64-gnu": "4.55.1", - "@rollup/rollup-linux-arm64-musl": "4.55.1", - "@rollup/rollup-linux-loong64-gnu": "4.55.1", - "@rollup/rollup-linux-loong64-musl": "4.55.1", - "@rollup/rollup-linux-ppc64-gnu": "4.55.1", - "@rollup/rollup-linux-ppc64-musl": "4.55.1", - "@rollup/rollup-linux-riscv64-gnu": "4.55.1", - "@rollup/rollup-linux-riscv64-musl": "4.55.1", - "@rollup/rollup-linux-s390x-gnu": "4.55.1", - "@rollup/rollup-linux-x64-gnu": "4.55.1", - "@rollup/rollup-linux-x64-musl": "4.55.1", - "@rollup/rollup-openbsd-x64": "4.55.1", - "@rollup/rollup-openharmony-arm64": "4.55.1", - "@rollup/rollup-win32-arm64-msvc": "4.55.1", - "@rollup/rollup-win32-ia32-msvc": "4.55.1", - "@rollup/rollup-win32-x64-gnu": "4.55.1", - "@rollup/rollup-win32-x64-msvc": "4.55.1", + "@rollup/rollup-android-arm-eabi": "4.60.2", + "@rollup/rollup-android-arm64": "4.60.2", + "@rollup/rollup-darwin-arm64": "4.60.2", + "@rollup/rollup-darwin-x64": "4.60.2", + "@rollup/rollup-freebsd-arm64": "4.60.2", + "@rollup/rollup-freebsd-x64": "4.60.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", + "@rollup/rollup-linux-arm-musleabihf": "4.60.2", + "@rollup/rollup-linux-arm64-gnu": "4.60.2", + "@rollup/rollup-linux-arm64-musl": "4.60.2", + "@rollup/rollup-linux-loong64-gnu": "4.60.2", + "@rollup/rollup-linux-loong64-musl": "4.60.2", + "@rollup/rollup-linux-ppc64-gnu": "4.60.2", + "@rollup/rollup-linux-ppc64-musl": "4.60.2", + "@rollup/rollup-linux-riscv64-gnu": "4.60.2", + "@rollup/rollup-linux-riscv64-musl": "4.60.2", + "@rollup/rollup-linux-s390x-gnu": "4.60.2", + "@rollup/rollup-linux-x64-gnu": "4.60.2", + "@rollup/rollup-linux-x64-musl": "4.60.2", + "@rollup/rollup-openbsd-x64": "4.60.2", + "@rollup/rollup-openharmony-arm64": "4.60.2", + "@rollup/rollup-win32-arm64-msvc": "4.60.2", + "@rollup/rollup-win32-ia32-msvc": "4.60.2", + "@rollup/rollup-win32-x64-gnu": "4.60.2", + "@rollup/rollup-win32-x64-msvc": "4.60.2", "fsevents": "~2.3.2" } }, @@ -7601,9 +7337,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.97.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.1.tgz", - "integrity": "sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==", + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", "dev": true, "license": "MIT", "dependencies": { @@ -7665,9 +7401,9 @@ } }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -7724,12 +7460,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -7781,14 +7511,14 @@ } }, "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==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -7875,17 +7605,17 @@ } }, "node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" @@ -7973,17 +7703,6 @@ "node": ">=0.10.0" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -7992,9 +7711,9 @@ "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8003,16 +7722,16 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, "node_modules/ssri": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.0.tgz", - "integrity": "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz", + "integrity": "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==", "dev": true, "license": "ISC", "dependencies": { @@ -8040,16 +7759,16 @@ } }, "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, "license": "MIT" }, "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.2.tgz", + "integrity": "sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A==", "dev": true, "license": "MIT", "engines": { @@ -8060,14 +7779,14 @@ } }, "node_modules/string-width": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", - "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", + "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", "dev": true, "license": "MIT", "dependencies": { - "get-east-asian-width": "^1.3.0", - "strip-ansi": "^7.1.0" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { "node": ">=20" @@ -8077,13 +7796,13 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -8092,19 +7811,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -8113,9 +7819,9 @@ "license": "MIT" }, "node_modules/tar": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.3.tgz", - "integrity": "sha512-ENg5JUHUm2rDD7IvKNFGzyElLXNjachNLp6RaGf4+JOgxXHkqA+gq81ZAMCUmtMtqBsoU62lcp6S27g1LCYGGQ==", + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", + "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -8147,9 +7853,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", "dev": true, "license": "MIT", "engines": { @@ -8174,9 +7880,9 @@ } }, "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", "engines": { @@ -8184,22 +7890,22 @@ } }, "node_modules/tldts": { - "version": "7.0.19", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz", - "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==", + "version": "7.0.28", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.28.tgz", + "integrity": "sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.19" + "tldts-core": "^7.0.28" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.19", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz", - "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==", + "version": "7.0.28", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.28.tgz", + "integrity": "sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==", "dev": true, "license": "MIT" }, @@ -8214,9 +7920,9 @@ } }, "node_modules/tough-cookie": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8290,41 +7996,15 @@ } }, "node_modules/undici": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.18.0.tgz", - "integrity": "sha512-CfPufgPFHCYu0W4h1NiKW9+tNJ39o3kWm7Cm29ET1enSJx+AERfz7A2wAr26aY0SZbYzZlTBQtcHy15o60VZfQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", + "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", "dev": true, "license": "MIT", "engines": { "node": ">=20.18.1" } }, - "node_modules/unique-filename": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz", - "integrity": "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/unique-slug": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-6.0.0.tgz", - "integrity": "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -8366,17 +8046,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "node_modules/validate-npm-package-name": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", @@ -8398,9 +8067,9 @@ } }, "node_modules/vite": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", - "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, "license": "MIT", "dependencies": { @@ -8473,31 +8142,31 @@ } }, "node_modules/vitest": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.17.tgz", - "integrity": "sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", + "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.0.17", - "@vitest/mocker": "4.0.17", - "@vitest/pretty-format": "4.0.17", - "@vitest/runner": "4.0.17", - "@vitest/snapshot": "4.0.17", - "@vitest/spy": "4.0.17", - "@vitest/utils": "4.0.17", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", + "@vitest/expect": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", - "std-env": "^3.10.0", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { @@ -8513,12 +8182,15 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.17", - "@vitest/browser-preview": "4.0.17", - "@vitest/browser-webdriverio": "4.0.17", - "@vitest/ui": "4.0.17", + "@vitest/browser-playwright": "4.1.5", + "@vitest/browser-preview": "4.1.5", + "@vitest/browser-webdriverio": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/ui": "4.1.5", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -8539,6 +8211,12 @@ "@vitest/browser-webdriverio": { "optional": true }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, "@vitest/ui": { "optional": true }, @@ -8547,6 +8225,9 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, @@ -8564,9 +8245,9 @@ } }, "node_modules/watchpack": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.0.tgz", - "integrity": "sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "license": "MIT", "dependencies": { @@ -8635,12 +8316,6 @@ "node": ">= 8" } }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "license": "ISC" - }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -8662,6 +8337,7 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -8676,6 +8352,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8685,6 +8362,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -8700,12 +8378,14 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8715,6 +8395,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -8729,6 +8410,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -8745,9 +8427,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "dev": true, "license": "MIT", "engines": { @@ -8873,9 +8555,9 @@ } }, "node_modules/zod": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", - "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", "funding": { @@ -8883,13 +8565,13 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", "dev": true, "license": "ISC", "peerDependencies": { - "zod": "^3.25 || ^4" + "zod": "^3.25.28 || ^4" } } } diff --git a/package.json b/package.json index cb816f6..e0982c7 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "fast-check", + "name": "qr-vitanova", "version": "0.0.0", "scripts": { "ng": "ng", @@ -29,7 +29,6 @@ "@angular/forms": "^21.0.0", "@angular/platform-browser": "^21.0.0", "@angular/router": "^21.0.0", - "angularx-qrcode": "^21.0.4", "rxjs": "~7.8.0", "tslib": "^2.3.0" }, @@ -41,4 +40,4 @@ "typescript": "~5.9.2", "vitest": "^4.0.8" } -} +} \ No newline at end of file diff --git a/payment.html b/payment.html new file mode 100644 index 0000000..184d9bb --- /dev/null +++ b/payment.html @@ -0,0 +1,291 @@ + + + + + Оплата через СБП + + + + + + + +
+
+ +
+ +

Оплата через СБП

+

Система быстрых платежей

+
+ +
+ +
+ +
+ + +
+ +
+ +
+ 🇷🇺 + RUB + Российский рубль +
+ +
+ + +
+ + + +
+ + + +
+
+ + + + + diff --git a/proxy.conf.json b/proxy.conf.json new file mode 100644 index 0000000..83d7baa --- /dev/null +++ b/proxy.conf.json @@ -0,0 +1,23 @@ +{ + "/proxy/legacy-qr": { + "target": "https://qr.vitanova.network:567", + "secure": false, + "changeOrigin": true, + "pathRewrite": { "^/proxy/legacy-qr": "" }, + "logLevel": "debug" + }, + "/proxy/fastcheck": { + "target": "https://api.fastcheck.store", + "secure": true, + "changeOrigin": true, + "pathRewrite": { "^/proxy/fastcheck": "" }, + "logLevel": "debug" + }, + "/proxy/qr-vitanova": { + "target": "https://qr.vitanova.network", + "secure": true, + "changeOrigin": true, + "pathRewrite": { "^/proxy/qr-vitanova": "" }, + "logLevel": "debug" + } +} diff --git a/public/Fastcheck_API (1).txt b/public/Fastcheck_API (1).txt new file mode 100644 index 0000000..ee210a8 --- /dev/null +++ b/public/Fastcheck_API (1).txt @@ -0,0 +1,142 @@ +eFastcheck.store +General Information +Information exchange with the Fastcheck server is realized via RESTful API. All requests to the server must be executed via HTTPS using GET||POST||PUT||DELETE requests to the given ROOT address. Body of requests must be in JSON format. All not public requests must be signed by the client and the public key must be sent to the server for client identification and sign checking. + + + + +Check if server is available +Client needs to periodically check if the server is available by sending “ping” to the client. On error corresponding message must be shown. +Protocol: https +Root Path: api.Fastcheck.store +Type GET +Path /ping +Request Parameters: +{ + + +} +Response (OK): +{ +"message": "pong", +} +________________ + + +Create new websession +Creates a new websession for qr generation. By timeout a new websession must be requested, after the user shows some activity (click on qr). +Protocol: https +Root Path: api.Fastcheck.store +Type GET +Path /websession +Request Parameters: +{ + + +} +Response (OK): +{ +"sessionId": “1AF3781BF6B94604B771AEA1D44FA63A” +"userId" : "", +"expires" : "sessionId", +"userSessionId": "", +"Status": false +} +________________ + + +Check websession status +Check if the user is already logged in. a new websession for qr generation. By timeout a new websession must be requested, after the user shows some activity (click on qr). +Protocol: https +Root Path: api.Fastcheck.store +Type GET +Path /websession/:webSessionID +Request Parameters: +{ + + +} +Response (OK): +{ +"sessionId": “1AF3781BF6B94604B771AEA1D44FA63A”, +"userId" : "kHaAe9roaC2uq63AKGE/8+Ti/t/iFro68QhEZ1dRGLo", +"expires" : "sessionId", +"userSessionId": "8A94EFEFD003426A9B456C48CAC99BE6", +"Status": true +} +________________ +Delete websession status +Delete the session to log out from the system. +Protocol: https +Root Path: api.Fastcheck.store +Type DELETE +Path /websession/:webSessionID +Request Parameters: +{ +"sessionId": “1AF3781BF6B94604B771AEA1D44FA63A” +} +Response (OK): +{ +} +________________ + + +Check Fastcheck status +Check if fastcheck exists and get the amount assigned to check. +Protocol: https +Root Path: api.Fastcheck.store +Type GET +Path /fastcheck + + +Request Parameters: +{ +"fastcheck": “1234-5678-0001”, +} +Response (OK): +{ + "fastcheck": "1234-5678-0001", + "expiration": 2021-07-07T09:08:18Z , + "Status": true +} +________________ +New Fastcheck +Create a fastcheck for a given amount. The Users must have a sufficient amount on the balance. +Protocol: https +Root Path: api.Fastcheck.store +Type POST +Path /fastcheck +HEADER: Authorization - {"sessionID": "1AF3781BF6B94604B771AEA1D44FA63A"} +Request Parameters: + { + "amount": 158000, + "currency": "RUB" + } +Response (OK): +{ + "fastcheck": "1234-5678-0001", + "expiration": 2021-07-07T09:08:18Z , + "code": "5864", + "Status": true +} +________________ +Accept Fastcheck +Accept fastcheck to the user balance. +Protocol: https +Root Path: api.Fastcheck.store +Type POST +Path /fastcheck +HEADER: Authorization - {"sessionID": "1AF3781BF6B94604B771AEA1D44FA63A"} +Request Parameters: + { + "fastcheck": "1234-5678-0001", + "code": "5864" + } +Response (404-ERROR): +{ + "message": "not authorized" +} +Response (200-OK): +{ + "message": "ok" +} \ No newline at end of file diff --git a/public/SBP QR API.txt b/public/SBP QR API.txt new file mode 100644 index 0000000..157b449 --- /dev/null +++ b/public/SBP QR API.txt @@ -0,0 +1,262 @@ +General Information +Information exchange with the SBP server is realized via RESTful API. All requests to the server must be executed via HTTPS using GET||POST||PUT||DELETE requests to the given ROOT address. Body of requests must be in JSON format. All not public requests must be signed by the client and the public key must be sent to the server for client identification and sign checking. + + +Header: +“Authorization”: {JSON WITH KEY AND PARTNERID} + + +Check if server is available +Client needs to periodically check if the server is available by sending “ping” to the client. On error corresponding message must be shown. +Protocol: https +Root Path: QR.VITANOVA.NETWORK +Type GET +Path /ping +Request Parameters: +{ + + +} +Response (Error): +{ +"message": "pong", +"status": "Wrong Header" +} +Response (OK): +{ +"message": "pong", +"status": "Correct Header" +} +________________ + + +Create New QR code +Create New QR for payment via SBP +Protocol: https +Root Path: QR.VITANOVA.NETWORK +Type POST +Path /qr +Request Parameters: +{ +"amount": 10.00, //amount from 10Rub to 499.000 Rub +"qrDescription": "Item description", +"order": "540", //orderid at partner’s platform +"partnerID": 102 //same as in header +"Phonemask": 79xxxx66265 //User phone number mask, needed only for crypto based operations. Payment will be accepted only from phone numbers corresponding to the mask +"Namelastname": Hakxx Sargxxxx /Mask for User name, lastname in cyrilic, needed only for crypto based operations. Payment will be accepted only from the user corresponding to that mask. +} + + +Response !=200(Error): +{ + "error": "wrong key" +} +Response =200(OK): +{ + "qrId": "BD10002CI1V3JP1T8QR8TIQ8K35RBVQB", + "qrStatus": "NEW", + "qrExpirationDate": "2025-11-20T10:10:44Z", + "Payload": "https://qr.nspk.ru/BD10002CI1V3JP1T8QR8TIQ8K35RBVQB?type=02&bank=100000000007&sum=1000&cur=RUB&crc=8ACC", + "qrUrl": "https://e-commerce.raiffeisen.ru/api/sbp/v1/qr/BD10002CI1V3JP1T8QR8TIQ8K35RBVQB/image" +} +________________ + + +Check Dynamic QR code +Check QR status +Protocol: https +Root Path: QR.VITANOVA.NETWORK +Type GET +Path /qr/dynamic/{qrId} + + +Request Parameters: +{ +} + + +Response !=200(Error): +{ + "error": "Error from the bank " +} +Response =200(OK): +{ +`json:"nspkID"` //": "AD100060JFQF8FSB9Q28FFL88IH6SST0" `json:"amount"` // "1235" +`json:"currency" // "RUB" +`json:"order"` // "126" partner order id PaymentDetails +`json:"paymentDetails"` // "Назначение платежа 2", +`json:"qrType"` //"QRDynamic", +`json:"qrExpirationDate"` //: "2025-11-22T09:14:38+03:00" `json:"sbpBank"` // "raiffeisen" +`json:"sbpMerchant"` //"Dexar" +`json:"sbpMerchantId"` //"", uint64 +`json:"sbpOperationId"` //0 Status +`json:"status"` //": "NEW", "APPROVED", "REJECTED", "COMPLETED" +`json:"nspkurl"` //"https://qr.nspk.ru/AD100060JFQF8FSB9Q28FFL88IH6SST0 +`json:"statusurl"` // "https://partner.com/1234321/status" url for checking QR `json:"redirectUrl"` //"https://fastcheck.store/" +`json:"qrDescription"` //"QR для оплаты заказа" +`json:"additionalInfo"` // TTL +`json:"TTL"` //10 timeout in minutes +`json:"callbackUrl"` // https://partner.com/1234321 callback after QR get paid +`json:"retry"` //0 retry count for calling partner +`json:"partnerID"` //103 Partner created QR PartnerqrID `json:"partnerqrID"` //QR ID in partner system RequestIP +`json:"requestIP"` //IP address of client requested QR +} +________________ + + +Check Static QR code +Get all qr-s paid by static QR for today, skipping already read qr codes +Protocol: https +Root Path: QR.VITANOVA.NETWORK +Type GET +Path /qr/static/{qrId}?skip=25 +Request Parameters: +{ +} + + +Response =200(OK): +[{ +`json:"nspkID"` //": "AD100060JFQF8FSB9Q28FFL88IH6SST0" `json:"amount"` // "1235" +`json:"currency" // "RUB" +`json:"order"` // "126" partner order id PaymentDetails +`json:"paymentDetails"` // "Назначение платежа 2", +`json:"qrType"` //"QRDynamic", +`json:"qrExpirationDate"` //: "2025-11-22T09:14:38+03:00" `json:"sbpBank"` // "raiffeisen" +`json:"sbpMerchant"` //"Dexar" +`json:"sbpMerchantId"` //"", uint64 +`json:"sbpOperationId"` //0 Status +`json:"status"` //": "NEW", "APPROVED", "REJECTED", "COMPLETED" +`json:"nspkurl"` //"https://qr.nspk.ru/AD100060JFQF8FSB9Q28FFL88IH6SST0 +`json:"statusurl"` // "https://partner.com/1234321/status" url for checking QR `json:"redirectUrl"` //"https://fastcheck.store/" +`json:"qrDescription"` //"QR для оплаты заказа" +`json:"additionalInfo"` // TTL +`json:"TTL"` //10 timeout in minutes +`json:"callbackUrl"` // https://partner.com/1234321 callback after QR get paid +`json:"retry"` //0 retry count for calling partner +`json:"partnerID"` //103 Partner created QR PartnerqrID `json:"partnerqrID"` //QR ID in partner system RequestIP +`json:"requestIP"` //IP address of client requested QR +}] + + +________________ + + +Delete QR +Delete unused QR. If QR is not paid until expiration time, it will be automatically deleted. +Protocol: https +Root Path: QR.VITANOVA.NETWORK +Type DELETE +Path /qr/{qrId} +Request Parameters: +{ +} + + +Response !=200(Error): +{ +"error": "Error from the bank " + + +} +Response =200(OK): +{ + } +________________ +Check Partner +Returns partner status, with balance and transactions. Each transaction id is QR code, which can be checked additionally. +Root Path: API.VITANOVA.NETWORK +Type Get +Path /partners/{partnerID} +Request Parameters: +{ +} +Response !=200(Error): +{ +"error": "Not authorized " +} +Response =200(OK): +{ + "telegram_id": 8285633, + "username": "ZZZ", + "first_name": "АMAN", + "last_name": "", + "balance": 22, + "transaction": [ + { + "additionalInfo": "Ручка", + "paymentPurpose": "Ручка", + "amount": 22, + "code": "SUCCESS", + "createDate": "2025-11-22T15:57:40.925104+03:00", + "currency": "RUB", + "order": "8285633735_301", + "paymentStatus": "SUCCESS", + "qrId": "AD10004C1K9N71MN907RD56UOA0BHIBR", + "transactionDate": "2025-11-22T15:58:14.814187+03:00", + "transactionId": 771515533, + "qrExpirationDate": "2025-11-22T16:12:40+03:00" + } + ], + "inn": 0 + } + + + + + + +________________ + + +Withdraw +Get amount from balance and Creates fastcheck, which then can be for buying usdt, transferring to bank account and to bank card. Fastcheck can be checked on site or via API only by Id, but can be used only with code. +Root Path: QR.VITANOVA.NETWORK +Type POST +Path/partners/withdraw/{partnerID} +Request Parameters: +{ +“amount”: 10600.00 +“currency”: “RUB” +“partnerId: “1023454” +“wallet”: “TBia4uHnb3oSSZm5isP284cA7Np1v15Vhi” +“” +“rate”:79.50 +} + + +Response !=200(Error): +{ +"error": "Not enough amount on balance " +} +Response !=200(Error): +{ +"error": "Rate is not correct " +} +Response =200(OK): +{ + “trxID”:”T5Mv2v8n9L7jY4k1pW3QhUoZfE9R1X3s7rY6tB0pA2C4D6E8F5H” +} +________________ +RATE +Get currency exchange rate. +Root Path: QR.VITANOVA.NETWORK +Type GET +Path/partners/rate +Request Parameters: + + + + +Response !=200(Error): +{ +"error": "Not Authorized " +} + + +Response =200(OK): + + +{ + "rate": 78.5 +} \ No newline at end of file diff --git a/public/alipay.svg b/public/alipay.svg new file mode 100644 index 0000000..cd9e6d7 --- /dev/null +++ b/public/alipay.svg @@ -0,0 +1,5 @@ + + + A + diff --git a/public/example.json b/public/example.json new file mode 100644 index 0000000..e69de29 diff --git a/public/favicon.ico b/public/favicon.ico index 57614f9..897b8b4 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/flags/arm.svg b/public/flags/arm.svg new file mode 100644 index 0000000..b83d158 --- /dev/null +++ b/public/flags/arm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/flags/en.svg b/public/flags/en.svg new file mode 100644 index 0000000..b3d4b3b --- /dev/null +++ b/public/flags/en.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/flags/ru.svg b/public/flags/ru.svg new file mode 100644 index 0000000..6a66ca4 --- /dev/null +++ b/public/flags/ru.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/i18n/en.json b/public/i18n/en.json new file mode 100644 index 0000000..dc91bc0 --- /dev/null +++ b/public/i18n/en.json @@ -0,0 +1,130 @@ +{ + "header": { + "nav_about": "About", + "nav_contacts": "Contacts", + "nav_partners": "Partners", + "nav_support": "Support", + "aria_nav": "Navigation", + "aria_menu": "Mobile menu", + "aria_burger": "Menu", + "aria_close": "Close menu" + }, + "footer": { + "desc": "An innovative virtual check service for individuals. Create digital checks online and cash them out at partner bank ATMs 24/7.", + "contacts_heading": "Contacts", + "russia": "Russia", + "armenia": "Armenia", + "support_label": "Tech support", + "support_hours": "24/7", + "questions_label": "Questions", + "questions_hours": "10:00–19:00 MSK", + "legal_heading": "Legal details", + "legal_company": "LLC «VIAEXPORT»", + "legal_inn_ru": "TIN (RU): 9909675800", + "legal_inn_am": "TIN (AM): 01051049", + "legal_kpp": "KPP: 770287001", + "legal_ogrn": "OGRN: 282.110.1296681", + "legal_address": "Armenia, 0201, Yerevan, Minskaya St. 21-23, apt. 44", + "rights": "LLC «VIAEXPORT». All rights reserved.", + "director": "Director: Amirkhanyan Sargis Artashesovich" + }, + "fastcheck": { + "subtitle": "Enter fastCHECK details or create a new one", + "number_label": "fastCHECK number", + "number_placeholder": "123456-123456-123456", + "number_new": "New", + "amount_label": "Amount", + "amount_checking": "Checking…", + "code_label": "Code", + "code_placeholder": "000000", + "pay_btn": "Pay", + "modal_title": "Sign in via Telegram", + "modal_sub": "Scan QR or open the link", + "modal_loading": "Loading…", + "modal_open_tg": "Open in Telegram", + "modal_confirming": "Confirming payment…", + "modal_waiting": "Waiting for sign-in…", + "modal_paid_title": "Paid", + "modal_paid_sub": "fastCHECK successfully accepted.", + "share_email": "Send by email", + "share_tg": "Send via Telegram" + }, + "create": { + "title": "New", + "subtitle": "Enter the amount to top up", + "back_label": "Back", + "payment_label": "Payment method", + "currency_label": "Currency", + "amount_label": "Payment amount", + "note_label": "Note", + "note_placeholder": "Reason for payment...", + "creating": "Creating…", + "create_btn": "Create", + "amount_hint": "Allowed amount:", + "qr_label": "Scan QR to pay", + "qr_waiting": "Waiting for payment confirmation…" + }, + "sbp": { + "title": "Pay via SBP", + "subtitle": "Fast Payment System", + "amount_label": "Payment amount", + "currency_name": "Russian ruble", + "note_label": "Note", + "note_placeholder": "Reason for payment...", + "pay_loading": "Please wait...", + "pay_btn": "Proceed to payment" + }, + "about": { + "title": "About the service", + "lead": "fastCHECK is an innovative virtual check service for individuals, available 24/7.", + "what_title": "What is fastCHECK?", + "what_text": "fastCHECK is a digital check you create online and cash out at partner bank ATMs at any time of day. No queues, no offices — just your phone and the nearest ATM.", + "how_title": "How does it work?", + "step1": "Log in and create a new fastCHECK with the required amount.", + "step2": "Save the check number and 5-digit code.", + "step3": "Enter the details on the site and confirm via Telegram.", + "step4": "Receive the funds in a convenient way.", + "why_title": "Why fastCHECK?", + "why1": "Available 24/7 — including weekends and holidays.", + "why2": "Secure authorisation via Telegram.", + "why3": "Supports SBP and other popular payment methods.", + "why4": "Fast processing — from seconds to a few minutes.", + "company_title": "About the company", + "company_text": "The service is developed by LLC VIAEXPORT (TIN 9909675800). The company is registered in Russia and Armenia. Legal address: Armenia, 0201, Yerevan, Minskaya St. 21-23, apt. 44." + }, + "contacts": { + "title": "Contacts", + "lead": "We are available 24/7. Choose your preferred way to reach us.", + "ru_label": "Phone — Russia", + "am_label": "Phone — Armenia", + "email_label": "Email", + "tg_label": "Telegram bot", + "hours_title": "Working hours" + }, + "errors": { + "not_found": "Payment not found or expired.", + "lookup_failed": "Could not verify the number. Please try again.", + "session_failed": "Could not create a session. Please try again.", + "payment_failed": "Could not process the payment. Check the code and try again.", + "invalid_code": "Invalid code. Please check and try again.", + "invalid_amount": "Please enter a valid amount." + }, + "common": { + "secure": "Secure connection" + }, + "partners": { + "title": "Partners", + "lead": "Stores, services and companies accepting fastCHECK as a payment method.", + "cat_finance": "Finance", + "cat_retail": "Retail", + "cat_hotels": "Hotels", + "cat_services": "Services", + "p1_desc": "Currency exchange and transfers across Armenia.", + "p2_desc": "Forex broker supporting fastCHECK for account top-ups.", + "p3_desc": "Online retailer with delivery across Russia and CIS.", + "p4_desc": "Hotel booking and payment via fastCHECK.", + "cta_title": "Want to become a partner?", + "cta_text": "Connect fastCHECK to your business — fast, with minimal paperwork.", + "cta_btn": "Contact us" + } +} diff --git a/public/i18n/hy.json b/public/i18n/hy.json new file mode 100644 index 0000000..b1596a3 --- /dev/null +++ b/public/i18n/hy.json @@ -0,0 +1,130 @@ +{ + "header": { + "nav_about": "Ծառայության մասին", + "nav_contacts": "Կապ", + "nav_partners": "Գործընկերներ", + "nav_support": "Աջակցություն", + "aria_nav": "Նավիգացիա", + "aria_menu": "Բջջային ընտրացանկ", + "aria_burger": "Ընտրացանկ", + "aria_close": "Փակել ընտրացանկը" + }, + "footer": { + "desc": "Ֆիզիկական անձանց համար վիրտուալ չեկերի նորարարական ծառայություն: Ստեղծեք թվային չեկեր առցանց և կանխիկացրեք դրանք գործընկեր բանկերի բանկոմատներում 24/7:", + "contacts_heading": "Կապ", + "russia": "Ռուսաստան", + "armenia": "Հայաստան", + "support_label": "Տեխ. աջակցություն", + "support_hours": "24/7", + "questions_label": "Հարցեր", + "questions_hours": "10:00–19:00 MSK", + "legal_heading": "Իրավաբանական տվյալներ", + "legal_company": "ООО «ВИАЭКСПОРТ»", + "legal_inn_ru": "ИНН (РФ): 9909675800", + "legal_inn_am": "ИНН (AM): 01051049", + "legal_kpp": "КПП: 770287001", + "legal_ogrn": "ОГРН: 282.110.1296681", + "legal_address": "Հայաստան, 0201, Երևան, Մինսկայա փ. 21-23, բն. 44", + "rights": "ООО «ВИАЭКСПОРТ»: Բոլոր իրավունքները պաշտպանված են:", + "director": "Տնօրեն՝ Ամիրխանյան Սարգիս Արտաշեսի" + }, + "fastcheck": { + "subtitle": "Մուտքագրեք fastCHECK տվյալները կամ ստեղծեք նորը", + "number_label": "fastCHECK համար", + "number_placeholder": "123456-123456-123456", + "number_new": "Նոր", + "amount_label": "Գումար", + "amount_checking": "Ստուգվում է…", + "code_label": "Կոդ", + "code_placeholder": "000000", + "pay_btn": "Վճարել", + "modal_title": "Մուտք գործել Telegram-ով", + "modal_sub": "Սկանավորեք QR կամ բացեք հղումը", + "modal_loading": "Բեռնվում է…", + "modal_open_tg": "Բացել Telegram-ում", + "modal_confirming": "Վճարման հաստատում…", + "modal_waiting": "Սպասում ենք մուտքի…", + "modal_paid_title": "Վճարված է", + "modal_paid_sub": "fastCHECK-ը հաջողությամբ ընդունված է:", + "share_email": "Ուղարկել էլ. նամակով", + "share_tg": "Ուղարկել Telegram-ով" + }, + "create": { + "title": "Նոր", + "subtitle": "Նշեք համալրման գումարը", + "back_label": "Հետ", + "payment_label": "Վճարման եղանակ", + "currency_label": "Արժույթ", + "amount_label": "Վճարման գումար", + "note_label": "Նշում", + "note_placeholder": "Վճարման պատճառ...", + "creating": "Ստեղծվում է…", + "create_btn": "Ստեղծել", + "amount_hint": "Թույլատրելի գումար՝", + "qr_label": "Սկանավորեք QR-կոդը վճարելու համար", + "qr_waiting": "Սպասում ենք վճարման հաստատման…" + }, + "sbp": { + "title": "Վճարել SBP-ով", + "subtitle": "Արագ վճարումների համակարգ", + "amount_label": "Վճարման գումար", + "currency_name": "Ռուսական ռուբլի", + "note_label": "Նշում", + "note_placeholder": "Վճարման պատճառ...", + "pay_loading": "Սպասեք...", + "pay_btn": "Անցնել վճարմանը" + }, + "about": { + "title": "Ծառայության մասին", + "lead": "fastCHECK-ը ֆիզիկական անձանց համար վիրտուալ չեկերի նորարարական ծառայություն է, հասանելի 24/7:", + "what_title": "Ի՞նչ է fastCHECK-ը", + "what_text": "fastCHECK-ը թվային չեկ է, որը ստեղծում եք առցանց և կանխիկացնում գործընկեր բանկերի բանկոմատներում: Հերթեր չկան, գրասենյակներ չկան — միայն հեռախոս և ամենամոտ բանկոմատ:", + "how_title": "Ինչպե՞ս է դա աշխատում", + "step1": "Մուտք գործեք և ստեղծեք նոր fastCHECK անհրաժեշտ գումարով:", + "step2": "Պահպանեք չեկի համարն ու 5-նիշ կոդը:", + "step3": "Մուտքագրեք տվյալները կայքում և հաստատեք Telegram-ի միջոցով:", + "step4": "Ստացեք գումարն ձեզ հարմար ձևով:", + "why_title": "Ինչու՞ fastCHECK", + "why1": "Հասանելի 24/7 — ներառյալ հանգստյան և տոն օրերը:", + "why2": "Անվտանգ թույլտվություն Telegram-ի միջոցով:", + "why3": "Աջակցում է ՍԲՊ-ին և այլ հայտնի վճարման եղանակներ:", + "why4": "Արագ մշակում — վայրկյաններից մինչև մի քանի րոպե:", + "company_title": "Ընկերության մասին", + "company_text": "Ծառայությունը մշակվել է ООО «ВИАЭКСПОРТ»-ի կողմից (ИНН 9909675800): Ընկերությունը գրանցված է Ռուսաստանում և Հայաստանում: Իրավաբանական հասցե՝ Հայաստան, 0201, Երևան, Մինսկայա փ. 21-23, բն. 44:" + }, + "contacts": { + "title": "Կապ", + "lead": "Մենք կապի մեջ ենք 24/7: Ընտրեք կապի հարմար եղանակ:", + "ru_label": "Հեռախոս — Ռուսաստան", + "am_label": "Հեռախոս — Հայաստան", + "email_label": "Էլ. փոստ", + "tg_label": "Telegram-բոտ", + "hours_title": "Աշխատանքային ժամեր" + }, + "errors": { + "not_found": "Վճարումը չի գտնվել կամ ժամկետն անցել է:", + "lookup_failed": "Չհաջողվեց ստուգել համարը: Կրկին փորձեք:", + "session_failed": "Չհաջողվեց ստեղծել նիստ: Կրկին փորձեք:", + "payment_failed": "Չհաջողվեց մշակել վճարումը: Ստուգեք կոդը և կրկին փորձեք:", + "invalid_code": "Սխալ կոդ: Ստուգեք և կրկին մուտքագրեք:", + "invalid_amount": "Մուտքագրեք ճիշտ գումար:" + }, + "common": { + "secure": "Անվտանգ կապ" + }, + "partners": { + "title": "Գործընկերներ", + "lead": "Խանութներ, ծառայություններ և ընկերություններ, որոնք ընդունում են fastCHECK-ը:", + "cat_finance": "Ֆինանսներ", + "cat_retail": "Ռիթեյլ", + "cat_hotels": "Հյուրանոցներ", + "cat_services": "Ծառայություններ", + "p1_desc": "Արժույթի փոխանակում և փոխանցումներ ամբողջ Հայաստանում:", + "p2_desc": "Ֆորեքս բրոքեր fastCHECK-ով հաշիվ համալրման համար:", + "p3_desc": "Առցանց ռիթեյլ՝ Ռուսաստանով և ԱՊՀ-ով առաքմամբ:", + "p4_desc": "Հյուրանոցի ամրագրում և վճարում fastCHECK-ի միջոցով:", + "cta_title": "Ցանկանու՞մ եք դառնալ գործընկեր", + "cta_text": "Միացրեք fastCHECK-ը ձեր բիզնեսին — արագ, նվազ փաստաթղթերով:", + "cta_btn": "Կապվեք մեզ հետ" + } +} diff --git a/public/i18n/ru.json b/public/i18n/ru.json new file mode 100644 index 0000000..d4a025b --- /dev/null +++ b/public/i18n/ru.json @@ -0,0 +1,130 @@ +{ + "header": { + "nav_about": "О сервисе", + "nav_contacts": "Контакты", + "nav_partners": "Партнёры", + "nav_support": "Поддержка", + "aria_nav": "Навигация", + "aria_menu": "Мобильное меню", + "aria_burger": "Меню", + "aria_close": "Закрыть меню" + }, + "footer": { + "desc": "Инновационный сервис виртуальных чеков для физических лиц. Создавайте цифровые чеки онлайн и обналичивайте их через банкоматы банков-партнёров 24/7.", + "contacts_heading": "Контакты", + "russia": "Россия", + "armenia": "Армения", + "support_label": "Техподдержка", + "support_hours": "24/7", + "questions_label": "Вопросы", + "questions_hours": "10:00–19:00 МСК", + "legal_heading": "Реквизиты", + "legal_company": "ООО «ВИАЭКСПОРТ»", + "legal_inn_ru": "ИНН (РФ): 9909675800", + "legal_inn_am": "ИНН (AM): 01051049", + "legal_kpp": "КПП: 770287001", + "legal_ogrn": "ОГРН: 282.110.1296681", + "legal_address": "Армения, 0201, Ереван, ул. Минская, дом 21-23, кв. 44", + "rights": "ООО «ВИАЭКСПОРТ». Все права защищены.", + "director": "Директор: Амирханян Саргис Арташесович" + }, + "fastcheck": { + "subtitle": "Введите данные fastCHECK или создайте новый", + "number_label": "Номер fastCHECK", + "number_placeholder": "123456-123456-123456", + "number_new": "Новый", + "amount_label": "Сумма", + "amount_checking": "Проверяем…", + "code_label": "Код", + "code_placeholder": "000000", + "pay_btn": "Оплатить", + "modal_title": "Войти через Telegram", + "modal_sub": "Отсканируйте QR или откройте ссылку", + "modal_loading": "Загрузка…", + "modal_open_tg": "Открыть в Telegram", + "modal_confirming": "Подтверждение оплаты…", + "modal_waiting": "Ожидание входа…", + "modal_paid_title": "Оплачено", + "modal_paid_sub": "fastCHECK успешно принят.", + "share_email": "Отправить на почту", + "share_tg": "Отправить в Telegram" + }, + "create": { + "title": "Новый", + "subtitle": "Укажите сумму для пополнения", + "back_label": "Назад", + "payment_label": "Способ оплаты", + "currency_label": "Валюта", + "amount_label": "Сумма платежа", + "note_label": "Примечание", + "note_placeholder": "Причина платежа...", + "creating": "Создание…", + "create_btn": "Создать", + "amount_hint": "Допустимая сумма:", + "qr_label": "Отсканируйте QR для оплаты", + "qr_waiting": "Ожидаем подтверждения оплаты…" + }, + "sbp": { + "title": "Оплата через СБП", + "subtitle": "Система быстрых платежей", + "amount_label": "Сумма платежа", + "currency_name": "Российский рубль", + "note_label": "Примечание", + "note_placeholder": "Причина платежа...", + "pay_loading": "Подождите...", + "pay_btn": "Перейти к оплате" + }, + "about": { + "title": "О сервисе", + "lead": "fastCHECK — инновационный сервис виртуальных чеков для физических лиц, доступный 24/7.", + "what_title": "Что такое fastCHECK?", + "what_text": "fastCHECK — это цифровой чек, который вы создаёте онлайн и обналичиваете через банкоматы банков-партнёров в любое время суток. Никакой очереди, никаких офисов — только телефон и ближайший банкомат.", + "how_title": "Как это работает?", + "step1": "Зайдите в личный кабинет и создайте новый fastCHECK с нужной суммой.", + "step2": "Запомните или сохраните номер чека и 5-значный код.", + "step3": "Введите данные на сайте и подтвердите операцию через Telegram.", + "step4": "Получите средства удобным вам способом.", + "why_title": "Почему fastCHECK?", + "why1": "Работает 24/7 — включая выходные и праздники.", + "why2": "Безопасная авторизация через Telegram.", + "why3": "Поддержка СБП и других популярных методов оплаты.", + "why4": "Быстрое обслуживание — от секунд до нескольких минут.", + "company_title": "О компании", + "company_text": "Сервис разработан ООО «ВИАЭКСПОРТ» (ИНН 9909675800). Компания зарегистрирована в России и Армении, юридический адрес: Армения, 0201, Ереван, ул. Минская, дом 21-23, кв. 44." + }, + "contacts": { + "title": "Контакты", + "lead": "Мы на связи 24/7. Выберите удобный способ связи.", + "ru_label": "Телефон — Россия", + "am_label": "Телефон — Армения", + "email_label": "Электронная почта", + "tg_label": "Telegram-бот", + "hours_title": "Часы работы" + }, + "errors": { + "not_found": "Платёж не найден или просрочен.", + "lookup_failed": "Не удалось проверить номер. Попробуйте ещё раз.", + "session_failed": "Не удалось создать сессию. Попробуйте ещё раз.", + "payment_failed": "Не удалось принять платёж. Проверьте код и попробуйте снова.", + "invalid_code": "Неверный код. Проверьте и введите снова.", + "invalid_amount": "Введите корректную сумму." + }, + "common": { + "secure": "Защищённое соединение" + }, + "partners": { + "title": "Партнёры", + "lead": "Магазины, сервисы и компании, принимающие fastCHECK как способ оплаты.", + "cat_finance": "Финансы", + "cat_retail": "Ритейл", + "cat_hotels": "Отели", + "cat_services": "Услуги", + "p1_desc": "Обмен валют и переводы по всей Армении.", + "p2_desc": "Форекс-брокер с поддержкой fastCHECK для пополнения счёта.", + "p3_desc": "Онлайн-ритейлер с доставкой по России и СНГ.", + "p4_desc": "Бронирование и оплата проживания через fastCHECK.", + "cta_title": "Хотите стать партнёром?", + "cta_text": "Подключите fastCHECK к своему бизнесу — быстро, без лишних документов.", + "cta_btn": "Связаться с нами" + } +} diff --git a/public/logo_big.png b/public/logo_big.png new file mode 100644 index 0000000..1bec9be Binary files /dev/null and b/public/logo_big.png differ diff --git a/public/logo_small.png b/public/logo_small.png new file mode 100644 index 0000000..818a2da Binary files /dev/null and b/public/logo_small.png differ diff --git a/public/mastercard.svg b/public/mastercard.svg new file mode 100644 index 0000000..23ce110 --- /dev/null +++ b/public/mastercard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/missing-apis.txt b/public/missing-apis.txt deleted file mode 100644 index d320c48..0000000 --- a/public/missing-apis.txt +++ /dev/null @@ -1,124 +0,0 @@ -MISSING APIs - TO BE IMPLEMENTED BY BACKEND -============================================== - -Get User Balance ----------------- -Get the current balance of the authenticated user. -Protocol: https -Root Path: api.Fastcheck.store -Type: GET -Path: /balance -HEADER: Authorization - {"sessionID": "1AF3781BF6B94604B771AEA1D44FA63A"} -Request Parameters: -{ -} -Response (200-OK): -{ - "balance": 150000, - "currency": "RUB" -} -Response (401-ERROR): -{ - "message": "not authorized" -} - - -Get Active FastChecks ---------------------- -Get all active (unused) FastChecks created by the current user. -Protocol: https -Root Path: api.Fastcheck.store -Type: GET -Path: /fastcheck/active -HEADER: Authorization - {"sessionID": "1AF3781BF6B94604B771AEA1D44FA63A"} -Request Parameters: -{ -} -Response (200-OK): -{ - "checks": [ - { - "fastcheck": "1234-5678-0001", - "amount": 15000, - "currency": "RUB", - "code": "5864", - "createdAt": "2026-01-19T09:08:18Z", - "expiration": "2026-01-26T09:08:18Z", - "status": "active" - }, - { - "fastcheck": "1234-5678-0002", - "amount": 25000, - "currency": "RUB", - "code": "1234", - "createdAt": "2026-01-19T10:15:30Z", - "expiration": "2026-01-26T10:15:30Z", - "status": "active" - } - ] -} -Response (401-ERROR): -{ - "message": "not authorized" -} - - -Get FastCheck History ---------------------- -Get all used/expired FastChecks (both created and accepted by user). -Protocol: https -Root Path: api.Fastcheck.store -Type: GET -Path: /fastcheck/history -HEADER: Authorization - {"sessionID": "1AF3781BF6B94604B771AEA1D44FA63A"} -Request Parameters: -{ -} -Response (200-OK): -{ - "checks": [ - { - "fastcheck": "1234-5678-0003", - "amount": 5000, - "currency": "RUB", - "type": "created", - "createdAt": "2026-01-15T09:08:18Z", - "usedAt": "2026-01-15T10:20:00Z", - "status": "used" - }, - { - "fastcheck": "9876-5432-0100", - "amount": 10000, - "currency": "RUB", - "type": "accepted", - "acceptedAt": "2026-01-14T14:30:00Z", - "status": "used" - } - ] -} -Response (401-ERROR): -{ - "message": "not authorized" -} - - -Bank Top-Up Integration (To be provided by bank) -------------------------------------------------- -WHAT WE NEED FROM BANK: -1. Payment page URL or API endpoint to initialize payment -2. Required parameters: - - Amount - - Currency - - Return URL (redirect after payment) - - Callback URL (for payment confirmation webhook) -3. Payment confirmation webhook format -4. Transaction ID for tracking - -EXPECTED FLOW: -1. User clicks "Top Up Balance" -2. Frontend redirects to bank payment page (or opens popup) -3. User completes card payment on bank side -4. Bank sends webhook to backend with payment confirmation -5. Backend updates user balance -6. Bank redirects user back to our app -7. Frontend refreshes balance diff --git a/public/visa.svg b/public/visa.svg new file mode 100644 index 0000000..c175e6e --- /dev/null +++ b/public/visa.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/wechat-pay.svg b/public/wechat-pay.svg new file mode 100644 index 0000000..079712e --- /dev/null +++ b/public/wechat-pay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/api.ts b/src/app/api.ts new file mode 100644 index 0000000..a64c274 --- /dev/null +++ b/src/app/api.ts @@ -0,0 +1,21 @@ +import { isDevMode } from '@angular/core'; + +/** + * Endpoint constants for the Fastcheck backend (see public/api.txt). + * Centralised so they can be swapped in one place. + * In dev mode (ng serve) requests go through the Angular proxy (proxy.conf.json) + * to avoid CORS issues. In production the real URLs are used. + */ +export const FASTCHECK_API = isDevMode() + ? '/proxy/fastcheck' + : 'https://api.fastcheck.store'; + +// Legacy QR endpoint kept for the SBP amount → payload redirect flow. +export const QR_API = isDevMode() + ? '/proxy/legacy-qr/qr' + : 'https://qr.vitanova.network:567/qr'; + +// New QR Vitanova API (dynamic QR, settings, polling). +export const QR_VITANOVA_API = isDevMode() + ? '/proxy/qr-vitanova/api' + : 'https://qr.vitanova.network/api'; diff --git a/src/app/app.config.ts b/src/app/app.config.ts index c51175a..94dd9d2 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,6 +1,6 @@ -import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; +import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; import { provideRouter } from '@angular/router'; -import { provideHttpClient, withFetch } from '@angular/common/http'; +import { provideHttpClient } from '@angular/common/http'; import { routes } from './app.routes'; @@ -8,6 +8,6 @@ export const appConfig: ApplicationConfig = { providers: [ provideBrowserGlobalErrorListeners(), provideRouter(routes), - provideHttpClient(withFetch()) + provideHttpClient() ] }; diff --git a/src/app/app.html b/src/app/app.html index 0680b43..dba92a9 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -1 +1,5 @@ - + +
+ +
+ \ No newline at end of file diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 3187b73..8ac1161 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,38 +1,36 @@ -import { Routes } from '@angular/router'; -import { authGuard, loginGuard } from './guards/auth.guard'; -import { LoginComponent } from './components/login/login.component'; -import { DashboardComponent } from './components/dashboard/dashboard.component'; -import { ActiveChecksComponent } from './components/active-checks/active-checks.component'; -import { HistoryComponent } from './components/history/history.component'; +import { Routes } from '@angular/router'; export const routes: Routes = [ { path: '', - redirectTo: '/login', - pathMatch: 'full' + loadComponent: () => { + // Branch: ?id= means legacy SBP merchant flow. + const hasLegacyId = typeof window !== 'undefined' + && new URLSearchParams(window.location.search).has('id'); + return hasLegacyId + ? import('./pages/legacy-pay-page/legacy-pay-page').then((m) => m.LegacyPayPage) + : import('./pages/fastcheck-page/fastcheck-page').then((m) => m.FastcheckPage); + } }, { - path: 'login', - component: LoginComponent, - canActivate: [loginGuard] + path: 'new', + loadComponent: () => + import('./pages/create-page/create-page').then((m) => m.CreatePage) }, { - path: 'dashboard', - component: DashboardComponent, - canActivate: [authGuard] + path: 'about', + loadComponent: () => + import('./pages/about-page/about-page').then((m) => m.AboutPage) }, { - path: 'active-checks', - component: ActiveChecksComponent, - canActivate: [authGuard] + path: 'contacts', + loadComponent: () => + import('./pages/contacts-page/contacts-page').then((m) => m.ContactsPage) }, { - path: 'history', - component: HistoryComponent, - canActivate: [authGuard] + path: 'partners', + loadComponent: () => + import('./pages/partners-page/partners-page').then((m) => m.PartnersPage) }, - { - path: '**', - redirectTo: '/login' - } + { path: '**', redirectTo: '' } ]; diff --git a/src/app/app.scss b/src/app/app.scss index 92faef9..9b823de 100644 --- a/src/app/app.scss +++ b/src/app/app.scss @@ -1,18 +1,12 @@ -* { - margin: 0; - padding: 0; - box-sizing: border-box; +:host { + display: flex; + flex-direction: column; + min-height: 100dvh; } -html, body { - height: 100%; - width: 100%; - overflow-x: hidden; +.app-main { + flex: 1; + display: flex; + flex-direction: column; } -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; - margin: 0; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/src/app/app.spec.ts b/src/app/app.spec.ts index cf7c9c2..652e94a 100644 --- a/src/app/app.spec.ts +++ b/src/app/app.spec.ts @@ -1,10 +1,12 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; import { App } from './app'; describe('App', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [App], + providers: [provideRouter([])] }).compileComponents(); }); @@ -13,11 +15,4 @@ describe('App', () => { const app = fixture.componentInstance; expect(app).toBeTruthy(); }); - - it('should render title', async () => { - const fixture = TestBed.createComponent(App); - await fixture.whenStable(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, FastCheck'); - }); }); diff --git a/src/app/app.ts b/src/app/app.ts index 5444c74..1a4c6b3 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -1,12 +1,13 @@ -import { Component, signal } from '@angular/core'; +import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; +import { SiteHeader } from './site-header/site-header'; +import { SiteFooter } from './site-footer/site-footer'; @Component({ selector: 'app-root', - imports: [RouterOutlet], + imports: [RouterOutlet, SiteHeader, SiteFooter], templateUrl: './app.html', styleUrl: './app.scss' }) -export class App { - protected readonly title = signal('FastCheck'); -} +export class App {} + diff --git a/src/app/components/active-checks/active-checks.component.html b/src/app/components/active-checks/active-checks.component.html deleted file mode 100644 index 36a445a..0000000 --- a/src/app/components/active-checks/active-checks.component.html +++ /dev/null @@ -1,95 +0,0 @@ -
-
- - -
- -
- - - @if (isLoading()) { -
-
-

Loading active checks...

-
- } - - @if (error()) { -
-

{{ error() }}

- -
- } - - @if (!isLoading() && !error()) { - @if (checks().length === 0) { -
-
📭
-

No Active Checks

-

You don't have any active FastChecks at the moment.

- Create FastCheck -
- } @else { -
- @for (check of checks(); track check.fastcheck) { -
-
- Active - {{ formatAmount(check.amount) }} ₽ -
- -
-
- FastCheck Number -
- {{ check.fastcheck }} - -
-
- -
- Code -
- {{ check.code }} - -
-
- -
- Created - {{ check.createdAt | date:'short' }} -
- -
- Expires - {{ check.expiration | date:'short' }} -
-
- -
- ⚠️ Keep this information secure. Anyone with these credentials can claim the money. -
-
- } -
- } - } -
-
diff --git a/src/app/components/active-checks/active-checks.component.scss b/src/app/components/active-checks/active-checks.component.scss deleted file mode 100644 index f1139c1..0000000 --- a/src/app/components/active-checks/active-checks.component.scss +++ /dev/null @@ -1,280 +0,0 @@ -.page-container { - min-height: 100vh; - background: #f5f7fa; -} - -.header { - background: white; - padding: 20px 40px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); - display: flex; - justify-content: space-between; - align-items: center; -} - -.logo { - font-size: 24px; - font-weight: 700; - color: #667eea; -} - -.nav { - display: flex; - gap: 30px; -} - -.nav-link { - text-decoration: none; - color: #666; - font-weight: 500; - padding: 8px 16px; - border-radius: 8px; - transition: all 0.3s; - - &:hover { - color: #667eea; - background: #f0f0f0; - } - - &.active { - color: #667eea; - background: #e8ebff; - } -} - -.content { - padding: 40px; - max-width: 1200px; - margin: 0 auto; - - @media (max-width: 768px) { - padding: 20px; - } -} - -.page-header { - margin-bottom: 40px; - - h1 { - font-size: 32px; - color: #333; - margin-bottom: 10px; - } - - p { - color: #666; - font-size: 16px; - } -} - -.loading { - text-align: center; - padding: 60px 20px; - - .spinner { - width: 50px; - height: 50px; - border: 4px solid #f3f3f3; - border-top: 4px solid #667eea; - border-radius: 50%; - animation: spin 1s linear infinite; - margin: 0 auto 20px; - } - - p { - color: #666; - } -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -.error-card { - background: white; - border-radius: 15px; - padding: 40px; - text-align: center; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); - - p { - color: #c33; - margin-bottom: 20px; - } -} - -.btn-retry { - background: #667eea; - color: white; - border: none; - padding: 12px 30px; - border-radius: 8px; - cursor: pointer; - font-weight: 500; - transition: all 0.3s; - - &:hover { - background: #764ba2; - } -} - -.empty-state { - background: white; - border-radius: 20px; - padding: 60px 40px; - text-align: center; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); - - .empty-icon { - font-size: 64px; - margin-bottom: 20px; - } - - h3 { - font-size: 24px; - color: #333; - margin-bottom: 10px; - } - - p { - color: #666; - margin-bottom: 30px; - } -} - -.btn-primary { - display: inline-block; - background: #667eea; - color: white; - text-decoration: none; - padding: 14px 30px; - border-radius: 8px; - font-weight: 600; - transition: all 0.3s; - - &:hover { - background: #764ba2; - transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); - } -} - -.checks-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); - gap: 30px; - - @media (max-width: 768px) { - grid-template-columns: 1fr; - gap: 20px; - } -} - -.check-card { - background: white; - border-radius: 15px; - padding: 25px; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); - border: 2px solid #e8ebff; - transition: all 0.3s; - - @media (max-width: 768px) { - padding: 20px; - } - - &:hover { - transform: translateY(-5px); - box-shadow: 0 8px 25px rgba(102, 126, 234, 0.15); - } -} - -.check-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20px; - padding-bottom: 15px; - border-bottom: 2px solid #f0f0f0; -} - -.check-badge { - background: #52c41a; - color: white; - padding: 6px 14px; - border-radius: 20px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; -} - -.check-amount { - font-size: 24px; - font-weight: 700; - color: #667eea; -} - -.check-details { - margin-bottom: 15px; -} - -.detail-item { - margin-bottom: 15px; - - .label { - display: block; - font-size: 12px; - color: #999; - text-transform: uppercase; - font-weight: 600; - margin-bottom: 5px; - } - - .value { - font-size: 16px; - color: #333; - font-weight: 500; - - &.code { - font-size: 20px; - color: #667eea; - font-weight: 700; - } - } -} - -.value-copy { - display: flex; - justify-content: space-between; - align-items: center; - gap: 10px; -} - -.btn-copy { - background: #f0f0f0; - border: none; - padding: 6px 12px; - border-radius: 6px; - cursor: pointer; - font-size: 16px; - transition: all 0.2s; - - &:hover { - background: #e0e0e0; - transform: scale(1.1); - } - - &:active { - transform: scale(0.95); - } -} - -.check-warning { - background: #fffbe6; - border-left: 4px solid #faad14; - padding: 12px; - border-radius: 6px; - font-size: 12px; - color: #666; - line-height: 1.5; -} diff --git a/src/app/components/active-checks/active-checks.component.ts b/src/app/components/active-checks/active-checks.component.ts deleted file mode 100644 index 4a0d7f4..0000000 --- a/src/app/components/active-checks/active-checks.component.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Component, OnInit, signal } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RouterLink } from '@angular/router'; -import { FastCheckService } from '../../services/fastcheck.service'; -import { FastCheck } from '../../models/fastcheck.model'; - -@Component({ - selector: 'app-active-checks', - standalone: true, - imports: [CommonModule, RouterLink], - templateUrl: './active-checks.component.html', - styleUrls: ['./active-checks.component.scss'] -}) -export class ActiveChecksComponent implements OnInit { - checks = signal([]); - isLoading = signal(true); - error = signal(''); - - constructor(private fastCheckService: FastCheckService) {} - - ngOnInit(): void { - this.loadActiveChecks(); - } - - loadActiveChecks(): void { - this.isLoading.set(true); - this.error.set(''); - - this.fastCheckService.getActiveFastChecks().subscribe({ - next: (response) => { - this.checks.set(response.checks); - this.isLoading.set(false); - }, - error: (err) => { - this.error.set('Failed to load active checks'); - this.isLoading.set(false); - console.error('Load error:', err); - } - }); - } - - formatAmount(amount: number): string { - return new Intl.NumberFormat('ru-RU').format(amount); - } - - copyToClipboard(text: string, type: string): void { - navigator.clipboard.writeText(text).then(() => { - alert(`${type} copied to clipboard!`); - }); - } -} diff --git a/src/app/components/dashboard/dashboard.component.html b/src/app/components/dashboard/dashboard.component.html deleted file mode 100644 index 74e3fd2..0000000 --- a/src/app/components/dashboard/dashboard.component.html +++ /dev/null @@ -1,142 +0,0 @@ -
- -
- - -
- -
- -
- @if (isLoadingBalance()) { -
-
-
- } @else if (balance()) { -
- Current Balance -

{{ formatAmount(balance()!.balance) }} ₽

- -
- } -
- -
- -
-

Create New FastCheck

- -
- - -
- - @if (createError()) { -
{{ createError() }}
- } - - -
- - -
-

Accept FastCheck

- -
- - -
- -
- - -
- - @if (acceptError()) { -
{{ acceptError() }}
- } - - @if (acceptSuccess()) { -
FastCheck accepted successfully!
- } - - -
-
-
-
- - -@if (createdCheck()) { - -} diff --git a/src/app/components/dashboard/dashboard.component.scss b/src/app/components/dashboard/dashboard.component.scss deleted file mode 100644 index c1b6ecb..0000000 --- a/src/app/components/dashboard/dashboard.component.scss +++ /dev/null @@ -1,363 +0,0 @@ -.dashboard-container { - min-height: 100vh; - background: #f5f7fa; -} - -.header { - background: white; - padding: 20px 40px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); - display: flex; - justify-content: space-between; - align-items: center; - - @media (max-width: 768px) { - padding: 15px 20px; - flex-direction: column; - gap: 15px; - } -} - -.logo { - font-size: 24px; - font-weight: 700; - color: #667eea; -} - -.nav { - display: flex; - gap: 30px; - align-items: center; - - @media (max-width: 768px) { - gap: 10px; - flex-wrap: wrap; - justify-content: center; - } -} - -.nav-link { - text-decoration: none; - color: #666; - font-weight: 500; - padding: 8px 16px; - border-radius: 8px; - transition: all 0.3s; - - &:hover { - color: #667eea; - background: #f0f0f0; - } - - &.active { - color: #667eea; - background: #e8ebff; - } -} - -.btn-logout { - background: #ff4d4f; - color: white; - border: none; - padding: 10px 20px; - border-radius: 8px; - cursor: pointer; - font-weight: 500; - transition: all 0.3s; - - &:hover { - background: #ff7875; - transform: translateY(-2px); - } -} - -.content { - padding: 40px; - max-width: 1200px; - margin: 0 auto; - - @media (max-width: 768px) { - padding: 20px; - } -} - -.balance-card { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - border-radius: 20px; - padding: 40px; - color: white; - margin-bottom: 40px; - box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3); - - @media (max-width: 768px) { - padding: 30px 20px; - margin-bottom: 20px; - } -} - -.balance-info { - text-align: center; -} - -.balance-label { - font-size: 16px; - opacity: 0.9; - display: block; - margin-bottom: 10px; -} - -.balance-amount { - font-size: 48px; - font-weight: 700; - margin: 10px 0 30px; - - @media (max-width: 768px) { - font-size: 36px; - margin: 10px 0 20px; - } -} - -.btn-topup { - background: rgba(255, 255, 255, 0.2); - color: white; - border: 2px solid white; - padding: 12px 30px; - border-radius: 10px; - cursor: pointer; - font-size: 16px; - font-weight: 600; - transition: all 0.3s; - - &:hover { - background: white; - color: #667eea; - } -} - -.actions-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); - gap: 30px; - - @media (max-width: 768px) { - grid-template-columns: 1fr; - gap: 20px; - } -} - -.card { - background: white; - border-radius: 15px; - padding: 30px; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); -} - -.card-title { - font-size: 20px; - font-weight: 600; - margin-bottom: 25px; - color: #333; -} - -.form-group { - margin-bottom: 20px; - - label { - display: block; - font-size: 14px; - font-weight: 500; - color: #666; - margin-bottom: 8px; - } -} - -.input { - width: 100%; - padding: 12px 16px; - border: 2px solid #e0e0e0; - border-radius: 8px; - font-size: 16px; - transition: all 0.3s; - box-sizing: border-box; - - &:focus { - outline: none; - border-color: #667eea; - } - - &:disabled { - background: #f5f5f5; - cursor: not-allowed; - } -} - -.btn-primary { - width: 100%; - background: #667eea; - color: white; - border: none; - padding: 14px; - border-radius: 8px; - cursor: pointer; - font-size: 16px; - font-weight: 600; - transition: all 0.3s; - margin-top: 10px; - - &:hover:not(:disabled) { - background: #764ba2; - transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); - } - - &:disabled { - background: #ccc; - cursor: not-allowed; - transform: none; - } -} - -.error-message { - background: #fee; - color: #c33; - padding: 12px; - border-radius: 8px; - font-size: 14px; - margin: 15px 0; -} - -.success-message { - background: #efe; - color: #3c3; - padding: 12px; - border-radius: 8px; - font-size: 14px; - margin: 15px 0; -} - -.loading-small { - text-align: center; - padding: 20px; - - .spinner-small { - width: 30px; - height: 30px; - border: 3px solid rgba(255, 255, 255, 0.3); - border-top: 3px solid white; - border-radius: 50%; - animation: spin 1s linear infinite; - margin: 0 auto; - } -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -// Modal -.modal-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.6); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; -} - -.modal { - background: white; - border-radius: 20px; - max-width: 500px; - width: 90%; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); -} - -.modal-header { - padding: 30px 30px 20px; - border-bottom: 1px solid #eee; - display: flex; - justify-content: space-between; - align-items: center; - - h3 { - margin: 0; - color: #333; - } -} - -.close-btn { - background: none; - border: none; - font-size: 32px; - cursor: pointer; - color: #999; - line-height: 1; - padding: 0; - width: 32px; - height: 32px; - - &:hover { - color: #333; - } -} - -.modal-body { - padding: 30px; -} - -.check-details { - background: #f9f9f9; - border-radius: 12px; - padding: 20px; - margin-bottom: 20px; -} - -.detail-row { - display: flex; - justify-content: space-between; - padding: 12px 0; - border-bottom: 1px solid #e0e0e0; - - &:last-child { - border-bottom: none; - } -} - -.detail-label { - color: #666; - font-size: 14px; -} - -.detail-value { - font-weight: 600; - color: #333; - - &.code { - font-size: 20px; - color: #667eea; - } -} - -.modal-note { - background: #fffbe6; - border-left: 4px solid #faad14; - padding: 15px; - border-radius: 8px; - - p { - margin: 0; - font-size: 14px; - color: #666; - line-height: 1.6; - } -} - -.modal-footer { - padding: 20px 30px 30px; - text-align: center; -} diff --git a/src/app/components/dashboard/dashboard.component.ts b/src/app/components/dashboard/dashboard.component.ts deleted file mode 100644 index 3034ee5..0000000 --- a/src/app/components/dashboard/dashboard.component.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { Component, OnInit, signal } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; -import { Router, RouterLink } from '@angular/router'; -import { FastCheckService } from '../../services/fastcheck.service'; -import { AuthService } from '../../services/auth.service'; -import { Balance, CreateFastCheckResponse } from '../../models/fastcheck.model'; - -@Component({ - selector: 'app-dashboard', - standalone: true, - imports: [CommonModule, FormsModule, RouterLink], - templateUrl: './dashboard.component.html', - styleUrls: ['./dashboard.component.scss'] -}) -export class DashboardComponent implements OnInit { - balance = signal(null); - isLoadingBalance = signal(true); - - // Create FastCheck - createAmount = signal(0); - isCreating = signal(false); - createdCheck = signal(null); - createError = signal(''); - - // Accept FastCheck - acceptNumber = signal(''); - acceptCode = signal(''); - isAccepting = signal(false); - acceptSuccess = signal(false); - acceptError = signal(''); - - constructor( - private fastCheckService: FastCheckService, - private authService: AuthService, - private router: Router - ) {} - - ngOnInit(): void { - this.loadBalance(); - } - - loadBalance(): void { - this.isLoadingBalance.set(true); - this.fastCheckService.getBalance().subscribe({ - next: (balance) => { - this.balance.set(balance); - this.isLoadingBalance.set(false); - }, - error: (err) => { - console.error('Failed to load balance:', err); - this.isLoadingBalance.set(false); - } - }); - } - - createFastCheck(): void { - const amount = this.createAmount(); - - if (!amount || amount <= 0) { - this.createError.set('Please enter a valid amount'); - return; - } - - const currentBalance = this.balance(); - if (currentBalance && amount > currentBalance.balance) { - this.createError.set('Insufficient balance'); - return; - } - - this.isCreating.set(true); - this.createError.set(''); - this.createdCheck.set(null); - - this.fastCheckService.createFastCheck({ - amount: amount, - currency: 'RUB' - }).subscribe({ - next: (response) => { - this.createdCheck.set(response); - this.isCreating.set(false); - this.createAmount.set(0); - this.loadBalance(); // Refresh balance - }, - error: (err) => { - this.createError.set('Failed to create FastCheck. Please try again.'); - this.isCreating.set(false); - console.error('Create error:', err); - } - }); - } - - acceptFastCheck(): void { - const number = this.acceptNumber().trim(); - const code = this.acceptCode().trim(); - - if (!number || !code) { - this.acceptError.set('Please enter both FastCheck number and code'); - return; - } - - this.isAccepting.set(true); - this.acceptError.set(''); - this.acceptSuccess.set(false); - - this.fastCheckService.acceptFastCheck({ - fastcheck: number, - code: code - }).subscribe({ - next: () => { - this.acceptSuccess.set(true); - this.isAccepting.set(false); - this.acceptNumber.set(''); - this.acceptCode.set(''); - this.loadBalance(); // Refresh balance - - setTimeout(() => { - this.acceptSuccess.set(false); - }, 3000); - }, - error: (err) => { - this.acceptError.set('Failed to accept FastCheck. Check your credentials.'); - this.isAccepting.set(false); - console.error('Accept error:', err); - } - }); - } - - formatAmount(amount: number): string { - return new Intl.NumberFormat('ru-RU').format(amount); - } - - formatFastCheckNumber(input: string): string { - const cleaned = input.replace(/\D/g, ''); - const formatted = cleaned.match(/.{1,4}/g)?.join('-') || ''; - return formatted.slice(0, 14); // xxxx-xxxx-xxxx - } - - onFastCheckNumberInput(event: Event): void { - const input = event.target as HTMLInputElement; - const formatted = this.formatFastCheckNumber(input.value); - this.acceptNumber.set(formatted); - } - - closeCreatedCheckModal(): void { - this.createdCheck.set(null); - } - - logout(): void { - const sessionId = this.authService.getSessionId(); - if (sessionId) { - this.authService.deleteWebSession(sessionId).subscribe({ - next: () => { - this.router.navigate(['/login']); - }, - error: (err) => { - console.error('Logout error:', err); - this.authService.clearAuthentication(); - this.router.navigate(['/login']); - } - }); - } - } - - topUpBalance(): void { - // TODO: Implement bank integration - alert('Bank integration will be implemented. You will be redirected to bank payment page.'); - } -} diff --git a/src/app/components/history/history.component.html b/src/app/components/history/history.component.html deleted file mode 100644 index df13677..0000000 --- a/src/app/components/history/history.component.html +++ /dev/null @@ -1,86 +0,0 @@ -
-
- - -
- -
- - - @if (isLoading()) { -
-
-

Loading history...

-
- } - - @if (error()) { -
-

{{ error() }}

- -
- } - - @if (!isLoading() && !error()) { - @if (checks().length === 0) { -
-
📜
-

No History

-

Your transaction history will appear here.

- Go to Dashboard -
- } @else { -
- @for (check of checks(); track check.fastcheck) { -
-
-
- - {{ getTypeLabel(check.type) }} - - {{ check.fastcheck }} -
- {{ formatAmount(check.amount) }} ₽ -
- -
- @if (check.createdAt) { -
- Created: - {{ check.createdAt | date:'short' }} -
- } - - @if (check.usedAt) { -
- Used: - {{ check.usedAt | date:'short' }} -
- } - - @if (check.acceptedAt) { -
- Accepted: - {{ check.acceptedAt | date:'short' }} -
- } - -
- Status: - {{ check.status }} -
-
-
- } -
- } - } -
-
diff --git a/src/app/components/history/history.component.scss b/src/app/components/history/history.component.scss deleted file mode 100644 index f3836df..0000000 --- a/src/app/components/history/history.component.scss +++ /dev/null @@ -1,270 +0,0 @@ -.page-container { - min-height: 100vh; - background: #f5f7fa; -} - -.header { - background: white; - padding: 20px 40px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); - display: flex; - justify-content: space-between; - align-items: center; -} - -.logo { - font-size: 24px; - font-weight: 700; - color: #667eea; -} - -.nav { - display: flex; - gap: 30px; -} - -.nav-link { - text-decoration: none; - color: #666; - font-weight: 500; - padding: 8px 16px; - border-radius: 8px; - transition: all 0.3s; - - &:hover { - color: #667eea; - background: #f0f0f0; - } - - &.active { - color: #667eea; - background: #e8ebff; - } -} - -.content { - padding: 40px; - max-width: 1000px; - margin: 0 auto; - - @media (max-width: 768px) { - padding: 20px; - } -} - -.page-header { - margin-bottom: 40px; - - h1 { - font-size: 32px; - color: #333; - margin-bottom: 10px; - } - - p { - color: #666; - font-size: 16px; - } -} - -.loading { - text-align: center; - padding: 60px 20px; - - .spinner { - width: 50px; - height: 50px; - border: 4px solid #f3f3f3; - border-top: 4px solid #667eea; - border-radius: 50%; - animation: spin 1s linear infinite; - margin: 0 auto 20px; - } - - p { - color: #666; - } -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -.error-card { - background: white; - border-radius: 15px; - padding: 40px; - text-align: center; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); - - p { - color: #c33; - margin-bottom: 20px; - } -} - -.btn-retry { - background: #667eea; - color: white; - border: none; - padding: 12px 30px; - border-radius: 8px; - cursor: pointer; - font-weight: 500; - transition: all 0.3s; - - &:hover { - background: #764ba2; - } -} - -.empty-state { - background: white; - border-radius: 20px; - padding: 60px 40px; - text-align: center; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); - - .empty-icon { - font-size: 64px; - margin-bottom: 20px; - } - - h3 { - font-size: 24px; - color: #333; - margin-bottom: 10px; - } - - p { - color: #666; - margin-bottom: 30px; - } -} - -.btn-primary { - display: inline-block; - background: #667eea; - color: white; - text-decoration: none; - padding: 14px 30px; - border-radius: 8px; - font-weight: 600; - transition: all 0.3s; - - &:hover { - background: #764ba2; - transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); - } -} - -.history-list { - display: flex; - flex-direction: column; - gap: 20px; -} - -.history-item { - background: white; - border-radius: 12px; - padding: 25px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); - transition: all 0.3s; - - @media (max-width: 768px) { - padding: 20px; - } - - &:hover { - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); - } -} - -.item-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20px; - padding-bottom: 15px; - border-bottom: 1px solid #f0f0f0; -} - -.item-info { - display: flex; - align-items: center; - gap: 15px; -} - -.type-badge { - padding: 6px 14px; - border-radius: 20px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - - &.type-created { - background: #e8ebff; - color: #667eea; - } - - &.type-accepted { - background: #e6f7ff; - color: #1890ff; - } -} - -.item-number { - font-family: monospace; - font-size: 16px; - color: #666; - font-weight: 500; -} - -.item-amount { - font-size: 24px; - font-weight: 700; - color: #333; -} - -.item-details { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 15px; - - @media (max-width: 768px) { - grid-template-columns: 1fr; - gap: 10px; - } -} - -.detail { - display: flex; - flex-direction: column; - gap: 5px; -} - -.detail-label { - font-size: 12px; - color: #999; - text-transform: uppercase; - font-weight: 600; -} - -.detail-value { - font-size: 14px; - color: #333; - font-weight: 500; -} - -.status-badge { - display: inline-block; - padding: 4px 12px; - border-radius: 12px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - background: #f5f5f5; - color: #999; -} diff --git a/src/app/components/history/history.component.ts b/src/app/components/history/history.component.ts deleted file mode 100644 index 4a98297..0000000 --- a/src/app/components/history/history.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Component, OnInit, signal } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RouterLink } from '@angular/router'; -import { FastCheckService } from '../../services/fastcheck.service'; -import { FastCheck } from '../../models/fastcheck.model'; - -@Component({ - selector: 'app-history', - standalone: true, - imports: [CommonModule, RouterLink], - templateUrl: './history.component.html', - styleUrls: ['./history.component.scss'] -}) -export class HistoryComponent implements OnInit { - checks = signal([]); - isLoading = signal(true); - error = signal(''); - - constructor(private fastCheckService: FastCheckService) {} - - ngOnInit(): void { - this.loadHistory(); - } - - loadHistory(): void { - this.isLoading.set(true); - this.error.set(''); - - this.fastCheckService.getFastCheckHistory().subscribe({ - next: (response) => { - this.checks.set(response.checks); - this.isLoading.set(false); - }, - error: (err) => { - this.error.set('Failed to load history'); - this.isLoading.set(false); - console.error('Load error:', err); - } - }); - } - - formatAmount(amount: number): string { - return new Intl.NumberFormat('ru-RU').format(amount); - } - - getTypeLabel(type?: string): string { - return type === 'created' ? 'Created' : 'Accepted'; - } - - getTypeClass(type?: string): string { - return type === 'created' ? 'type-created' : 'type-accepted'; - } -} diff --git a/src/app/components/login/login.component.html b/src/app/components/login/login.component.html deleted file mode 100644 index 14e7f75..0000000 --- a/src/app/components/login/login.component.html +++ /dev/null @@ -1,39 +0,0 @@ - diff --git a/src/app/components/login/login.component.scss b/src/app/components/login/login.component.scss deleted file mode 100644 index d6c17ce..0000000 --- a/src/app/components/login/login.component.scss +++ /dev/null @@ -1,177 +0,0 @@ -.login-container { - height: 100vh; - display: flex; - align-items: center; - justify-content: center; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - padding: 20px; - overflow: hidden; -} - -.login-card { - background: white; - border-radius: 20px; - padding: 40px; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); - max-width: 400px; - width: 100%; - text-align: center; - - @media (max-width: 768px) { - padding: 30px 20px; - border-radius: 15px; - max-width: 100%; - } -} - -.title { - font-size: 32px; - font-weight: 700; - color: #333; - margin-bottom: 10px; - - @media (max-width: 768px) { - font-size: 28px; - } -} - -.subtitle { - font-size: 16px; - color: #666; - margin-bottom: 30px; - - @media (max-width: 768px) { - font-size: 14px; - margin-bottom: 20px; - } -} - -.loading { - padding: 40px 0; - - .spinner { - width: 50px; - height: 50px; - border: 4px solid #f3f3f3; - border-top: 4px solid #667eea; - border-radius: 50%; - animation: spin 1s linear infinite; - margin: 0 auto 20px; - } - - p { - color: #666; - } -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -.error-message { - padding: 20px; - background: #fee; - border-radius: 10px; - color: #c33; - margin: 20px 0; - - p { - margin-bottom: 15px; - } -} - -.qr-section { - margin: 30px 0; -} - -.qr-wrapper { - display: inline-block; - padding: 20px; - background: white; - border-radius: 15px; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); - margin-bottom: 20px; - - @media (max-width: 768px) { - padding: 15px; - } - - ::ng-deep canvas { - max-width: 100%; - height: auto !important; - } -} - -.status-indicator { - display: flex; - align-items: center; - justify-content: center; - gap: 10px; - color: #667eea; - font-weight: 500; - margin: 20px 0; - - .pulse { - width: 10px; - height: 10px; - background: #667eea; - border-radius: 50%; - animation: pulse 1.5s ease-in-out infinite; - } -} - -@keyframes pulse { - 0%, 100% { - opacity: 1; - transform: scale(1); - } - 50% { - opacity: 0.5; - transform: scale(1.2); - } -} - -.btn-link { - background: none; - border: none; - color: #667eea; - cursor: pointer; - text-decoration: underline; - font-size: 14px; - padding: 10px; - - &:hover { - color: #764ba2; - } -} - -.btn-secondary { - background: #667eea; - color: white; - border: none; - padding: 12px 30px; - border-radius: 8px; - cursor: pointer; - font-size: 16px; - font-weight: 500; - transition: all 0.3s; - - &:hover { - background: #764ba2; - transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); - } -} - -.info { - margin-top: 30px; - padding-top: 20px; - border-top: 1px solid #eee; - - p { - font-size: 14px; - color: #999; - line-height: 1.6; - } -} diff --git a/src/app/components/login/login.component.ts b/src/app/components/login/login.component.ts deleted file mode 100644 index 8081a2e..0000000 --- a/src/app/components/login/login.component.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Component, OnInit, OnDestroy, signal } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { Router } from '@angular/router'; -import { AuthService } from '../../services/auth.service'; -import { Subscription } from 'rxjs'; -import { QRCodeComponent } from 'angularx-qrcode'; - -@Component({ - selector: 'app-login', - standalone: true, - imports: [CommonModule, QRCodeComponent], - templateUrl: './login.component.html', - styleUrls: ['./login.component.scss'] -}) -export class LoginComponent implements OnInit, OnDestroy { - qrData = signal(''); - sessionId = signal(''); - isLoading = signal(true); - error = signal(''); - - private pollSubscription?: Subscription; - - constructor( - private authService: AuthService, - private router: Router - ) {} - - ngOnInit(): void { - this.createSession(); - } - - ngOnDestroy(): void { - this.pollSubscription?.unsubscribe(); - } - - createSession(): void { - this.isLoading.set(true); - this.error.set(''); - - this.authService.createWebSession().subscribe({ - next: (session) => { - this.sessionId.set(session.sessionId); - this.qrData.set(`fastcheck://login?session=${session.sessionId}`); - this.isLoading.set(false); - this.startPolling(session.sessionId); - }, - error: (err) => { - this.error.set('Failed to create session. Please try again.'); - this.isLoading.set(false); - console.error('Session creation error:', err); - } - }); - } - - private startPolling(sessionId: string): void { - this.pollSubscription = this.authService.startPolling(sessionId).subscribe({ - next: (session) => { - if (session.Status) { - this.router.navigate(['/dashboard']); - } - }, - error: (err) => { - this.error.set('Authentication failed. Please try again.'); - console.error('Polling error:', err); - } - }); - } - - refreshQR(): void { - this.pollSubscription?.unsubscribe(); - this.createSession(); - } -} diff --git a/src/app/fastcheck.service.ts b/src/app/fastcheck.service.ts new file mode 100644 index 0000000..3257096 --- /dev/null +++ b/src/app/fastcheck.service.ts @@ -0,0 +1,28 @@ +import { Injectable, signal } from '@angular/core'; + +export interface FastcheckData { + fastcheck: string; + amount: number | null; + code: string; + expiration?: string; +} + +/** + * Shared state between the home (Fastcheck) page and the create-new page. + * When a new fastcheck is created via POST /fastcheck, the create page stores + * the returned data here and the home page reads it to autofill its fields. + */ +@Injectable({ providedIn: 'root' }) +export class FastcheckService { + readonly created = signal(null); + + setCreated(data: FastcheckData): void { + this.created.set(data); + } + + consume(): FastcheckData | null { + const value = this.created(); + this.created.set(null); + return value; + } +} diff --git a/src/app/guards/auth.guard.ts b/src/app/guards/auth.guard.ts deleted file mode 100644 index 4a75d1d..0000000 --- a/src/app/guards/auth.guard.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { inject } from '@angular/core'; -import { Router, CanActivateFn } from '@angular/router'; -import { AuthService } from '../services/auth.service'; - -export const authGuard: CanActivateFn = () => { - const authService = inject(AuthService); - const router = inject(Router); - - if (authService.isAuthenticated().isAuthenticated) { - return true; - } - - router.navigate(['/login']); - return false; -}; - -export const loginGuard: CanActivateFn = () => { - const authService = inject(AuthService); - const router = inject(Router); - - if (!authService.isAuthenticated().isAuthenticated) { - return true; - } - - router.navigate(['/dashboard']); - return false; -}; diff --git a/src/app/models/api.model.ts b/src/app/models/api.model.ts deleted file mode 100644 index 76afc7a..0000000 --- a/src/app/models/api.model.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface ApiResponse { - data?: T; - message?: string; - error?: string; -} - -export interface PingResponse { - message: string; -} diff --git a/src/app/models/fastcheck.model.ts b/src/app/models/fastcheck.model.ts deleted file mode 100644 index 9cd7e02..0000000 --- a/src/app/models/fastcheck.model.ts +++ /dev/null @@ -1,44 +0,0 @@ -export interface FastCheck { - fastcheck: string; - amount: number; - currency: string; - code?: string; - expiration: string; - status: 'active' | 'used' | 'expired'; - createdAt?: string; - usedAt?: string; - acceptedAt?: string; - type?: 'created' | 'accepted'; -} - -export interface CreateFastCheckRequest { - amount: number; - currency: string; -} - -export interface CreateFastCheckResponse { - fastcheck: string; - expiration: string; - code: string; - Status: boolean; -} - -export interface AcceptFastCheckRequest { - fastcheck: string; - code: string; -} - -export interface CheckStatusResponse { - fastcheck: string; - expiration: string; - Status: boolean; -} - -export interface Balance { - balance: number; - currency: string; -} - -export interface FastCheckListResponse { - checks: FastCheck[]; -} diff --git a/src/app/models/session.model.ts b/src/app/models/session.model.ts deleted file mode 100644 index e94c5bf..0000000 --- a/src/app/models/session.model.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface WebSession { - sessionId: string; - userId: string; - expires: string; - userSessionId: string; - Status: boolean; -} - -export interface AuthState { - isAuthenticated: boolean; - sessionId: string | null; - userSessionId: string | null; -} diff --git a/src/app/pages/about-page/about-page.html b/src/app/pages/about-page/about-page.html new file mode 100644 index 0000000..4773b01 --- /dev/null +++ b/src/app/pages/about-page/about-page.html @@ -0,0 +1,40 @@ +
+
+

{{ 'about.title' | translate }}

+

{{ 'about.lead' | translate }}

+
+ +
+ +
+

{{ 'about.what_title' | translate }}

+

{{ 'about.what_text' | translate }}

+
+ +
+

{{ 'about.how_title' | translate }}

+
    +
  1. {{ 'about.step1' | translate }}
  2. +
  3. {{ 'about.step2' | translate }}
  4. +
  5. {{ 'about.step3' | translate }}
  6. +
  7. {{ 'about.step4' | translate }}
  8. +
+
+ +
+

{{ 'about.why_title' | translate }}

+
    +
  • {{ 'about.why1' | translate }}
  • +
  • {{ 'about.why2' | translate }}
  • +
  • {{ 'about.why3' | translate }}
  • +
  • {{ 'about.why4' | translate }}
  • +
+
+ +
+

{{ 'about.company_title' | translate }}

+

{{ 'about.company_text' | translate }}

+
+ +
+
diff --git a/src/app/pages/about-page/about-page.scss b/src/app/pages/about-page/about-page.scss new file mode 100644 index 0000000..b987bbb --- /dev/null +++ b/src/app/pages/about-page/about-page.scss @@ -0,0 +1,75 @@ +:host { + display: block; + background: #f8fafc; + min-height: 100vh; +} + +// Shared info page layout — used by AboutPage and ContactsPage +.info-page { + max-width: 760px; + margin: 0 auto; + padding: 48px 24px 72px; + + @media (max-width: 600px) { + padding: 32px 16px 56px; + } + + &__hero { + margin-bottom: 48px; + border-bottom: 1px solid #e2e8f0; + padding-bottom: 32px; + } + + &__title { + font-size: 32px; + font-weight: 800; + color: #0f172a; + margin: 0 0 12px; + letter-spacing: -0.5px; + + @media (max-width: 600px) { font-size: 26px; } + } + + &__lead { + font-size: 17px; + line-height: 1.7; + color: #475569; + margin: 0; + } + + &__body { + display: flex; + flex-direction: column; + gap: 48px; + } +} + +.info-section { + &__title { + font-size: 20px; + font-weight: 700; + color: #1e293b; + margin: 0 0 14px; + } + + &__text { + font-size: 15.5px; + line-height: 1.75; + color: #475569; + margin: 0; + } + + &__steps, &__list { + padding-left: 22px; + margin: 0; + display: flex; + flex-direction: column; + gap: 10px; + + li { + font-size: 15.5px; + line-height: 1.65; + color: #475569; + } + } +} diff --git a/src/app/pages/about-page/about-page.ts b/src/app/pages/about-page/about-page.ts new file mode 100644 index 0000000..3979fea --- /dev/null +++ b/src/app/pages/about-page/about-page.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { TranslatePipe } from '../../translate/translate.pipe'; + +@Component({ + selector: 'app-about-page', + imports: [TranslatePipe], + templateUrl: './about-page.html', + styleUrl: './about-page.scss' +}) +export class AboutPage {} diff --git a/src/app/pages/contacts-page/contacts-page.html b/src/app/pages/contacts-page/contacts-page.html new file mode 100644 index 0000000..5400fab --- /dev/null +++ b/src/app/pages/contacts-page/contacts-page.html @@ -0,0 +1,66 @@ +
+
+

{{ 'contacts.title' | translate }}

+

{{ 'contacts.lead' | translate }}

+
+ +
+ + + +
+

{{ 'contacts.hours_title' | translate }}

+
+
+ {{ 'footer.support_label' | translate }} + 24/7 +
+
+ {{ 'footer.questions_label' | translate }} + 10:00–19:00 МСК +
+
+
+ +
+
diff --git a/src/app/pages/contacts-page/contacts-page.scss b/src/app/pages/contacts-page/contacts-page.scss new file mode 100644 index 0000000..76e3c95 --- /dev/null +++ b/src/app/pages/contacts-page/contacts-page.scss @@ -0,0 +1,146 @@ +:host { + display: block; + background: #f8fafc; + min-height: 100vh; +} + +.info-page { + max-width: 760px; + margin: 0 auto; + padding: 48px 24px 72px; + + @media (max-width: 600px) { + padding: 32px 16px 56px; + } + + &__hero { + margin-bottom: 48px; + border-bottom: 1px solid #e2e8f0; + padding-bottom: 32px; + } + + &__title { + font-size: 32px; + font-weight: 800; + color: #0f172a; + margin: 0 0 12px; + letter-spacing: -0.5px; + + @media (max-width: 600px) { font-size: 26px; } + } + + &__lead { + font-size: 17px; + line-height: 1.7; + color: #475569; + margin: 0; + } + + &__body { + display: flex; + flex-direction: column; + gap: 48px; + } +} + +.info-section { + &__title { + font-size: 20px; + font-weight: 700; + color: #1e293b; + margin: 0 0 14px; + } +} + +.contacts-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + + @media (max-width: 540px) { + grid-template-columns: 1fr; + } +} + +.contact-card { + display: flex; + align-items: center; + gap: 16px; + padding: 20px; + border-radius: 16px; + border: 1px solid #e2e8f0; + background: #fff; + text-decoration: none; + transition: border-color 0.15s, box-shadow 0.15s, background 0.15s; + + &:hover { + border-color: #93c5fd; + box-shadow: 0 4px 16px rgba(30, 64, 175, 0.08); + background: #f8fbff; + } + + &__icon { + font-size: 28px; + line-height: 1; + flex-shrink: 0; + width: 44px; + height: 44px; + display: flex; + align-items: center; + justify-content: center; + } + + &__body { + display: flex; + flex-direction: column; + gap: 3px; + min-width: 0; + } + + &__label { + font-size: 11.5px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: #94a3b8; + } + + &__value { + font-size: 14.5px; + font-weight: 600; + color: #0f172a; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} + +.hours-table { + display: flex; + flex-direction: column; + gap: 12px; +} + +.hours-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 18px; + border-radius: 10px; + background: #f8fafc; + border: 1px solid #e2e8f0; + + &__label { + font-size: 14px; + color: #475569; + font-weight: 500; + } + + &__value { + font-size: 14px; + font-weight: 700; + color: #0f172a; + + &--green { color: #16a34a; } + } +} diff --git a/src/app/pages/contacts-page/contacts-page.ts b/src/app/pages/contacts-page/contacts-page.ts new file mode 100644 index 0000000..3f6bca9 --- /dev/null +++ b/src/app/pages/contacts-page/contacts-page.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import { TranslatePipe } from '../../translate/translate.pipe'; + +@Component({ + selector: 'app-contacts-page', + imports: [TranslatePipe], + templateUrl: './contacts-page.html', + styleUrl: './contacts-page.scss' +}) +export class ContactsPage {} diff --git a/src/app/pages/create-page/create-page.html b/src/app/pages/create-page/create-page.html new file mode 100644 index 0000000..f28fc67 --- /dev/null +++ b/src/app/pages/create-page/create-page.html @@ -0,0 +1,158 @@ +
+
+ +
+ + + + + +

+ {{ 'create.title' | translate }}  + fastCHECK +

+

{{ 'create.subtitle' | translate }}

+
+ +
+ + +
+ {{ 'create.payment_label' | translate }} +
+ + + + + +
+
+ + +
+ {{ 'create.currency_label' | translate }} +
+ + + + + +
+
+ +
+ +
+ + +
+ {{ 'create.amount_hint' | translate }} {{ minAmount() }}–{{ maxAmount().toLocaleString('ru') }} ₽ + @if (error()) { + {{ error() }} + } +
+ +
+ + +
+ + + + +@if (qrImageUrl()) { +
+
+ +

{{ 'create.qr_label' | translate }}

+ QR + @if (qrStatus()) { + {{ qrStatus() }} + } + @if (qrPolling()) { +

{{ 'create.qr_waiting' | translate }}

+ } +
+
+} +
+ + +
+
diff --git a/src/app/pages/create-page/create-page.scss b/src/app/pages/create-page/create-page.scss new file mode 100644 index 0000000..d4621ea --- /dev/null +++ b/src/app/pages/create-page/create-page.scss @@ -0,0 +1,266 @@ +@use './../../../shared' as *; + +.card__header { + position: relative; +} + +.back { + position: absolute; + top: 14px; + left: 14px; + width: 44px; + height: 44px; + border-radius: 50%; + display: inline-flex; + align-items: center; + justify-content: center; + color: #475569; + background: #f1f5f9; + border: 1px solid #e2e8f0; + text-decoration: none; + transition: background 0.15s, color 0.15s; + z-index: 1; + + &:hover { background: #e2e8f0; color: #0f172a; } + &:active { background: #cbd5e1; } +} + +.currency-badge { + display: flex; + align-items: center; + gap: 10px; + background: #f1f5f9; + border-radius: 12px; + padding: 12px 16px; + margin-bottom: 18px; + + &__flag { font-size: 22px; line-height: 1; } + &__code { font-size: 15px; font-weight: 700; color: #0f172a; } + &__name { font-size: 13px; color: #64748b; margin-left: auto; } +} + +// ─── Methods row ──────────────────────────────────────────────────────────── +.methods { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 8px; + + @media (max-width: 360px) { + gap: 6px; + } +} + +.method { + display: flex; + align-items: center; + justify-content: center; + height: 56px; + padding: 8px; + border-radius: 12px; + border: 2px solid #e2e8f0; + background: #fff; + cursor: pointer; + transition: border-color .15s, background .15s, transform .1s, box-shadow .15s; + -webkit-appearance: none; + font-family: inherit; + + @media (max-width: 360px) { + height: 52px; + padding: 6px; + } + + &__logo { + max-width: 100%; + max-height: 28px; + object-fit: contain; + display: block; + pointer-events: none; + } + + &:hover:not(:disabled):not(.method--disabled) { + border-color: #cbd5e1; + } + + &:active:not(:disabled) { transform: scale(.97); } + + &--active { + border-color: #2563eb; + background: rgba(37, 99, 235, .06); + box-shadow: 0 0 0 3px rgba(37, 99, 235, .1); + } + + &--disabled, + &:disabled { + cursor: not-allowed; + background: #f8fafc; + + .method__logo { + filter: grayscale(1); + opacity: .45; + } + } +} + +// ─── Currency chips ───────────────────────────────────────────────────────── +.currencies { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.chip { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 0 14px; + height: 44px; + border-radius: 999px; + border: 2px solid #e2e8f0; + background: #f8fafc; + color: #475569; + font-family: inherit; + font-size: 14px; + font-weight: 700; + cursor: pointer; + transition: border-color .15s, background .15s, color .15s; + -webkit-appearance: none; + + &__flag { font-size: 16px; line-height: 1; } + &__sign { + font-size: 15px; + font-weight: 800; + color: #1e40af; + line-height: 1; + } + &__code { letter-spacing: .3px; } + + &--active { + border-color: #2563eb; + background: rgba(37, 99, 235, .08); + color: #1e40af; + } + + &--disabled, + &:disabled { + opacity: .45; + cursor: not-allowed; + color: #94a3b8; + + .chip__sign { color: #94a3b8; } + } +} + +.note-input { + width: 100%; + border: 2px solid #e2e8f0; + border-radius: 14px; + background: #f8fafc; + padding: 14px 16px; + font-size: 15px; + font-weight: 500; + color: #0f172a; + font-family: inherit; + resize: vertical; + outline: none; + transition: border-color 0.2s, box-shadow 0.2s, background 0.2s; + line-height: 1.5; + + &::placeholder { color: #cbd5e1; font-weight: 400; } + + &:focus { + border-color: #2563eb; + box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12); + background: #fff; + } +} + +// ─── QR section ───────────────────────────────────────────────────────────── +// ─── QR popup ─────────────────────────────────────────────────────────────── +.qr-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.55); + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; + animation: overlay-in 0.2s ease; +} + +.qr-modal { + position: relative; + background: #fff; + border-radius: 20px; + padding: 32px 28px 24px; + display: flex; + flex-direction: column; + align-items: center; + gap: 14px; + box-shadow: 0 20px 60px rgba(0,0,0,0.25); + animation: modal-in 0.22s cubic-bezier(.34,1.56,.64,1); + max-width: 340px; + width: 90vw; + + &__close { + position: absolute; + top: 12px; + right: 12px; + width: 36px; + height: 36px; + border-radius: 50%; + border: none; + background: #f1f5f9; + color: #475569; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.15s; + &:hover { background: #e2e8f0; } + } + + &__label { + font-size: 13px; + font-weight: 600; + color: #475569; + text-transform: uppercase; + letter-spacing: 0.05em; + } + + &__img { + border-radius: 12px; + box-shadow: 0 2px 12px rgba(0,0,0,0.1); + } + + &__hint { + font-size: 13px; + color: #64748b; + animation: pulse 1.6s ease-in-out infinite; + } + + &__status { + font-size: 11px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + padding: 3px 10px; + border-radius: 20px; + background: #f1f5f9; + color: #475569; + } +} + +@keyframes overlay-in { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes modal-in { + from { opacity: 0; transform: scale(0.85); } + to { opacity: 1; transform: scale(1); } +} + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.45; } +} diff --git a/src/app/pages/create-page/create-page.ts b/src/app/pages/create-page/create-page.ts new file mode 100644 index 0000000..9346e6f --- /dev/null +++ b/src/app/pages/create-page/create-page.ts @@ -0,0 +1,274 @@ +import { Component, inject, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { Router, RouterLink } from '@angular/router'; +import { HttpClient } from '@angular/common/http'; +import { FastcheckService } from '../../fastcheck.service'; +import { FASTCHECK_API, QR_VITANOVA_API } from '../../api'; +import { TranslatePipe } from '../../translate/translate.pipe'; +import { TranslationService } from '../../translate/translation.service'; + +type PaymentMethod = 'sbp'; +type Currency = 'RUB'; + +interface SettingsResponse { + minAmount?: number; + maxAmount?: number; + [key: string]: unknown; +} + +interface CreateQrResponse { + qrId?: string; + nspkID?: string; + Payload?: string; // per API doc (capital P) + nspkurl?: string; // actual field name in real responses + qrUrl?: string; + status?: string; // e.g. "REGISTERED" + [key: string]: unknown; +} + +interface QrStatusResponse { + status?: string; // "REGISTERED" | "NEW" | "APPROVED" | "REJECTED" | "COMPLETED" + nspkurl?: string; + nspkID?: string; + [key: string]: unknown; +} + +interface CreateFastcheckResponse { + id?: string; // real field name from server + fastcheck?: string; // per API doc fallback + expiration?: string; + code?: string; + amount?: number; + Status?: boolean; +} + +/** Generate a v4-like UUID without crypto dependency. */ +function generateUUID(): string { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); + }); +} + +@Component({ + selector: 'app-create-page', + imports: [FormsModule, RouterLink, TranslatePipe], + templateUrl: './create-page.html', + styleUrl: './create-page.scss' +}) +export class CreatePage { + private http = inject(HttpClient); + private store = inject(FastcheckService); + private router = inject(Router); + private i18n = inject(TranslationService); + + private t(key: string): string { return this.i18n.translate(key); } + + // Limits – updated from settings API on init. + minAmount = signal(30); + maxAmount = signal(200_000); + + amount = signal(null); + note = signal(''); + error = signal(''); + loading = signal(false); + settingsLoaded = signal(false); + + currency = signal('RUB'); + payment = signal('sbp'); + + selectPayment(method: PaymentMethod, enabled: boolean): void { + if (!enabled) return; + this.payment.set(method); + } + + selectCurrency(c: Currency, enabled: boolean): void { + if (!enabled) return; + this.currency.set(c); + } + + // QR display state + qrImageUrl = signal(null); + qrPolling = signal(false); + qrStatus = signal(''); + private pollHandle: ReturnType | null = null; + private activeQrId = ''; + + /** Auth credentials passed by the host page as URL params. */ + private get authKey(): string { + return new URLSearchParams(window.location.search).get('authorization-key') ?? ''; + } + private get userId(): string { + return new URLSearchParams(window.location.search).get('userid-value') ?? ''; + } + private get sessionId(): string { + return new URLSearchParams(window.location.search).get('session') ?? ''; + } + private get reference(): string { + return new URLSearchParams(window.location.search).get('ref') ?? window.location.hostname; + } + + get isMobile(): boolean { + return window.innerWidth < 768; + } + + constructor() { + this.loadSettings(); + } + + private loadSettings(): void { + this.http.get(`${QR_VITANOVA_API}/settings`).subscribe({ + next: (s) => { + if (typeof s?.minAmount === 'number') this.minAmount.set(s.minAmount); + if (typeof s?.maxAmount === 'number') this.maxAmount.set(s.maxAmount); + this.settingsLoaded.set(true); + }, + error: () => this.settingsLoaded.set(true) // proceed with defaults + }); + } + + createCheck(): void { + const val = this.amount(); + if (val !== null && val < this.minAmount()) { + this.error.set(`${this.t('errors.invalid_amount')} (мин. ${this.minAmount()} ₽)`); + return; + } + if (val !== null && val > this.maxAmount()) { + this.error.set(`${this.t('errors.invalid_amount')} (макс. ${this.maxAmount().toLocaleString('ru')} ₽)`); + return; + } + + this.error.set(''); + this.loading.set(true); + + const headers: Record = {}; + if (this.authKey) headers['authorization-key'] = this.authKey; + if (this.userId) headers['userid-value'] = this.userId; + + const partnerqrID = generateUUID(); + + this.http + .post( + `${QR_VITANOVA_API}/qr`, + { + qrtype: 'QRDynamic', + ...(val !== null ? { amount: val } : {}), + currency: this.currency(), + partnerqrID, + qrDescription: this.note().trim(), + Userid: this.userId, + Reference: this.reference + }, + { headers } + ) + .subscribe({ + next: (res) => { + this.loading.set(false); + const qrId = res?.qrId ?? res?.nspkID ?? ''; + // Real API uses 'nspkurl'; doc says 'Payload' — try both + const nspkUrl = res?.nspkurl ?? res?.Payload; + this.qrStatus.set(res?.status ?? ''); + + if (nspkUrl && this.isMobile) { + window.location.href = nspkUrl; + return; + } + + if (qrId || nspkUrl) { + this.activeQrId = qrId; + const qrData = nspkUrl + ? `https://api.qrserver.com/v1/create-qr-code/?size=256x256&margin=8&data=${encodeURIComponent(nspkUrl)}` + : (res.qrUrl ?? null); + this.qrImageUrl.set(qrData); + if (qrId) this.startPolling(qrId); + } else { + this.error.set(this.t('errors.payment_failed')); + } + }, + error: (err) => { + this.loading.set(false); + const msg: string | undefined = err?.error?.message; + this.error.set(msg ?? this.t('errors.lookup_failed')); + } + }); + } + + private startPolling(qrId: string): void { + this.stopPolling(); + this.qrPolling.set(true); + this.pollHandle = setInterval(() => { + this.http.get(`${QR_VITANOVA_API}/qr/dynamic/${qrId}`) + .subscribe({ + next: (res) => { + const st = res?.status ?? ''; + this.qrStatus.set(st); + if (st === 'COMPLETED' || st === 'APPROVED') { + this.stopPolling(); + this.createFastcheck(); + } else if (st === 'REJECTED') { + this.stopPolling(); + this.error.set(this.t('errors.payment_failed')); + this.qrImageUrl.set(null); + } + // REGISTERED / NEW / '' — keep polling + }, + error: () => undefined + }); + }, 5000); + } + + private stopPolling(): void { + if (this.pollHandle !== null) { + clearInterval(this.pollHandle); + this.pollHandle = null; + } + this.qrPolling.set(false); + } + + private createFastcheck(): void { + const headers: Record = {}; + if (this.sessionId) headers['Authorization'] = JSON.stringify({ sessionID: this.sessionId }); + + this.http + .post( + `${FASTCHECK_API}/fastcheck`, + { amount: this.amount(), currency: this.currency() }, + { headers } + ) + .subscribe({ + next: (res) => { + const fcNumber = res?.id ?? res?.fastcheck ?? ''; + const payload = { + fastcheck: fcNumber, + code: res?.code ?? '', + amount: res?.amount ?? this.amount() ?? null, + expiration: res?.expiration + }; + if (fcNumber) { + this.store.setCreated(payload); + } + this.router.navigate(['/'], { state: fcNumber ? payload : {} }); + }, + error: () => this.router.navigate(['/']) + }); + } + + onAmountChange(value: number | null): void { + this.amount.set(value || null); + if (value && value > 0) this.error.set(''); + } + + onNoteChange(value: string): void { + this.note.set(value); + } + + closeQr(): void { + this.qrImageUrl.set(null); + this.qrPolling.set(false); + this.qrStatus.set(''); + if (this.pollHandle !== null) { + clearInterval(this.pollHandle); + this.pollHandle = null; + } + } +} diff --git a/src/app/pages/fastcheck-page/fastcheck-page.html b/src/app/pages/fastcheck-page/fastcheck-page.html new file mode 100644 index 0000000..baa0ac4 --- /dev/null +++ b/src/app/pages/fastcheck-page/fastcheck-page.html @@ -0,0 +1,177 @@ +
+
+ +
+ fastCHECK +

+ {{ 'fastcheck.subtitle' | translate }} +

+
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ @if (amountLoading()) { + {{ 'fastcheck.amount_checking' | translate }} + } +
+ + + + + +
+ + + @if (error()) { + {{ error() }} + } +
+ + +
+ + +
+
+ + +@if (popupOpen()) { + +} diff --git a/src/app/pages/fastcheck-page/fastcheck-page.scss b/src/app/pages/fastcheck-page/fastcheck-page.scss new file mode 100644 index 0000000..eec9b8e --- /dev/null +++ b/src/app/pages/fastcheck-page/fastcheck-page.scss @@ -0,0 +1,260 @@ +@use './../../../shared' as *; + +.row { + display: flex; + gap: 8px; + align-items: stretch; + + .input { flex: 1; min-width: 0; } +} + +.share-row { + display: flex; + gap: 8px; +} + +.share-btn { + flex: 1; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + height: 40px; + border-radius: 10px; + border: 1.5px solid #e2e8f0; + font-size: 13px; + font-weight: 600; + font-family: inherit; + cursor: pointer; + transition: background .15s, border-color .15s; + + &--email { + background: #f8fafc; + color: #475569; + &:hover { background: #e2e8f0; border-color: #cbd5e1; } + } + + &--tg { + background: #e7f3fe; + color: #0088cc; + border-color: #bfdbfe; + &:hover { background: #dbeafe; border-color: #93c5fd; } + } + + &:disabled { + opacity: .4; + cursor: not-allowed; + pointer-events: none; + } +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0 16px; + height: 48px; + min-width: 64px; + border-radius: 12px; + font-size: 14px; + font-weight: 700; + text-decoration: none; + border: 2px solid transparent; + cursor: pointer; + font-family: inherit; + white-space: nowrap; + transition: opacity .15s, transform .1s, background .15s; + -webkit-appearance: none; + + &--ghost { + background: #f1f5f9; + color: #2563eb; + border-color: #e2e8f0; + + &:hover { background: #e2e8f0; } + &:active { transform: scale(.97); } + } +} + +.input { + width: 100%; + border: 2px solid #e2e8f0; + border-radius: 12px; + background: #f8fafc; + padding: 0 14px; + height: 48px; + font-size: 16px; + font-weight: 600; + color: #0f172a; + font-family: inherit; + outline: none; + transition: border-color .2s, box-shadow .2s, background .2s; + + &::placeholder { color: #cbd5e1; font-weight: 500; } + + &:focus { + border-color: #2563eb; + box-shadow: 0 0 0 4px rgba(37,99,235,.12); + background: #fff; + } +} + +// ─── Modal (Telegram QR popup) ────────────────────────────────────────────── +.modal { + position: fixed; + inset: 0; + z-index: 1000; + background: rgba(15, 23, 42, .55); + backdrop-filter: blur(6px); + display: flex; + align-items: center; + justify-content: center; + padding: 16px; + animation: fade-in .15s ease-out; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + + @media (max-width: 480px) { + align-items: stretch; + padding: 0; + } + + &__card { + position: relative; + background: #fff; + border-radius: 24px; + width: 100%; + max-width: 360px; + padding: 28px 24px 24px; + text-align: center; + box-shadow: 0 24px 60px rgba(0,0,0,.25); + animation: pop-in .2s ease-out; + margin: auto; + + @media (max-width: 480px) { + max-width: 100%; + border-radius: 0; + box-shadow: none; + padding: calc(28px + env(safe-area-inset-top)) 20px calc(28px + env(safe-area-inset-bottom)); + margin: 0; + min-height: 100dvh; + display: flex; + flex-direction: column; + justify-content: center; + } + } + + &__close { + position: absolute; + top: 8px; + right: 8px; + width: 44px; + height: 44px; + border-radius: 50%; + border: none; + background: #f1f5f9; + color: #475569; + font-size: 24px; + line-height: 1; + cursor: pointer; + font-family: inherit; + transition: background .15s; + -webkit-appearance: none; + + &:hover { background: #e2e8f0; } + } + + &__title { + font-size: 20px; + font-weight: 700; + color: #0f172a; + margin: 4px 0 6px; + } + + &__sub { + font-size: 14px; + color: #64748b; + margin: 0 0 18px; + } + + &__hint { + font-size: 13px; + color: #94a3b8; + margin: 14px 0 0; + } + + &__error { + font-size: 13px; + color: #ef4444; + font-weight: 500; + margin: 12px 0 0; + } + + &__success { + padding: 12px 0 4px; + + svg { display: block; margin: 0 auto 10px; } + } +} + +.qr { + display: flex; + align-items: center; + justify-content: center; + background: #f8fafc; + border: 2px solid #e2e8f0; + border-radius: 16px; + padding: 12px; + width: 264px; + height: 264px; + max-width: 100%; + margin: 0 auto; + + @media (max-width: 380px) { + width: min(264px, 70vw); + height: auto; + aspect-ratio: 1; + } + + &__placeholder { + color: #94a3b8; + font-size: 14px; + } + + img { + width: 100%; + height: auto; + max-width: 240px; + display: block; + } +} + +.tg-link { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + margin-top: 16px; + padding: 14px 22px; + min-height: 48px; + border-radius: 12px; + background: #229ED9; + color: #fff; + font-size: 15px; + font-weight: 700; + text-decoration: none; + transition: opacity .15s; + + &:hover { opacity: .9; } + &:active { transform: scale(.97); } +} + +@keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes pop-in { + from { transform: translateY(12px) scale(.98); opacity: 0; } + to { transform: translateY(0) scale(1); opacity: 1; } +} diff --git a/src/app/pages/fastcheck-page/fastcheck-page.ts b/src/app/pages/fastcheck-page/fastcheck-page.ts new file mode 100644 index 0000000..90b5f0d --- /dev/null +++ b/src/app/pages/fastcheck-page/fastcheck-page.ts @@ -0,0 +1,293 @@ +import { Component, computed, inject, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { Router, RouterLink } from '@angular/router'; +import { HttpClient } from '@angular/common/http'; +import { FastcheckService } from '../../fastcheck.service'; +import { FASTCHECK_API } from '../../api'; +import { TranslatePipe } from '../../translate/translate.pipe'; +import { TranslationService } from '../../translate/translation.service'; + +interface WebSessionResponse { + sessionId: string; + userId: string; + expires: string; + userSessionId: string; + Status: boolean; +} + +interface CheckFastcheckResponse { + id: string; + code: string; + owneID: string; + amount: number; + currency: string; + createdAt: string; + creattransactionID: string; + firedAT: string; + firetransactionID: string; +} + +@Component({ + selector: 'app-fastcheck-page', + imports: [FormsModule, RouterLink, TranslatePipe], + templateUrl: './fastcheck-page.html', + styleUrl: './fastcheck-page.scss' +}) +export class FastcheckPage { + private http = inject(HttpClient); + private store = inject(FastcheckService); + private router = inject(Router); + private i18n = inject(TranslationService); + + private t(key: string): string { return this.i18n.translate(key); } + + // Telegram bot used for the sign-in deep link. + private readonly telegramBot = 'DexarSupport_bot'; + + fastcheckNumber = signal(''); + fastcheckAmount = signal(null); + fastcheckCode = signal(''); + codeEnabled = signal(false); + error = signal(''); + amountLoading = signal(false); + + popupOpen = signal(false); + popupLoading = signal(false); + popupError = signal(''); + webSessionId = signal(''); + paid = signal(false); + private pollHandle: ReturnType | null = null; + private lastLookedUpNumber = ''; + + canPay = computed(() => { + const digits = this.fastcheckNumber().replace(/\D/g, ''); + const codeDigits = this.fastcheckCode().replace(/\D/g, ''); + return digits.length === 18 && codeDigits.length === 6 + && this.codeEnabled() && !this.amountLoading(); + }); + + telegramLink = computed(() => { + const sid = this.webSessionId(); + return sid + ? `https://t.me/${this.telegramBot}?start=${encodeURIComponent(sid)}` + : `https://t.me/${this.telegramBot}`; + }); + + qrUrl = computed(() => { + const link = this.telegramLink(); + return `https://api.qrserver.com/v1/create-qr-code/?size=240x240&margin=8&data=${encodeURIComponent(link)}`; + }); + + get isMobile(): boolean { + return typeof window !== 'undefined' && window.innerWidth < 768; + } + + constructor() { + // Pull autofill data: prefer router navigation state, fall back to service. + const navState = typeof window !== 'undefined' ? (window.history?.state ?? {}) : {}; + const created = (navState?.fastcheck) + ? { fastcheck: navState.fastcheck, code: navState.code ?? '', amount: navState.amount ?? null, expiration: navState.expiration } + : this.store.consume(); + + if (created) { + this.fastcheckNumber.set(created.fastcheck); + this.fastcheckAmount.set(created.amount); + this.fastcheckCode.set(created.code); + this.codeEnabled.set(true); + } + + // ?iid=xxxxxx-xxxxxx-xxxxxx — auto-fill and trigger lookup + const iidParam = new URLSearchParams(window.location.search).get('iid') ?? ''; + if (iidParam && !created) { + const digits = iidParam.replace(/\D/g, '').slice(0, 18); + const groups: string[] = []; + for (let i = 0; i < digits.length; i += 6) groups.push(digits.slice(i, i + 6)); + const masked = groups.join('-'); + this.fastcheckNumber.set(masked); + if (digits.length === 18) this.lookupFastcheck(masked); + } + } + + pay(): void { + if (!this.canPay()) { + return; + } + this.error.set(''); + this.openPopup(); + } + + private openPopup(): void { + this.popupOpen.set(true); + this.popupError.set(''); + this.paid.set(false); + this.popupLoading.set(true); + + this.http.get(`${FASTCHECK_API}/websession`).subscribe({ + next: (res) => { + this.popupLoading.set(false); + this.webSessionId.set(res.sessionId); + if (this.isMobile) { + window.location.href = `https://t.me/${this.telegramBot}?start=${encodeURIComponent(res.sessionId)}`; + } else { + this.startPolling(res.sessionId); + } + }, + error: () => { + this.popupLoading.set(false); + this.popupError.set(this.t('errors.session_failed')); + } + }); + } + + closePopup(): void { + this.popupOpen.set(false); + this.stopPolling(); + if (this.webSessionId()) { + // Best-effort logout; ignore errors. + this.http + .request('DELETE', `${FASTCHECK_API}/websession/${this.webSessionId()}`, { + body: { sessionId: this.webSessionId() } + }) + .subscribe({ error: () => undefined }); + } + this.webSessionId.set(''); + } + + private startPolling(sessionId: string): void { + this.stopPolling(); + this.pollHandle = setInterval(() => { + this.http + .get(`${FASTCHECK_API}/websession/${sessionId}`) + .subscribe({ + next: (res) => { + if (res?.Status) { + this.stopPolling(); + this.acceptFastcheck(sessionId); + } + }, + error: () => undefined + }); + }, 3000); + } + + private stopPolling(): void { + if (this.pollHandle !== null) { + clearInterval(this.pollHandle); + this.pollHandle = null; + } + } + + private acceptFastcheck(sessionId: string): void { + this.popupLoading.set(true); + this.http + .post( + `${FASTCHECK_API}/fastcheck`, + { fastcheck: this.fastcheckNumber().trim(), code: this.fastcheckCode().trim() }, + { headers: { Authorization: JSON.stringify({ sessionID: sessionId }) } } + ) + .subscribe({ + next: () => { + this.popupLoading.set(false); + this.paid.set(true); + // Fire DELETE to mark fastcheck as consumed on the merchant side. + this.http + .delete(`${FASTCHECK_API}/fastcheck/${encodeURIComponent(this.fastcheckNumber())}`) + .subscribe({ error: () => undefined }); + this.fireMerchantCallback(); + }, + error: () => { + this.popupLoading.set(false); + this.popupError.set(this.t('errors.payment_failed')); + } + }); + } + + private fireMerchantCallback(): void { + const params = new URLSearchParams(window.location.search); + const returnUrl = params.get('return_url'); + if (returnUrl) { + setTimeout(() => { + window.location.href = `${returnUrl}${returnUrl.includes('?') ? '&' : '?'}fastcheck=${encodeURIComponent( + this.fastcheckNumber() + )}&status=ok`; + }, 1500); + } + } + + onAmountChange(value: number | null): void { + this.fastcheckAmount.set(value); + } + + /** Mask fastcheck number as XXXXXX-XXXXXX-XXXXXX, allow only digits. */ + onNumberChange(raw: string): void { + const digits = (raw ?? '').replace(/\D/g, '').slice(0, 18); + const groups: string[] = []; + for (let i = 0; i < digits.length; i += 6) { + groups.push(digits.slice(i, i + 6)); + } + const masked = groups.join('-'); + this.fastcheckNumber.set(masked); + this.error.set(''); + + if (digits.length < 18 && this.lastLookedUpNumber) { + this.fastcheckAmount.set(null); + this.codeEnabled.set(false); + this.lastLookedUpNumber = ''; + } + + if (digits.length === 18 && masked !== this.lastLookedUpNumber) { + this.lookupFastcheck(masked); + } + } + + /** Allow only digits, max 6, in the code field. */ + onCodeChange(raw: string): void { + const digits = (raw ?? '').replace(/\D/g, '').slice(0, 6); + this.fastcheckCode.set(digits); + this.error.set(''); + } + + private lookupFastcheck(number: string): void { + this.lastLookedUpNumber = number; + this.amountLoading.set(true); + this.fastcheckAmount.set(null); + this.codeEnabled.set(false); + + // API doc: GET /fastcheck/ + this.http + .get(`${FASTCHECK_API}/fastcheck/${number}`) + .subscribe({ + next: (res) => { + this.amountLoading.set(false); + if (res?.id) { + this.fastcheckAmount.set(typeof res.amount === 'number' ? res.amount : null); + this.codeEnabled.set(true); + } else { + this.error.set(this.t('errors.not_found')); + this.lastLookedUpNumber = ''; + } + }, + error: (err) => { + this.amountLoading.set(false); + const serverMsg: string | undefined = err?.error?.message; + this.error.set(serverMsg ?? this.t('errors.lookup_failed')); + this.lastLookedUpNumber = ''; + } + }); + } + + shareByEmail(): void { + const num = this.fastcheckNumber(); + const amount = this.fastcheckAmount(); + const subject = encodeURIComponent('fastCHECK'); + const body = encodeURIComponent(`Номер: ${num}\nСумма: ${amount} ₽\nhttps://qr.vitanova.network/`); + window.open(`mailto:?subject=${subject}&body=${body}`, '_blank'); + } + + shareByTelegram(): void { + const num = this.fastcheckNumber(); + const amount = this.fastcheckAmount(); + const text = encodeURIComponent(`fastCHECK: ${num} — ${amount} ₽`); + window.open(`https://t.me/share/url?url=https%3A%2F%2Fqr.vitanova.network%2F&text=${text}`, '_blank'); + } +} diff --git a/src/app/pages/legacy-pay-page/legacy-pay-page.html b/src/app/pages/legacy-pay-page/legacy-pay-page.html new file mode 100644 index 0000000..963379b --- /dev/null +++ b/src/app/pages/legacy-pay-page/legacy-pay-page.html @@ -0,0 +1,93 @@ +
+
+ +
+ +

{{ 'sbp.title' | translate }}

+

{{ 'sbp.subtitle' | translate }}

+
+ +
+ +
+ +
+ + +
+ @if (error()) { + {{ error() }} + } +
+ +
+ 🇷🇺 + RUB + {{ 'sbp.currency_name' | translate }} +
+ +
+ + +
+ + @if (nspkUrl()) { +
+ SBP QR +

Отсканируйте QR-код в приложении вашего банка

+
+ } + + +
+ + +
+
diff --git a/src/app/pages/legacy-pay-page/legacy-pay-page.scss b/src/app/pages/legacy-pay-page/legacy-pay-page.scss new file mode 100644 index 0000000..7af3f29 --- /dev/null +++ b/src/app/pages/legacy-pay-page/legacy-pay-page.scss @@ -0,0 +1,81 @@ +@use './../../../shared' as *; + +.sbp-logo { + display: inline-flex; + align-items: center; + justify-content: center; + background: rgba(255, 255, 255, 0.15); + backdrop-filter: blur(8px); + border-radius: 16px; + padding: 12px 20px; + border: 1px solid rgba(255, 255, 255, 0.25); + margin-bottom: 14px; + + img { + height: 40px; + display: block; + + @media (max-width: 480px) { + height: 34px; + } + } +} + +.currency-badge { + display: flex; + align-items: center; + gap: 10px; + background: #f1f5f9; + border-radius: 12px; + padding: 12px 16px; + margin-bottom: 18px; + + &__flag { font-size: 22px; line-height: 1; } + &__code { font-size: 15px; font-weight: 700; color: #0f172a; } + &__name { font-size: 13px; color: #64748b; margin-left: auto; } +} + +.qr-pay { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + margin-bottom: 20px; + + img { + border-radius: 12px; + border: 1px solid #e2e8f0; + display: block; + } + + &__hint { + font-size: 13px; + color: #64748b; + text-align: center; + margin: 0; + } +} + +.note-input { + width: 100%; + border: 2px solid #e2e8f0; + border-radius: 14px; + background: #f8fafc; + padding: 14px 16px; + font-size: 15px; + font-weight: 500; + color: #0f172a; + font-family: inherit; + resize: vertical; + outline: none; + transition: border-color 0.2s, box-shadow 0.2s, background 0.2s; + line-height: 1.5; + + &::placeholder { color: #cbd5e1; font-weight: 400; } + + &:focus { + border-color: #2563eb; + box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12); + background: #fff; + } +} diff --git a/src/app/pages/legacy-pay-page/legacy-pay-page.ts b/src/app/pages/legacy-pay-page/legacy-pay-page.ts new file mode 100644 index 0000000..f8530e3 --- /dev/null +++ b/src/app/pages/legacy-pay-page/legacy-pay-page.ts @@ -0,0 +1,107 @@ +import { Component, computed, inject, isDevMode, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; +import { HttpClient } from '@angular/common/http'; +import { TranslatePipe } from '../../translate/translate.pipe'; +import { TranslationService } from '../../translate/translation.service'; + +interface LegacyPayResponse { + nspkurl?: string; +} + +/** + * Legacy SBP merchant payment flow. + * Activated when the root URL has `?id=`. + * Mirrors public/payment.html behaviour: + * POST https://qr.vitanova.network:567/qr + * { payment, amount, currency, id, note } -> { payload: '' } + * then window.location.href = payload. + */ +@Component({ + selector: 'app-legacy-pay-page', + imports: [FormsModule, TranslatePipe], + templateUrl: './legacy-pay-page.html', + styleUrl: './legacy-pay-page.scss' +}) +export class LegacyPayPage { + private http = inject(HttpClient); + private route = inject(ActivatedRoute); + private i18n = inject(TranslationService); + + private t(key: string): string { return this.i18n.translate(key); } + + private readonly LEGACY_API = isDevMode() + ? '/proxy/legacy-qr/qr' + : 'https://qr.vitanova.network:567/qr'; + + amount = signal(null); + note = signal(''); + error = signal(''); + loading = signal(false); + nspkUrl = signal(''); + + get isMobile(): boolean { + return window.innerWidth < 768; + } + + paymentId = signal(''); + + canPay = computed(() => { + const a = this.amount(); + return !!this.paymentId() && a !== null && a > 0 && !this.loading(); + }); + + constructor() { + const id = this.route.snapshot.queryParamMap.get('id') ?? ''; + this.paymentId.set(id); + } + + onAmountChange(value: number | null): void { + this.amount.set(value); + if (this.error()) this.error.set(''); + } + + onNoteChange(value: string): void { + this.note.set(value); + } + + pay(): void { + if (!this.canPay()) { + if (!this.paymentId()) { + this.error.set(this.t('errors.not_found')); + } else { + this.error.set(this.t('errors.invalid_amount')); + } + return; + } + this.error.set(''); + this.loading.set(true); + + const body = { + qrtype: 'QRDynamic', + amount: this.amount(), + currency: 'RUB', + partnerqrID: this.paymentId(), + qrDescription: this.note().trim() + }; + + this.http.post(this.LEGACY_API, body).subscribe({ + next: (res) => { + this.loading.set(false); + if (res?.nspkurl) { + if (this.isMobile) { + window.location.href = res.nspkurl; + } else { + this.nspkUrl.set(res.nspkurl); + } + } else { + this.error.set(this.t('errors.payment_failed')); + } + }, + error: () => { + this.loading.set(false); + this.error.set(this.t('errors.lookup_failed')); + } + }); + } +} diff --git a/src/app/pages/partners-page/partners-page.html b/src/app/pages/partners-page/partners-page.html new file mode 100644 index 0000000..314884c --- /dev/null +++ b/src/app/pages/partners-page/partners-page.html @@ -0,0 +1,26 @@ +
+
+

{{ 'partners.title' | translate }}

+

{{ 'partners.lead' | translate }}

+
+ +
+ @for (p of partners; track p.name) { +
+ +
+ {{ p.category | translate }} +

{{ p.name }}

+

📍 {{ p.city }}

+

{{ p.desc | translate }}

+
+
+ } +
+ +
+

{{ 'partners.cta_title' | translate }}

+

{{ 'partners.cta_text' | translate }}

+ {{ 'partners.cta_btn' | translate }} +
+
diff --git a/src/app/pages/partners-page/partners-page.scss b/src/app/pages/partners-page/partners-page.scss new file mode 100644 index 0000000..b45f9d0 --- /dev/null +++ b/src/app/pages/partners-page/partners-page.scss @@ -0,0 +1,146 @@ +:host { + display: block; + background: #f8fafc; + min-height: 100vh; +} + +.info-page { + max-width: 900px; + margin: 0 auto; + padding: 48px 24px 72px; + + @media (max-width: 600px) { + padding: 32px 16px 56px; + } + + &__hero { + margin-bottom: 40px; + border-bottom: 1px solid #e2e8f0; + padding-bottom: 32px; + } + + &__title { + font-size: 32px; + font-weight: 800; + color: #0f172a; + margin: 0 0 12px; + letter-spacing: -0.5px; + + @media (max-width: 600px) { font-size: 26px; } + } + + &__lead { + font-size: 17px; + line-height: 1.7; + color: #475569; + margin: 0; + } +} + +.partners-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 20px; + margin-bottom: 56px; +} + +.partner-card { + display: flex; + gap: 16px; + padding: 22px 20px; + background: #fff; + border: 1px solid #e2e8f0; + border-radius: 16px; + transition: border-color 0.15s, box-shadow 0.15s; + + &:hover { + border-color: #93c5fd; + box-shadow: 0 4px 16px rgba(30, 64, 175, 0.08); + } + + &__logo { + font-size: 36px; + line-height: 1; + flex-shrink: 0; + width: 52px; + height: 52px; + display: flex; + align-items: center; + justify-content: center; + background: #f1f5f9; + border-radius: 12px; + } + + &__body { + display: flex; + flex-direction: column; + gap: 4px; + } + + &__cat { + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.08em; + color: #1e40af; + } + + &__name { + font-size: 16px; + font-weight: 700; + color: #0f172a; + margin: 0; + } + + &__city { + font-size: 13px; + color: #64748b; + margin: 0; + } + + &__desc { + font-size: 13.5px; + line-height: 1.6; + color: #475569; + margin: 4px 0 0; + } +} + +.partners-cta { + text-align: center; + padding: 40px 24px; + background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); + border-radius: 20px; + border: 1px solid #bfdbfe; + + &__title { + font-size: 22px; + font-weight: 800; + color: #1e3a8a; + margin: 0 0 12px; + } + + &__text { + font-size: 15px; + line-height: 1.7; + color: #3b5998; + margin: 0 0 24px; + max-width: 480px; + margin-inline: auto; + margin-bottom: 24px; + } + + &__btn { + display: inline-block; + padding: 12px 28px; + background: #1e40af; + color: #fff; + border-radius: 10px; + font-size: 15px; + font-weight: 700; + text-decoration: none; + transition: background 0.15s; + + &:hover { background: #1d3a9f; } + } +} diff --git a/src/app/pages/partners-page/partners-page.ts b/src/app/pages/partners-page/partners-page.ts new file mode 100644 index 0000000..0d501d1 --- /dev/null +++ b/src/app/pages/partners-page/partners-page.ts @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { TranslatePipe } from '../../translate/translate.pipe'; + +interface Partner { + name: string; + category: string; + city: string; + logo: string; // emoji placeholder until real logos are provided + desc: string; +} + +@Component({ + selector: 'app-partners-page', + imports: [RouterLink, TranslatePipe], + templateUrl: './partners-page.html', + styleUrl: './partners-page.scss' +}) +export class PartnersPage { + partners: Partner[] = [ + { name: 'Vitanova Exchange', category: 'partners.cat_finance', city: 'Ереван', logo: '🏦', desc: 'partners.p1_desc' }, + { name: 'ForEx.am', category: 'partners.cat_finance', city: 'Ереван', logo: '💱', desc: 'partners.p2_desc' }, + { name: 'Dexar Market', category: 'partners.cat_retail', city: 'Москва', logo: '🛒', desc: 'partners.p3_desc' }, + { name: 'City Hotel Yerevan', category: 'partners.cat_hotels', city: 'Ереван', logo: '🏨', desc: 'partners.p4_desc' }, + ]; +} diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts deleted file mode 100644 index 10540c3..0000000 --- a/src/app/services/api.service.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { environment } from '../../environments/environment'; - -@Injectable({ - providedIn: 'root' -}) -export class ApiService { - private readonly API_URL = 'https://api.fastcheck.store'; - - constructor(private http: HttpClient) {} - - ping(): Observable<{ message: string }> { - return this.http.get<{ message: string }>(`${this.API_URL}/ping`); - } - - get(path: string, sessionId?: string): Observable { - const headers = sessionId ? this.createAuthHeaders(sessionId) : undefined; - return this.http.get(`${this.API_URL}${path}`, { headers }); - } - - post(path: string, body: any, sessionId?: string): Observable { - const headers = sessionId ? this.createAuthHeaders(sessionId) : undefined; - return this.http.post(`${this.API_URL}${path}`, body, { headers }); - } - - delete(path: string, sessionId?: string): Observable { - const headers = sessionId ? this.createAuthHeaders(sessionId) : undefined; - return this.http.delete(`${this.API_URL}${path}`, { headers }); - } - - private createAuthHeaders(sessionId: string): HttpHeaders { - return new HttpHeaders({ - 'Authorization': JSON.stringify({ sessionID: sessionId }), - 'Content-Type': 'application/json' - }); - } -} diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts deleted file mode 100644 index 0fd8c05..0000000 --- a/src/app/services/auth.service.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Injectable, signal } from '@angular/core'; -import { Observable, interval, switchMap, takeWhile, tap } from 'rxjs'; -import { ApiService } from './api.service'; -import { WebSession, AuthState } from '../models/session.model'; - -@Injectable({ - providedIn: 'root' -}) -export class AuthService { - private authState = signal({ - isAuthenticated: false, - sessionId: null, - userSessionId: null - }); - - readonly isAuthenticated = this.authState.asReadonly(); - - constructor(private apiService: ApiService) { - this.loadSessionFromStorage(); - } - - createWebSession(): Observable { - return this.apiService.get('/websession'); - } - - checkWebSessionStatus(sessionId: string): Observable { - return this.apiService.get(`/websession/${sessionId}`); - } - - startPolling(sessionId: string): Observable { - return interval(2000).pipe( - switchMap(() => this.checkWebSessionStatus(sessionId)), - tap(session => { - if (session.Status) { - this.setAuthenticated(session); - } - }), - takeWhile(session => !session.Status, true) - ); - } - - deleteWebSession(sessionId: string): Observable { - return this.apiService.delete(`/websession/${sessionId}`, sessionId).pipe( - tap(() => this.clearAuthentication()) - ); - } - - private setAuthenticated(session: WebSession): void { - const state = { - isAuthenticated: true, - sessionId: session.sessionId, - userSessionId: session.userSessionId - }; - this.authState.set(state); - sessionStorage.setItem('authState', JSON.stringify(state)); - } - - private loadSessionFromStorage(): void { - const stored = sessionStorage.getItem('authState'); - if (stored) { - this.authState.set(JSON.parse(stored)); - } - } - - clearAuthentication(): void { - this.authState.set({ - isAuthenticated: false, - sessionId: null, - userSessionId: null - }); - sessionStorage.removeItem('authState'); - } - - getSessionId(): string | null { - return this.authState().sessionId; - } -} diff --git a/src/app/services/fastcheck.service.ts b/src/app/services/fastcheck.service.ts deleted file mode 100644 index 78ce70b..0000000 --- a/src/app/services/fastcheck.service.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable, of } from 'rxjs'; -import { ApiService } from './api.service'; -import { AuthService } from './auth.service'; -import { - FastCheck, - CreateFastCheckRequest, - CreateFastCheckResponse, - AcceptFastCheckRequest, - CheckStatusResponse, - Balance, - FastCheckListResponse -} from '../models/fastcheck.model'; - -@Injectable({ - providedIn: 'root' -}) -export class FastCheckService { - constructor( - private apiService: ApiService, - private authService: AuthService - ) {} - - checkStatus(fastcheckNumber: string): Observable { - return this.apiService.post( - '/fastcheck', - { fastcheck: fastcheckNumber } - ); - } - - createFastCheck(request: CreateFastCheckRequest): Observable { - const sessionId = this.authService.getSessionId(); - if (!sessionId) { - throw new Error('Not authenticated'); - } - return this.apiService.post( - '/fastcheck', - request, - sessionId - ); - } - - acceptFastCheck(request: AcceptFastCheckRequest): Observable<{ message: string }> { - const sessionId = this.authService.getSessionId(); - if (!sessionId) { - throw new Error('Not authenticated'); - } - return this.apiService.post<{ message: string }>( - '/fastcheck', - request, - sessionId - ); - } - - // MOCKED - Backend needs to implement - getBalance(): Observable { - const sessionId = this.authService.getSessionId(); - if (!sessionId) { - throw new Error('Not authenticated'); - } - - // TODO: Replace with real API call - // return this.apiService.get('/balance', sessionId); - - // MOCK DATA - return of({ - balance: 150000, - currency: 'RUB' - }); - } - - // MOCKED - Backend needs to implement - getActiveFastChecks(): Observable { - const sessionId = this.authService.getSessionId(); - if (!sessionId) { - throw new Error('Not authenticated'); - } - - // TODO: Replace with real API call - // return this.apiService.get('/fastcheck/active', sessionId); - - // MOCK DATA - return of({ - checks: [ - { - fastcheck: '4568-1109-3402', - amount: 15000, - currency: 'RUB', - code: '5568', - expiration: '2026-01-26T09:08:18Z', - status: 'active', - createdAt: '2026-01-19T09:08:18Z' - }, - { - fastcheck: '7890-2234-5566', - amount: 25000, - currency: 'RUB', - code: '1234', - expiration: '2026-01-26T10:15:30Z', - status: 'active', - createdAt: '2026-01-19T10:15:30Z' - } - ] - }); - } - - // MOCKED - Backend needs to implement - getFastCheckHistory(): Observable { - const sessionId = this.authService.getSessionId(); - if (!sessionId) { - throw new Error('Not authenticated'); - } - - // TODO: Replace with real API call - // return this.apiService.get('/fastcheck/history', sessionId); - - // MOCK DATA - return of({ - checks: [ - { - fastcheck: '1234-5678-0003', - amount: 5000, - currency: 'RUB', - type: 'created', - createdAt: '2026-01-15T09:08:18Z', - usedAt: '2026-01-15T10:20:00Z', - status: 'used', - expiration: '2026-01-22T09:08:18Z' - }, - { - fastcheck: '9876-5432-0100', - amount: 10000, - currency: 'RUB', - type: 'accepted', - acceptedAt: '2026-01-14T14:30:00Z', - status: 'used', - expiration: '2026-01-21T14:30:00Z' - } - ] - }); - } -} diff --git a/src/app/site-footer/site-footer.html b/src/app/site-footer/site-footer.html new file mode 100644 index 0000000..a38acae --- /dev/null +++ b/src/app/site-footer/site-footer.html @@ -0,0 +1,57 @@ +
+ + + +
diff --git a/src/app/site-footer/site-footer.scss b/src/app/site-footer/site-footer.scss new file mode 100644 index 0000000..5f0beb4 --- /dev/null +++ b/src/app/site-footer/site-footer.scss @@ -0,0 +1,156 @@ +:host { display: block; } + +.site-footer { + background: #0f172a; + color: #94a3b8; + + &__inner { + max-width: 1100px; + margin: 0 auto; + padding: 48px 24px 32px; + display: grid; + grid-template-columns: 2fr 1fr 1fr; + gap: 40px; + + @media (max-width: 860px) { + grid-template-columns: 1fr 1fr; + } + + @media (max-width: 560px) { + grid-template-columns: 1fr; + gap: 32px; + padding: 36px 20px 24px; + } + } + + &__col { + &--brand { + @media (max-width: 860px) { + grid-column: 1 / -1; + } + } + } + + &__brand { + display: inline-flex; + align-items: center; + gap: 10px; + text-decoration: none; + margin-bottom: 14px; + + img { + width: 28px; + height: 28px; + object-fit: contain; + filter: brightness(0) invert(1); + opacity: 0.9; + } + } + + &__wordmark { + font-size: 18px; + letter-spacing: -0.02em; + line-height: 1; + } + + &__desc { + font-size: 13.5px; + line-height: 1.65; + color: #64748b; + max-width: 380px; + } + + &__heading { + font-size: 12px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.8px; + color: #e2e8f0; + margin-bottom: 16px; + } + + &__list { + list-style: none; + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: 18px; + + li { + display: flex; + align-items: center; + gap: 8px; + font-size: 13.5px; + + svg { flex-shrink: 0; opacity: 0.5; } + } + + a { + color: #94a3b8; + text-decoration: none; + transition: color 0.15s; + + &:hover { color: #e2e8f0; } + } + + &--legal { + li { + display: block; + font-size: 12.5px; + color: #64748b; + gap: 0; + } + } + } + + &__note { + font-size: 11px; + color: #475569; + margin-left: 4px; + } + + &__hours { + font-size: 12.5px; + color: #64748b; + line-height: 1.7; + } + + &__address { + color: #475569; + font-size: 12px !important; + line-height: 1.5; + margin-top: 4px; + } + + &__bottom { + border-top: 1px solid #1e293b; + max-width: 1100px; + margin: 0 auto; + padding: 16px 24px; + display: flex; + flex-wrap: wrap; + gap: 6px 24px; + justify-content: space-between; + font-size: 12px; + color: #475569; + + @media (max-width: 560px) { + flex-direction: column; + padding: 14px 20px; + } + } +} + +.wm-fast { + font-weight: 400; + font-size: 0.72em; + color: #64748b; + margin-right: 0.04em; +} +.wm-check { + font-weight: 700; + font-size: 1em; + color: #93c5fd; + text-transform: uppercase; + letter-spacing: 0.03em; +} diff --git a/src/app/site-footer/site-footer.ts b/src/app/site-footer/site-footer.ts new file mode 100644 index 0000000..440a21c --- /dev/null +++ b/src/app/site-footer/site-footer.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { TranslatePipe } from '../translate/translate.pipe'; + +@Component({ + selector: 'app-site-footer', + imports: [TranslatePipe], + templateUrl: './site-footer.html', + styleUrl: './site-footer.scss' +}) +export class SiteFooter { + year = new Date().getFullYear(); +} diff --git a/src/app/site-header/site-header.html b/src/app/site-header/site-header.html new file mode 100644 index 0000000..2f20ca2 --- /dev/null +++ b/src/app/site-header/site-header.html @@ -0,0 +1,98 @@ + diff --git a/src/app/site-header/site-header.scss b/src/app/site-header/site-header.scss new file mode 100644 index 0000000..2db627d --- /dev/null +++ b/src/app/site-header/site-header.scss @@ -0,0 +1,324 @@ +:host { + display: block; + position: sticky; + top: 0; + z-index: 900; +} + +.site-header { + background: #fff; + border-bottom: 1px solid #e2e8f0; + box-shadow: 0 1px 8px rgba(0, 0, 0, 0.06); + + &__inner { + max-width: 1100px; + margin: 0 auto; + padding: 0 24px; + height: 60px; + display: flex; + align-items: center; + gap: 32px; + + @media (max-width: 600px) { + padding: 0 16px; + } + } + + &__brand { + display: inline-flex; + align-items: center; + gap: 10px; + text-decoration: none; + flex-shrink: 0; + + img { + width: 32px; + height: 32px; + object-fit: contain; + } + } + + &__wordmark { + font-size: 18px; + letter-spacing: -0.02em; + white-space: nowrap; + line-height: 1; + } + + &__nav { + display: flex; + align-items: center; + gap: 4px; + margin-left: auto; + + @media (max-width: 600px) { + display: none; + } + } + + &__link { + padding: 8px 14px; + border-radius: 8px; + font-size: 14px; + font-weight: 500; + color: #475569; + text-decoration: none; + transition: background 0.15s, color 0.15s; + + &:hover { + background: #f1f5f9; + color: #0f172a; + } + } + + &__lang { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 5px 10px; + border-radius: 6px; + border: none; + background: transparent; + font-size: 12px; + font-weight: 600; + letter-spacing: 0.04em; + color: #94a3b8; + cursor: pointer; + transition: background 0.15s, color 0.15s; + font-family: inherit; + + &:hover { background: #f1f5f9; color: #475569; } + + &--active { + background: #eff6ff; + color: #1e40af; + } + } + + &__mobile-langs { + display: flex; + gap: 4px; + padding: 8px 14px 4px; + border-top: 1px solid #f1f5f9; + margin-top: 4px; + } + + &__burger { + display: none; + margin-left: auto; + width: 40px; + height: 40px; + border-radius: 8px; + border: none; + background: transparent; + color: #475569; + cursor: pointer; + align-items: center; + justify-content: center; + transition: background 0.15s; + -webkit-appearance: none; + font-family: inherit; + + &:hover { background: #f1f5f9; } + + @media (max-width: 600px) { + display: inline-flex; + } + } + + &__mobile-menu { display: none; } // replaced by .mobile-overlay / .mobile-panel + + &__mobile-link { display: none; } +} + +// Wordmark colours +.wm-fast { + font-weight: 400; + font-size: 0.72em; + color: #64748b; + margin-right: 0.04em; +} +.wm-check { + font-weight: 700; + font-size: 1em; + color: #1e40af; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +// Language dropdown +.lang-select { + position: relative; + flex-shrink: 0; + + @media (max-width: 600px) { + display: none; + } + + &__trigger { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 7px 10px; + border-radius: 8px; + border: 1px solid #e2e8f0; + background: #fff; + font-size: 13px; + font-weight: 600; + color: #334155; + cursor: pointer; + font-family: inherit; + transition: border-color 0.15s, background 0.15s; + white-space: nowrap; + + &:hover { background: #f8fafc; border-color: #cbd5e1; } + } + + &--open &__trigger { + background: #f8fafc; + border-color: #94a3b8; + } + + &__flag { width: 20px; height: 20px; object-fit: cover; border-radius: 2px; flex-shrink: 0; } + + &__code { font-size: 12px; font-weight: 700; letter-spacing: 0.05em; } + + &__chevron { + color: #94a3b8; + transition: transform 0.2s; + } + + &--open &__chevron { transform: rotate(180deg); } + + &__dropdown { + position: absolute; + top: calc(100% + 6px); + right: 0; + min-width: 160px; + background: #fff; + border: 1px solid #e2e8f0; + border-radius: 12px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); + overflow: hidden; + z-index: 1000; + animation: dropdown-in 0.12s ease; + } + + &__option { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + padding: 11px 14px; + border: none; + background: transparent; + font-family: inherit; + font-size: 14px; + font-weight: 500; + color: #334155; + cursor: pointer; + text-align: left; + transition: background 0.12s; + + &:hover { background: #f8fafc; } + + &--active { color: #1e40af; background: #eff6ff; } + } + + &__name { flex: 1; } + + &__check { color: #1e40af; margin-left: auto; flex-shrink: 0; } +} + +@keyframes dropdown-in { + from { opacity: 0; transform: translateY(-6px); } + to { opacity: 1; transform: translateY(0); } +} + +// ── Mobile overlay + drawer ────────────────────────────────────── +.mobile-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.45); + z-index: 998; + animation: overlay-in 0.2s ease; +} + +.mobile-panel { + position: fixed; + top: 0; + right: 0; + height: 100%; + width: min(300px, 85vw); + background: #fff; + z-index: 999; + display: flex; + flex-direction: column; + gap: 2px; + overflow-y: auto; + animation: panel-in 0.22s cubic-bezier(0.4, 0, 0.2, 1); + + &__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 18px 20px 16px; + border-bottom: 1px solid #e2e8f0; + flex-shrink: 0; + } + + &__title { + font-size: 16px; + font-weight: 700; + color: #1e40af; + letter-spacing: 0.02em; + } + + &__close { + display: inline-flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + border-radius: 8px; + border: none; + background: transparent; + color: #64748b; + cursor: pointer; + transition: background 0.15s, color 0.15s; + font-family: inherit; + + &:hover { background: #f1f5f9; color: #0f172a; } + } + + &__link { + display: block; + padding: 14px 20px; + font-size: 15px; + font-weight: 500; + color: #0f172a; + text-decoration: none; + transition: background 0.12s; + border-radius: 0; + + &:hover { background: #f8fafc; } + } + + &__langs { + display: flex; + gap: 6px; + padding: 12px 20px 16px; + border-top: 1px solid #f1f5f9; + margin-top: auto; + } +} + +@keyframes overlay-in { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes panel-in { + from { transform: translateX(100%); } + to { transform: translateX(0); } +} diff --git a/src/app/site-header/site-header.ts b/src/app/site-header/site-header.ts new file mode 100644 index 0000000..7283803 --- /dev/null +++ b/src/app/site-header/site-header.ts @@ -0,0 +1,48 @@ +import { UpperCasePipe } from '@angular/common'; +import { Component, HostListener, inject, signal } from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { TranslatePipe } from '../translate/translate.pipe'; +import { TranslationService, Lang } from '../translate/translation.service'; + +interface LangOption { code: Lang; label: string; flag: string; } + +@Component({ + selector: 'app-site-header', + imports: [RouterLink, TranslatePipe, UpperCasePipe], + templateUrl: './site-header.html', + styleUrl: './site-header.scss' +}) +export class SiteHeader { + private i18n = inject(TranslationService); + + menuOpen = signal(false); + langOpen = signal(false); + currentLang = this.i18n.currentLang; + + langs: LangOption[] = [ + { code: 'ru', label: 'Русский', flag: '/flags/ru.svg' }, + { code: 'en', label: 'English', flag: '/flags/en.svg' }, + { code: 'hy', label: 'Հայերեն', flag: '/flags/arm.svg' }, + ]; + + get activeLang(): LangOption { + return this.langs.find(l => l.code === this.currentLang()) ?? this.langs[0]; + } + + toggleMenu(): void { this.menuOpen.update(v => !v); } + closeMenu(): void { this.menuOpen.set(false); } + toggleLang(): void { this.langOpen.update(v => !v); } + closeLang(): void { this.langOpen.set(false); } + + setLang(lang: Lang): void { + this.i18n.setLanguage(lang); + this.langOpen.set(false); + } + + @HostListener('document:click', ['$event.target']) + onDocClick(target: EventTarget | null): void { + if (!(target instanceof HTMLElement) || !target.closest('.lang-select')) { + this.langOpen.set(false); + } + } +} diff --git a/src/app/translate/translate.pipe.ts b/src/app/translate/translate.pipe.ts new file mode 100644 index 0000000..bebb3ec --- /dev/null +++ b/src/app/translate/translate.pipe.ts @@ -0,0 +1,11 @@ +import { Pipe, PipeTransform, inject } from '@angular/core'; +import { TranslationService } from './translation.service'; + +@Pipe({ name: 'translate', pure: false, standalone: true }) +export class TranslatePipe implements PipeTransform { + private svc = inject(TranslationService); + + transform(key: string): string { + return this.svc.translate(key); + } +} diff --git a/src/app/translate/translation.service.ts b/src/app/translate/translation.service.ts new file mode 100644 index 0000000..c2d6478 --- /dev/null +++ b/src/app/translate/translation.service.ts @@ -0,0 +1,36 @@ +import { Injectable, inject, signal } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +export type Lang = 'ru' | 'en' | 'hy'; +type Translations = Record>; + +@Injectable({ providedIn: 'root' }) +export class TranslationService { + private http = inject(HttpClient); + + currentLang = signal('ru'); + private translations = signal({}); + + constructor() { + this.load('ru'); + } + + setLanguage(lang: Lang): void { + this.currentLang.set(lang); + this.load(lang); + } + + private load(lang: Lang): void { + this.http.get(`/i18n/${lang}.json`).subscribe({ + next: data => this.translations.set(data), + }); + } + + translate(key: string): string { + const dot = key.indexOf('.'); + if (dot === -1) return key; + const section = key.slice(0, dot); + const k = key.slice(dot + 1); + return this.translations()[section]?.[k] ?? key; + } +} diff --git a/src/environments/environment.ts b/src/environments/environment.ts deleted file mode 100644 index 12d5e44..0000000 --- a/src/environments/environment.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const environment = { - production: false, - apiUrl: 'https://api.fastcheck.store' -}; diff --git a/src/index.html b/src/index.html index 4a149a0..bc39507 100644 --- a/src/index.html +++ b/src/index.html @@ -1,11 +1,16 @@ - - + + - FastCheck + fastCHECK - - + + + + + + + diff --git a/src/main.ts b/src/main.ts index 5df75f9..8648ba6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import { bootstrapApplication } from '@angular/platform-browser'; +import { bootstrapApplication } from '@angular/platform-browser'; import { appConfig } from './app/app.config'; import { App } from './app/app'; diff --git a/src/shared.scss b/src/shared.scss new file mode 100644 index 0000000..3fc0239 --- /dev/null +++ b/src/shared.scss @@ -0,0 +1,262 @@ +// Shared page-level styles for the Fastcheck and Create pages. +// Imported via @use './../../../shared' as *; + +.page { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + padding: 16px; + padding-top: max(16px, env(safe-area-inset-top)); + padding-bottom: max(16px, env(safe-area-inset-bottom)); + background: linear-gradient(135deg, #1e40af 0%, #2563eb 40%, #0ea5e9 100%); + + @media (max-width: 480px) { + align-items: stretch; + padding: 0; + } +} + +.card { + background: #ffffff; + border-radius: 24px; + width: 100%; + max-width: 440px; + box-shadow: 0 24px 60px rgba(0, 0, 0, 0.18); + overflow: hidden; + + @media (max-width: 480px) { + border-radius: 0; + max-width: 100%; + box-shadow: none; + flex: 1; + display: flex; + flex-direction: column; + } + + &__header { + background: #ffffff; + padding: 28px 24px 20px; + text-align: center; + border-bottom: 1px solid #e2e8f0; + + @media (max-width: 480px) { + padding-top: calc(28px + env(safe-area-inset-top)); + } + } + + &__title { + color: #0f172a; + font-size: 22px; + font-weight: 700; + margin: 0 0 4px; + letter-spacing: -0.3px; + } + + &__subtitle { + color: #64748b; + font-size: 13px; + margin: 0; + } + + &__brand { + display: block; + margin: 0 auto 10px; + max-width: 220px; + height: auto; + object-fit: contain; + + @media (max-width: 480px) { + max-width: 200px; + } + } + + &__body { + padding: 24px 22px 18px; + + @media (max-width: 480px) { + padding: 22px 18px 16px; + flex: 1; + } + + @media (max-width: 360px) { + padding: 18px 14px 12px; + } + } + + &__footer { + padding: 0 24px 22px; + display: flex; + justify-content: center; + + @media (max-width: 480px) { + padding: 0 18px calc(22px + env(safe-area-inset-bottom)); + } + } +} + +.field { + margin-bottom: 16px; + + &__label { + display: block; + font-size: 12px; + font-weight: 700; + color: #64748b; + margin-bottom: 8px; + text-transform: uppercase; + letter-spacing: 0.6px; + } + + &__error { + display: block; + margin-top: 6px; + font-size: 13px; + color: #ef4444; + font-weight: 500; + } + + &__hint { + display: block; + margin-top: 6px; + font-size: 13px; + color: #64748b; + font-weight: 500; + } +} + +.input-wrap { + display: flex; + align-items: center; + border: 2px solid #e2e8f0; + border-radius: 14px; + background: #f8fafc; + transition: border-color 0.2s, box-shadow 0.2s, background 0.2s; + + &:focus-within { + border-color: #2563eb; + box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12); + background: #fff; + } + + &--error { + border-color: #ef4444; + box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.1); + } + + &__prefix { + padding: 0 4px 0 18px; + font-size: 24px; + font-weight: 700; + color: #2563eb; + user-select: none; + line-height: 1; + } + + &__input { + flex: 1; + border: none; + background: transparent; + padding: 14px 14px 14px 8px; + font-size: 28px; + font-weight: 700; + color: #0f172a; + outline: none; + min-width: 0; + font-family: inherit; + appearance: textfield; + -moz-appearance: textfield; + + &::placeholder { color: #cbd5e1; } + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + + @media (max-width: 480px) { + font-size: 26px; + padding: 12px 12px 12px 6px; + } + } +} + +.pay-btn { + width: 100%; + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + padding: 16px 24px; + min-height: 52px; + background: linear-gradient(135deg, #1e40af 0%, #2563eb 100%); + color: #fff; + border: none; + border-radius: 14px; + font-size: 16px; + font-weight: 700; + letter-spacing: 0.2px; + cursor: pointer; + transition: opacity 0.15s, transform 0.1s, box-shadow 0.15s; + box-shadow: 0 6px 20px rgba(37, 99, 235, 0.38); + font-family: inherit; + appearance: none; + -webkit-appearance: none; + + &:hover { opacity: 0.92; box-shadow: 0 8px 28px rgba(37, 99, 235, 0.45); } + &:active { transform: scale(0.98); opacity: 0.88; } + &:disabled { opacity: 0.55; cursor: not-allowed; transform: none; } + + &__icon { display: flex; align-items: center; } +} + +.secure-badge { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 12px; + color: #94a3b8; + font-weight: 500; + + svg { flex-shrink: 0; } +} + +// ─── Brand wordmark: "fastCHECK" inline ───────────────────────────────────── +// "fast" sits a bit smaller and lighter than "CHECK". +.brand { + display: inline-flex; + align-items: baseline; + font-weight: inherit; + letter-spacing: -0.02em; + white-space: nowrap; + font-size: calc(1em + 3px); + + &__fast { + font-size: 0.72em; + font-weight: 400; + text-transform: lowercase; + margin-right: 0.05em; + opacity: 0.85; + } + + &__check { + font-size: 1em; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.02em; + } +} + +// Standalone logo image (used inside modal/header) +.brand-logo { + display: block; + height: auto; + object-fit: contain; + user-select: none; + -webkit-user-drag: none; + + &--small { + max-height: 32px; + margin: 0 auto 8px; + } +} diff --git a/src/styles.scss b/src/styles.scss index 87a73d5..7c8f115 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,21 +1,37 @@ -/* You can add global styles to this file, and also import other style files */ - -* { +*, *::before, *::after { + box-sizing: border-box; margin: 0; padding: 0; - box-sizing: border-box; + -webkit-tap-highlight-color: transparent; } html, body { height: 100%; - width: 100%; - margin: 0; - padding: 0; - overflow-x: hidden; +} + +html { + // Prevent iOS rubber-band overscroll showing white background + background: #1e40af; + // Prevent iOS auto-zoom on form fields with small text + -webkit-text-size-adjust: 100%; } body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + background: #1e40af; + // Avoid iOS overscroll bounce leaking other pages on PWA + overscroll-behavior-y: none; +} + +// Disable long-press image saving / callout on payment-method logos +img { + -webkit-touch-callout: none; + user-select: none; +} + +// Inputs: ensure ≥16px font-size to prevent iOS Safari from auto-zooming on focus +input, textarea, select, button { + font-size: 16px; } diff --git a/tsconfig.app.json b/tsconfig.app.json index fb792a9..264f459 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -7,8 +7,7 @@ "types": [] }, "include": [ - "src/**/*.ts", - "src/**/*.html" + "src/**/*.ts" ], "exclude": [ "src/**/*.spec.ts"