commit 3b845c8fcea3e15e4a93f51a116012b1337b24f1 Author: Mikhail Date: Sat May 16 19:03:49 2026 +0300 Initial SFERA platform baseline diff --git a/.codex/instructions.md b/.codex/instructions.md new file mode 100644 index 0000000..50f81c4 --- /dev/null +++ b/.codex/instructions.md @@ -0,0 +1,25 @@ +# Codex Instructions for SFERA + +Путь проекта для Windows-команд: `R:\codex\SFERA`. + +Диск `R:` смонтирован на `\\nas\MST`; используй `R:\codex\SFERA` вместо UNC-пути `\\nas\MST\codex\SFERA`, чтобы Windows/Node/Next не упирались в ограничения сетевого current directory. + +Всегда читай: + +1. `docs/design-system.md` +2. `docs/component-architecture.md` +3. `docs/codex-ui-guidelines.md` + +Перед созданием UI: +- определи бизнес-сущность +- выбери стандартный page pattern +- проверь наличие базовых компонентов +- не создавай новый UI primitive, если есть shadcn/ui компонент +- делай маленькие файлы + +После создания UI: +- добавь loading/error/empty states +- проверь accessibility +- проверь responsive +- проверь TypeScript +- добавь комментарии только там, где они реально помогают diff --git a/.cursor/rules/sfera-ui.mdc b/.cursor/rules/sfera-ui.mdc new file mode 100644 index 0000000..55b6cc8 --- /dev/null +++ b/.cursor/rules/sfera-ui.mdc @@ -0,0 +1,47 @@ +--- +description: SFERA UI rules +globs: + - "src/**/*.tsx" + - "src/**/*.ts" +alwaysApply: true +--- + +# SFERA UI Rules + +Use: +- Next.js +- React +- TypeScript +- Tailwind +- shadcn/ui +- lucide-react +- TanStack Table +- Zod +- React Hook Form + +Do not use: +- Bootstrap +- random colors +- inline styles +- huge components +- business logic inside JSX + +Every page must include: +- loading state +- error state +- empty state +- permission state where applicable + +Visual style: +- enterprise +- minimal +- rounded-2xl +- soft shadows +- clear hierarchy +- dark/light ready + +AI actions must show: +- selected model +- token usage +- project/user limits +- audit log entry diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8a3ace5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +.git +.pytest_cache +.venv +**/__pycache__ +**/*.pyc +frontend/sfera-web/.next +frontend/sfera-web/node_modules +rust/target diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..84f6480 --- /dev/null +++ b/.env.example @@ -0,0 +1,24 @@ +SFERA_ENV=local +SFERA_LOG_LEVEL=INFO +# Optional: path to compiled Rust BSL parser executable. +# Windows example: rust\target\debug\bsl-parser.exe +SFERA_BSL_PARSER= +POSTGRES_DSN=postgresql://sfera:sfera@localhost:5432/sfera +NEO4J_URI=bolt://docker-test.cin.su:17687 +NEO4J_USER=neo4j +NEO4J_PASSWORD=password +QDRANT_URL=http://localhost:6333 +REDIS_URL=redis://localhost:6379/0 + +# Optional local 1C/EDT imports. Do not store infobase passwords here. +RUNTIME_ADAPTER_MODE=mock +RUNTIME_ADAPTER_URL=http://localhost:8010 +ONEC_DESIGNER_PATH=C:\Program Files\1cv8\8.5.1.1150\bin\1cv8.exe +SFERA_EDT_PROJECTS_PATH=C:\EDT\projects +SFERA_UPO_EDT_PATH=C:\EDT\projects\iFCM-UPO\upo\src +SFERA_UPO_INFOBASE='Srvr="192.168.200.95";Ref="upo";' + +# Optional official 1C documentation access. Put real credentials only in .env.local. +SFERA_ITS_URL=https://its.1c.ru/db/v838doc#browse:13:-1:7 +SFERA_ITS_USERNAME= +SFERA_ITS_PASSWORD= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..28c3e49 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: CI + +on: + push: + pull_request: + +jobs: + python: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v4 + - run: uv sync --all-packages + - run: uv run ruff check . + - run: uv run mypy packages services || true + - run: uv run pytest packages/sir/tests + + rust: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: cd rust && cargo test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2418329 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +.venv/ +__pycache__/ +*.egg-info/ +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +target/ +node_modules/ +.next/ +*.tsbuildinfo +.env +.env.local +.env.*.local +.sfera/ +tmp/ +tmp-*/ +api_server_diag.py +*.pyc +*.log +*smoke-debug.png +.DS_Store +.idea/ +.vscode/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..493161f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,20 @@ +# AGENTS.md instructions for SFERA + +## Shared Test Docker Host + +- Test and stand verification must be done on the shared Docker host, not on a local Docker Engine. +- Use SSH alias `test-docker` / `docker-test`. +- Host: `docker-test.cin.su` (`192.168.200.61`). +- SSH user: `test`. +- Preferred Docker endpoint when Docker CLI is available: `ssh://test-docker`. +- Deploy both backend/server services and frontend services on `docker-test` for integrated testing. +- Portainer: `http://docker-test.cin.su:9000/`, user `admin`. +- Do not store the password in repositories or project files; use an SSH key for persistent access. + +## Local Workspace Path + +- The project is available locally at `Z:\codex\SFERA`. +- `Z:\codex\SFERA` is a mapped network folder for `\\nas\MST\codex\SFERA`. +- Prefer `Z:\codex\SFERA` for Windows tooling and frontend commands. +- Do not fall back to UNC current directories for npm/cmd workflows; Windows `cmd.exe` does not support UNC current directories reliably. + diff --git a/CODEX_INSTRUCTIONS.md b/CODEX_INSTRUCTIONS.md new file mode 100644 index 0000000..8a903e5 --- /dev/null +++ b/CODEX_INSTRUCTIONS.md @@ -0,0 +1,72 @@ +# Codex Instructions for SFERA + +Ты реализуешь SFERA по шагам. Не перескакивай к AI и UI, пока не работает semantic core. + +## Абсолютные правила + +1. Не писать autonomous code generation до готового SIR + parser + graph. +2. Каждый parser bug превращать в golden fixture. +3. Не писать напрямую в Neo4j вне `projection-engine`. +4. Все изменения в будущем должны быть связаны с task/session/user, но в Phase 1 можно оставить placeholders. +5. Русский UI и команды по умолчанию, но должен быть выбор английского интерфейса/команд; internal models — English. +6. BSL parser обязан поддерживать смешанный русский/английский синтаксис 1С в одном тексте. +7. Любые integration/security/agent слои делать только после core. + +## Test stand and workspace + +- Тестирование интегрированного проекта проводить на `docker-test` / `test-docker`, а не на локальном Docker Engine. +- На `docker-test` разворачивать обе части: backend/server services и frontend. +- Docker endpoint: `ssh://test-docker`. +- Host: `docker-test.cin.su` (`192.168.200.61`), SSH user: `test`. +- Portainer: `http://docker-test.cin.su:9000/`, user `admin`; пароль не сохранять в репозитории и проектных файлах. +- Локальный рабочий путь проекта: `Z:\codex\SFERA`. +- `Z:\codex\SFERA` — подмонтированная сетевая папка `\\nas\MST\codex\SFERA`. +- Для Windows/npm/frontend команд использовать `Z:\codex\SFERA`, не UNC current directory. + +## Frontend contract + +Перед любым изменением frontend: + +1. Прочитать `docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md`. +2. Прочитать `docs/frontend/SFERA_IDE_UI_CONTRACT.md`. +3. Если меняется дерево 1С - прочитать `docs/frontend/SFERA_METADATA_TREE_CONTRACT.md`. +4. Если меняются настройки проекта - прочитать `docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md`. +5. Если контракт устарел - сначала обновить контракт, затем код. +6. Все UI-изменения фиксировать в `docs/frontend/SFERA_FRONTEND_CHANGELOG.md`. + +Не ломать принятую модель: SFERA = metadata-first semantic configurator for 1C, основной экран = IDE последнего проекта, проект выбирается сверху, левая панель = дерево текущего проекта, основная конфигурация и расширения = configuration-like roots одного уровня, центр = рабочая область, правая панель = контекстные свойства, низ = открытые объекты, tools и status. + +Для 1C-specific поведения использовать official 1C docs через ITS/v8.1c.ru/1C DN или локальные knowledge packs. ITS credentials брать только из `.env.local`; реальные credentials не коммитить, не писать в markdown/Dockerfile и не выводить в logs. + +## Текущий приоритет + +Реализовать Phase 1: + +```text +packages/sir +rust/crates/bsl-parser +packages/semantic-kernel +packages/projection-engine +packages/incremental-indexer +``` + +## Стиль кода + +- Python 3.12+. +- Pydantic v2. +- Async где есть IO. +- Rust parser сначала простой и детерминированный. +- Тесты обязательны. +- Минимальная магия. + +## Definition of Done Phase 1 + +```text +1. BSL procedures extracted. +2. Calls extracted. +3. Queries extracted. +4. Writes extracted. +5. SIR snapshot validates. +6. Neo4j projection works. +7. Incremental update works on changed file. +``` diff --git a/PROJECT_OVERVIEW.md b/PROJECT_OVERVIEW.md new file mode 100644 index 0000000..b29fc65 --- /dev/null +++ b/PROJECT_OVERVIEW.md @@ -0,0 +1,95 @@ +# SFERA — полный анализ проекта для Codex + +## Что строим + +SFERA — серверная semantic SDLC платформа для 1С: + +- semantic graph 1С-конфигурации; +- полноценная IDE-среда для ручной и AI-assisted разработки 1С; +- object-level versioning вместо обязательного Git; +- task-linked изменения; +- review/impact/runtime intelligence; +- knowledge-aware AI, который умеет анализировать, писать и изменять 1С-код и metadata; +- агенты EPF/CFE; +- marketplace/download center; +- многопользовательская серверная консоль. + +## Продуктовая формула + +```text +SIR + Lineage + Object Versioning + Runtime Overlay + Knowledge Base + Collaboration +``` + +Расширенная формула продукта: + +```text +Semantic Core + 1C IDE + AI Pair Programmer + Object/Form Designer + Guarded Apply +``` + +## Что не делаем в начале + +- автоприменение изменений в production; +- автономное применение AI-изменений без preview/diff/approval; +- полный live debugger; +- сложную marketplace-экосистему; +- heavy frontend до ядра. + +## IDE и authoring стратегия + +SFERA должна уметь всё, что ожидается от современной IDE для 1С, но опираясь на semantic graph и структуру конфигурации: + +- ручное редактирование BSL-кода с подсветкой, диагностикой, навигацией, поиском ссылок и refactoring; +- AI autocomplete и продолжение кода с учётом текущей процедуры, локальных переменных, параметров, доступных реквизитов, табличных частей, форм, команд, ролей и связей объекта; +- AI generation для процедур, функций, обработчиков команд, запросов, движений регистров и безопасных шаблонов 1С; +- создание и изменение объектов 1С: документы, справочники, регистры, общие модули, реквизиты, табличные части, команды, формы и отчёты; +- visual/object designer для metadata, форм, команд, реквизитов, табличных частей и отчётов; +- preview/diff всех изменений перед применением; +- guarded apply: проверка impact, прав, privacy, review findings, style rules и AI policy до записи изменений; +- AI объясняет, почему предлагает именно такой код, какие объекты будут затронуты и какие риски есть. + +## Что берём из 1С Конфигуратора + +SFERA не копирует старый интерфейс Конфигуратора, но сохраняет его сильную рабочую модель, знакомую 1С-разработчикам: + +- дерево конфигурации как основной навигатор по метаданным, модулям, формам, реквизитам, командам, ролям и регистрам; +- отдельные рабочие режимы для модуля, формы, реквизитов/табличных частей, команд, свойств, событий и обработчиков; +- вкладки открытых объектов и быстрый переход между модулем объекта, модулем формы, дизайнером формы, свойствами и событиями; +- правый инспектор свойств/событий, который меняет содержимое по выбранному объекту или элементу формы; +- нижние панели проблем, ссылок, output, preview, diff и статуса выполнения; +- поиск по дереву, объектам, процедурам, событиям, формам и документации. + +Поверх этой модели SFERA добавляет то, чего нет в классическом Конфигураторе как единой среды: + +- object-level версии и rollback для каждого изменения; +- semantic diff, impact analysis и guarded apply перед записью; +- документацию проекта, vendor/BSP docs, базу знаний, паттерны команды и историю решений прямо в IDE; +- обучение и подсказки для разработчиков по текущему объекту, коду и стандартам команды; +- AI pair programmer, который умеет читать контекст 1С, писать код, создавать объекты/формы/отчёты и объяснять риски; +- task/session binding, audit trail, права доступа, privacy policy и учёт AI token/cost impact. + +## Первый технический proof + +```text +BSL file +↓ +Rust parser +↓ +SIR Snapshot +↓ +Neo4j graph +↓ +find_callers / find_callees +``` + +## Языковая стратегия + +- UI по умолчанию русский. +- В интерфейсе и командах русский язык используется по умолчанию. +- Пользователь должен иметь возможность выбрать английский язык интерфейса и английский вариант написания команд. +- Внутренний код/модели — английский. +- BSL parser обязан понимать русские и английские ключевые слова: `Процедура/Procedure`, `Функция/Function`, `КонецПроцедуры/EndProcedure` и т.д. +- В одном BSL-тексте 1С допустима смесь русских и английских ключевых слов/команд; SFERA обязана это поддерживать. + +## Git strategy + +Git не является обязательным source of truth. История SFERA хранится в Semantic Object Version Store. Git — только optional import/export adapter. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8f6191 --- /dev/null +++ b/README.md @@ -0,0 +1,726 @@ +# SFERA Platform + +**SFERA — Semantic Operating Platform for 1C Ecosystems** + +SFERA — enterprise semantic platform для анализа, понимания, индексирования, визуализации и AI-оркестрации экосистем 1С. + +SFERA также является современной IDE/authoring-средой для 1С: пользователь должен уметь вручную писать код, создавать и менять объекты, формы, команды и отчёты, а AI должен помогать как pair programmer, который видит текущий код, metadata, связи объектов, доступные переменные и правила платформы. + +Платформа строит детерминированное semantic core ядро поверх: +- 1C BSL +- XML metadata +- CF/CFE +- integrations +- access topology +- UI semantics +- scheduled jobs +- object dependencies +- runtime graph + +SFERA проектируется как: + +```text +Enterprise AI Operating System +for 1C ecosystems +``` + +--- + +# Core Philosophy + +```text +Semantic truth first. +AI later. +``` + +AI не является источником истины. + +Сначала: +- deterministic parsing +- semantic graph +- metadata topology +- impact analysis +- dependency resolution +- integration discovery +- access analysis + +И только потом: +- AI copilots +- AI review +- AI reasoning +- AI onboarding +- AI architecture analysis +- AI migration planning + +--- + +# High-Level Architecture + +```text +1C BSL/XML/CF/CFE + ↓ +Rust BSL Parser + ↓ +SIR Snapshot + ↓ +Semantic Kernel + ↓ +Neo4j Semantic Graph + ↓ +Incremental Indexing + ↓ +Impact Analysis + ↓ +AI Operating Layer +``` + +--- + +# Main Goals + +## Semantic Understanding of 1C + +SFERA должна понимать: + +- объекты 1С +- формы +- команды +- реквизиты +- табличные части +- роли +- права доступа +- BSL dependencies +- integrations +- scheduled jobs +- runtime topology +- object impact +- UI semantics + +--- + +## 1C IDE and Authoring + +SFERA должна давать возможности современной IDE для 1С: + +- BSL editor: подсветка, диагностика, folding, outline, go to definition, find references, rename, extract method и безопасные refactoring actions. +- Semantic autocomplete: продолжение кода с учётом текущей процедуры, параметров, локальных переменных, реквизитов объекта, табличных частей, форм, команд, ролей, интеграций и доступных методов 1С. +- AI pair programmer: генерация процедур, функций, запросов, обработчиков команд, движений регистров, проверок заполнения и обработчиков форм. +- Object designer: создание и изменение документов, справочников, регистров, общих модулей, реквизитов, табличных частей, команд и форм. +- Form/report designer: работа с формами, элементами, командами, обработчиками и отчётами в visual/object-oriented интерфейсе. +- Diff/preview/apply: любое AI- или ручное изменение проходит через preview, semantic diff, impact analysis, review и подтверждение. +- Context-aware hints: подсказки не просто по словам, а по текущему объекту 1С, доступным данным, связям, query/write context и runtime/knowledge facts. + +AI не ограничивается анализом. Он должен уметь писать код и предлагать структурные изменения, но SFERA обязана показывать последствия и держать контроль применения у пользователя. + +--- + +## Enterprise AI Layer + +Поверх semantic graph строится AI operating layer: + +- AI code completion +- AI code generation +- AI object/form/report generation +- AI guarded refactoring +- AI code review +- AI impact analysis +- AI onboarding +- AI architecture assistant +- AI dependency explorer +- AI migration assistant +- AI semantic search +- AI documentation generation +- AI risk analysis +- AI integration analysis + +AI должен работать поверх semantic truth: перед предложением кода он учитывает текущий BSL-контекст, AST/SIR, metadata object, форму, доступные реквизиты, табличные части, команды, роли, запросы, регистры, интеграции, knowledge records и privacy policy. + +--- + +## 1C Knowledge Coverage + +`GET /projects/{project_id}/knowledge/schema-coverage` показывает покрытие knowledge-records для документов, справочников, реквизитов и табличных частей. + +`GET /projects/{project_id}/review` добавляет INFO `Missing 1C schema knowledge`, если узел схемы 1С не связан ни с одной knowledge-записью. + +`POST /knowledge/packs` импортирует BSP/vendor documentation pack как набор `KnowledgeRecord` с тегами `pack:{pack_id}` и `vendor:{vendor}`. `GET /knowledge/packs` показывает установленные пакеты знаний. + +`GET /projects/{project_id}/patterns` выполняет детерминированный pattern mining по SIR: повторяющиеся чтения таблиц, записи таблиц и совпадающие read/write формы процедур. + +## 1C Ownership + +`POST /projects/{project_id}/comments` добавляет обсуждение к `target_id` внутри проекта, а `GET /projects/{project_id}/comments/{target_id}` возвращает комментарии по конкретному объекту, задаче или lineage. + +`POST /projects/{project_id}/ownership` назначает ответственного на 1С-объект по `lineage_id`. + +`GET /projects/{project_id}/objects/ownership/{object_name}` возвращает владельцев документа, справочника, регистра, общего модуля и других корневых объектов 1С. + +`GET /projects/{project_id}/review` добавляет INFO `Missing 1C object owner` для 1С-объектов без назначенного владельца, а `GET /projects/{project_id}/report` включает `ownership_count`, `unowned_object_count` и `unowned_objects`. + +## 1C Privacy + +`POST /projects/{project_id}/privacy/markers` назначает privacy-классификацию на `lineage_id`: `PUBLIC`, `INTERNAL`, `CONFIDENTIAL`, `PERSONAL_DATA`, `SECRET`. + +`GET /projects/{project_id}/objects/privacy/{object_name}` возвращает privacy-маркеры самого 1С-объекта и его прямых реквизитов/табличных частей/форм. + +`GET /projects/{project_id}/review` добавляет INFO `Unclassified sensitive 1C field` для реквизитов с чувствительными именами вроде ИНН, паспорт, телефон, email, адрес, если они ещё не классифицированы. + +## AI Usage Governance + +`POST /ai/usage` записывает факт AI-действия: проект, пользователь, модель, операция, prompt/completion токены и стоимость. + +`GET /ai/usage/summary` агрегирует AI usage по проекту, пользователю, модели и операции. `GET /ai/policy` показывает текущий token limit и остаток для пользователя. + +`GET /projects/{project_id}/report` включает `ai_usage_request_count`, `ai_usage_total_tokens` и `ai_usage_cost`. + +`POST /projects/{project_id}/ai/answer-policy` проверяет, можно ли отвечать на AI-вопрос по выбранному 1С-контексту: учитывает token budget, knowledge records, privacy markers и запрет external model calls. + +--- + +# Monorepo Structure + +```text +sfera-platform/ + +packages/ + bsl-parser-rs/ + sir/ + semantic-kernel/ + neo4j-projection/ + indexing/ + integrations/ + api/ + ai/ + +frontend/ + sfera-web/ + +docs/ + architecture/ + frontend/ + operations/ + ai/ + prompts/ + +.codex/ +.cursor/ +``` + +--- + +# Technology Stack + +## Backend + +```text +Python +FastAPI +Rust +Neo4j +PostgreSQL +Pydantic +NetworkX +asyncio +uv +``` + +## Frontend + +```text +Next.js +React +TypeScript +Tailwind CSS +shadcn/ui +TanStack Table +TanStack Query +Zustand +Framer Motion +Recharts / ECharts +``` + +## AI Layer + +```text +OpenAI-compatible APIs +Local LLM support +Multi-model routing +AI policy engine +AI audit system +Context orchestration +Token accounting +Semantic AI routing +``` + +--- + +# Quick Start + +## Environment + +```bash +cp .env.example .env +uv sync --all-packages +``` + +## Run tests + +```bash +pytest packages/sir/tests +``` + +## Run Rust parser + +```bash +cargo run -p bsl-parser -- ../tests/golden/english_module.bsl +``` + +--- + +# Development Philosophy + +SFERA строится как: + +```text +Deterministic semantic platform first. +AI-enhanced operating system second. +``` + +Главный приоритет: +- reproducibility +- deterministic parsing +- semantic correctness +- graph consistency +- auditability +- incremental scalability + +--- + +# Semantic Intermediate Representation (SIR) + +Rust parser возвращает deterministic JSON contract: + +```json +{ + "procedures": [], + "calls": [], + "queries": [], + "writes": [], + "diagnostics": [] +} +``` + +SIR является semantic truth snapshot проекта. + +--- + +# Supported 1C Metadata + +## Core metadata objects + +```text +Catalog +Document +Register +CommonModule +ExchangePlan +ScheduledJob +BusinessProcess +Task +Role +Form +Command +Attribute +TabularSection +Element +``` + +--- + +# Semantic Graph Relations + +## Main graph relations + +```text +CALLS +WRITES +READS +USES_INTEGRATION +HANDLES +CONTAINS +HAS_FORM +HAS_COMMAND +HAS_ATTRIBUTE +HAS_TABULAR_SECTION +HAS_ROLE +HAS_ELEMENT +RUNS +GRANTS_ACCESS +``` + +--- + +# Object Impact Analysis + +SFERA умеет строить object-level impact: + +- реквизиты +- табличные части +- формы +- команды +- BSL handlers +- registers +- integrations +- scheduled jobs +- roles/access +- UI semantics +- cross-module dependencies + +--- + +# Incremental Indexing + +SFERA поддерживает incremental semantic updates. + +Изменение: +- `.bsl` +- `.xml` +- metadata object +- forms +- handlers + +перестраивает только affected semantic graph sections. + +--- + +# Neo4j Projection + +Semantic graph может быть выгружен в Neo4j: + +```text +SIR Snapshot + ↓ +Neo4j Projection + ↓ +Cypher Queries + ↓ +Graph Analytics +``` + +--- + +# Integration Topology + +SFERA извлекает integrations из: + +- HTTPConnection +- HTTPСоединение +- WSProxy +- FTPConnection +- COMObject +- ExchangePlan +- URL strings +- external services + +--- + +# Scheduled Jobs + +Регламентные задания индексируются как runtime semantic graph: + +```text +ScheduledJob + RUNS +Procedure +``` + +--- + +# Access Model + +Для ролей 1С извлекаются: + +- object permissions +- rights +- grants +- access topology + +Graph relation: + +```text +Role GRANTS_ACCESS Object +``` + +--- + +# UI Semantics + +SFERA анализирует UI layer: + +- forms +- commands +- command handlers +- form elements +- UI actions +- BSL bindings + +--- + +# API Examples + +## Object impact + +```text +GET /projects/{project_id}/objects/impact/{object_name} +``` + +## UI semantics + +```text +GET /projects/{project_id}/objects/ui/{object_name} +``` + +## Integrations + +```text +GET /projects/{project_id}/integrations +``` + +## Scheduled jobs + +```text +GET /projects/{project_id}/jobs/scheduled +``` + +## Access graph + +```text +GET /projects/{project_id}/access/roles/{role_name}/objects +``` + +--- + +# Frontend Philosophy + +SFERA UI — не обычная CRM. + +Интерфейс должен ощущаться как: + +- Linear +- Stripe Dashboard +- Notion +- Attio +- Plane +- Enterprise AI Workspace + +--- + +# Frontend Stack + +```text +Next.js +React +TypeScript +Tailwind CSS +shadcn/ui +TanStack Table +Framer Motion +``` + +--- + +# Enterprise UI Principles + +## Main principles + +- clean enterprise minimalism +- dark/light mode +- modular workspace +- AI-native UX +- semantic navigation +- adaptive layouts +- contextual side panels +- command palette +- realtime analytics + +--- + +# AI-Assisted Development + +Проект проектируется для работы через: + +- Codex +- Cursor +- v0 +- AI code review +- AI UI generation +- AI semantic assistants + +--- + +# Codex Workflow + +В репозитории присутствуют: + +```text +.codex/ +.cursor/ +docs/design-system.md +docs/component-architecture.md +docs/codex-ui-guidelines.md +prompts/ +``` + +Codex обязан: +- соблюдать architecture rules +- соблюдать design system +- генерировать production-ready TypeScript +- использовать reusable components +- учитывать AI limits/audit/token usage + +--- + +# Frontend Design System + +Frontend design system основан на: + +```text +Tailwind CSS +shadcn/ui +Radix UI +Design Tokens +Enterprise Layout Rules +``` + +Основной принцип: + +```text +Enterprise AI Operating System +instead of legacy CRM UI +``` + +--- + +# AI Operating Layer + +Будущие AI возможности: + +- AI semantic copilots +- AI impact prediction +- AI migration planning +- AI documentation generation +- AI integration analysis +- AI security review +- AI onboarding assistant +- AI dependency graph reasoning +- AI runtime diagnostics +- AI topology explorer + +--- + +# Infrastructure + +Docker Engine локально для development stand не обязателен. + +Общий infrastructure host: + +```text +docker-test +test-docker +``` + +Infrastructure documentation: + +```text +docs/operations/STAND_RUNBOOK.md +``` + +--- + +# First Demo Target + +```bsl +Процедура Проведение() + ПроверитьОстатки(); + Движения.ОстаткиТоваров.Записать(); +КонецПроцедуры +``` + +Expected semantic graph: + +```text +Проведение CALLS ПроверитьОстатки +Проведение WRITES РегистрНакопления.ОстаткиТоваров +``` + +--- + +# Long-Term Vision + +SFERA — это не просто analyzer. + +Цель проекта: + +```text +Semantic Operating System +for enterprise 1C ecosystems +``` + +Где: +- semantic graph +- runtime topology +- integrations +- access model +- UI semantics +- AI reasoning +- enterprise workflows +- impact analysis + +становятся единой operating platform. + +--- + +# Core Principles + +```text +Deterministic. +Semantic. +Incremental. +Observable. +AI-Ready. +Enterprise-Scale. +``` + +--- + +# Future Roadmap + +## Phase 1 + +- Rust parser +- SIR +- semantic graph +- Neo4j projection +- incremental indexing + +## Phase 2 + +- semantic APIs +- integrations topology +- access graph +- UI semantics + +## Phase 3 + +- enterprise frontend +- AI copilots +- semantic search +- AI review + +## Phase 4 + +- distributed indexing +- multi-project graph +- semantic federation +- AI orchestration +- autonomous semantic agents diff --git a/docs/1c-metadata-object-catalog.md b/docs/1c-metadata-object-catalog.md new file mode 100644 index 0000000..f1c959f --- /dev/null +++ b/docs/1c-metadata-object-catalog.md @@ -0,0 +1,21 @@ +# 1C Metadata Object Catalog + +This catalog is the product source of truth for the 1C metadata tree. It is backed by the official EDT mdclass metamodel and exposed by `/metadata/catalog`. + +Primary sources: + +- EDT mdclass package: https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/package-summary.html +- EDT HTTPService: https://edt.1c.ru/dev/edt/2024.2/apidocs/com/_1c/g5/v8/dt/metadata/mdclass/HTTPService.html +- 1C HTTP services guide: https://1c-dn.com/1c_enterprise/http_services/ + +Root configuration objects are maintained in `packages/one-c-normalizer/src/one_c_normalizer/metadata_catalog.py` as `METADATA_TYPE_SPECS` plus descriptions in `METADATA_TYPE_DESCRIPTIONS`. + +Child metadata elements are maintained in the same module as `METADATA_CHILD_OBJECT_SPECS`. + +Important documented structures: + +- HTTP service: HTTP service -> URL templates -> methods -> module. +- Web service: Web service -> operations -> parameters -> module. +- Integration service: Integration service -> channels -> messages -> module. +- Registers: register -> dimensions -> resources -> requisites -> forms -> commands -> templates -> rights -> record set/manager modules. +- Catalogs/plans/documents: object -> requisites -> tabular sections -> forms -> commands -> templates -> rights -> modules, with type-specific groups such as movements or predefined data. diff --git a/docs/1c-metadata-structure.md b/docs/1c-metadata-structure.md new file mode 100644 index 0000000..a15995e --- /dev/null +++ b/docs/1c-metadata-structure.md @@ -0,0 +1,411 @@ +# Структура объектов метаданных 1С для дерева SFERA + +Дата фиксации: 2026-05-09. + +Назначение документа: единая опорная модель для загрузчика метаданных из 1С и дерева SFERA IDE. Реальные объекты, имена и состав узлов должны приходить из выгрузки конфигурации 1С/SIR. В коде интерфейса допустимо хранить только типы объектов, правила группировки, иконки и шаблоны подчинённых узлов. + +## Источники + +- 1C:Enterprise 8.3.23 Developer Guide, "Configuration objects": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.2._Configuration_objects/ +- 1C:Enterprise 8.3.23 Developer Guide, "The concept of configuration": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.1._The_concept_of__configuration_/ +- 1C:Enterprise 8.3.23 Developer Guide, "Modules": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.5._Modules/ +- 1C:Enterprise 8.3.23 Developer Guide, "Common attributes": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_5._Configuration_objects/5.3.__Common__configuration_branch/5.3.5._Common_attributes/ +- 1C:Enterprise 8.3.23 Developer Guide, "Functional options": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_5._Configuration_objects/5.3.__Common__configuration_branch/5.3.10._Functional_options_and_functional_option_parameters/ +- 1C:Enterprise 8.3.23 Developer Guide, "Commands": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_6._Command_interface/6.2._Global_command_interface_structure/6.2.2._Commands/ +- 1C:Enterprise 8.3.23 Developer Guide, "Templates": https://kb.1ci.com/1C_Enterprise_Platform/Guides/Developer_Guides/1C_Enterprise_8.3.23_Developer_Guide/Chapter_1._General_concepts/1.3._Basic_concepts/1.3.6._Templates/ + +Отдельной публичной документации `1C:Enterprise 8.5 Developer Guide` на kb.1ci.com при проверке не найдено. До появления официальной ветки 8.5 используем модель 8.3 как базовую и оставляем место под версионные отличия. + +## Принципы дерева + +1. В Designer/Конфигураторе типы объектов метаданных сгруппированы в дереве конфигурации. +2. Объект метаданных описывает структуру и поведение, но не хранит конкретные пользовательские данные. +3. Внутри объектов есть подчинённые объекты: реквизиты, табличные части, формы, команды, макеты, модули, измерения, ресурсы, права и т.д. +4. SFERA не должна создавать плоский список. Дерево строится по типу объекта и подчинённым коллекциям. +5. Узел `Задачи 1С` внутри конфигуратора является типом метаданных 1С. Узел `Задачи` верхнего уровня SFERA является системой разработки. + +## Корневые ветки конфигурации + +```text +Конфигурация +├── Общие +├── Константы +├── Справочники +├── Документы +├── Журналы документов +├── Перечисления +├── Отчеты +├── Обработки +├── Планы видов характеристик +├── Планы счетов +├── Планы видов расчета +├── Регистры сведений +├── Регистры накопления +├── Регистры бухгалтерии +├── Регистры расчета +├── Бизнес-процессы +├── Задачи +├── Внешние источники данных +└── Расширения конфигурации +``` + +## Ветка "Общие" + +```text +Общие +├── Подсистемы +├── Общие модули +├── Параметры сеанса +├── Роли +├── Общие реквизиты +├── Планы обмена +├── Критерии отбора +├── Подписки на события +├── Регламентные задания +├── Функциональные опции +├── Параметры функциональных опций +├── Определяемые типы +├── Хранилища настроек +├── Общие команды +├── Группы команд +├── Общие формы +├── Общие макеты +├── Общие картинки +├── XDTO-пакеты +├── Web-сервисы +├── HTTP-сервисы +├── WS-ссылки +├── WebSocket-клиенты +├── Сервисы интеграции +├── Цвета палитры +├── Элементы стиля +├── Стили +└── Языки +``` + +## Шаблоны подчинённых узлов + +### Справочник + +```text +Справочники +└── <ИмяСправочника> + ├── Реквизиты + ├── Табличные части + │ └── <ИмяТабличнойЧасти> + │ ├── Реквизиты + │ └── Индексы + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль объекта + ├── Модуль менеджера + ├── Права + ├── Предопределенные данные + └── SFERA: Версии / Проверки / Инциденты / Знания +``` + +### Документ + +```text +Документы +└── <ИмяДокумента> + ├── Реквизиты + ├── Табличные части + │ └── <ИмяТабличнойЧасти> + │ ├── Реквизиты + │ └── Индексы + ├── Формы + ├── Команды + ├── Макеты + ├── Движения + │ ├── Регистры сведений + │ ├── Регистры накопления + │ ├── Регистры бухгалтерии + │ └── Регистры расчета + ├── Последовательности + ├── Нумераторы + ├── Модуль объекта + ├── Модуль менеджера + ├── Права + └── SFERA: Версии / Проверки / Инциденты / Знания +``` + +### Журнал документов + +```text +Журналы документов +└── <ИмяЖурнала> + ├── Графы + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль менеджера + └── Права +``` + +### Перечисление + +```text +Перечисления +└── <ИмяПеречисления> + ├── Значения + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль менеджера + └── Права +``` + +### Отчет + +```text +Отчеты +└── <ИмяОтчета> + ├── СКД + │ ├── Наборы данных + │ ├── Запросы + │ ├── Поля + │ ├── Ресурсы + │ ├── Группировки + │ ├── Отборы + │ └── Варианты + ├── Реквизиты + ├── Табличные части + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль объекта + ├── Модуль менеджера + └── Права +``` + +### Обработка + +```text +Обработки +└── <ИмяОбработки> + ├── Реквизиты + ├── Табличные части + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль объекта + ├── Модуль менеджера + └── Права +``` + +### План видов характеристик + +```text +Планы видов характеристик +└── <ИмяПВХ> + ├── Реквизиты + ├── Табличные части + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль объекта + ├── Модуль менеджера + ├── Предопределенные данные + └── Права +``` + +### План счетов + +```text +Планы счетов +└── <ИмяПланаСчетов> + ├── Признаки учета + ├── Признаки учета субконто + ├── Табличные части + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль объекта + ├── Модуль менеджера + ├── Предопределенные данные + └── Права +``` + +### План видов расчета + +```text +Планы видов расчета +└── <ИмяПВР> + ├── Реквизиты + ├── Табличные части + ├── Вытесняющие виды расчета + ├── Ведущие виды расчета + ├── Базовые виды расчета + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль объекта + ├── Модуль менеджера + └── Права +``` + +### Регистр сведений + +```text +Регистры сведений +└── <ИмяРегистра> + ├── Измерения + ├── Ресурсы + ├── Реквизиты + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль набора записей + ├── Модуль менеджера + ├── Кто пишет + ├── Кто читает + └── Права +``` + +### Регистр накопления + +```text +Регистры накопления +└── <ИмяРегистра> + ├── Измерения + ├── Ресурсы + ├── Реквизиты + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль набора записей + ├── Модуль менеджера + ├── Кто пишет + ├── Кто читает + └── Права +``` + +### Регистр бухгалтерии + +```text +Регистры бухгалтерии +└── <ИмяРегистра> + ├── Измерения + ├── Ресурсы + ├── Реквизиты + ├── Признаки учета + ├── Признаки учета субконто + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль набора записей + ├── Модуль менеджера + └── Права +``` + +### Регистр расчета + +```text +Регистры расчета +└── <ИмяРегистра> + ├── Измерения + ├── Ресурсы + ├── Реквизиты + ├── Перерасчеты + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль набора записей + ├── Модуль менеджера + └── Права +``` + +### Бизнес-процесс + +```text +Бизнес-процессы +└── <ИмяБизнесПроцесса> + ├── Реквизиты + ├── Табличные части + ├── Карта маршрута + ├── Точки маршрута + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль объекта + ├── Модуль менеджера + └── Права +``` + +### Задача 1С + +```text +Задачи +└── <ИмяЗадачи> + ├── Реквизиты + ├── Табличные части + ├── Адресация + ├── Формы + ├── Команды + ├── Макеты + ├── Модуль объекта + ├── Модуль менеджера + └── Права +``` + +### Внешний источник данных + +```text +Внешние источники данных +└── <ИмяИсточника> + ├── Таблицы + │ └── <ИмяТаблицы> + │ └── Поля + ├── Кубы + ├── Функции + ├── Формы + ├── Команды + └── Макеты +``` + +## Универсальные подчинённые узлы + +Эти узлы могут встречаться у разных типов объектов. Загрузчик должен брать фактический состав из 1С, а не создавать все узлы всегда. + +- `Реквизиты` +- `Табличные части` +- `Формы` +- `Команды` +- `Макеты` +- `Модуль объекта` +- `Модуль менеджера` +- `Модуль набора записей` +- `Права` +- `Предопределенные данные` +- `Измерения` +- `Ресурсы` +- `Графы` +- `Значения` +- `Перерасчеты` +- `Движения` +- `Адресация` +- `СКД` +- `URL-шаблоны` +- `Методы` +- `Контракты` +- `Обработчики` + +## Правило для SFERA + +Загрузчик метаданных должен сохранять: + +- `metadata_type`: тип объекта 1С; +- `name`: имя объекта из конфигурации; +- `synonym`: синоним; +- `qualified_name`: полное имя вида `Документ.Имя`, `Справочник.Имя.Форма.ФормаЭлемента`; +- `parent`: родительский узел; +- `children`: подчинённые коллекции; +- `module_kind`: тип модуля, если узел является модулем; +- `rights`: права/ограничения доступа; +- `extension_origin`: основная конфигурация или расширение; +- `version_origin`: снимок/версия/задача; +- `sfera_overlays`: проверки, инциденты, знания, владельцы, runtime-события. + +UI-дерево обязано строиться из этой структуры. Любые демонстрационные имена объектов должны быть заменены данными из SIR после подключения реального загрузчика. diff --git a/docs/CODEX_INSTRUCTIONS.md b/docs/CODEX_INSTRUCTIONS.md new file mode 100644 index 0000000..10cfbde --- /dev/null +++ b/docs/CODEX_INSTRUCTIONS.md @@ -0,0 +1,46 @@ +# Codex Instructions for SFERA Docs + +## Frontend Contract Rules + +Перед любым изменением frontend: + +1. Прочитать `docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md`. +2. Прочитать `docs/frontend/SFERA_IDE_UI_CONTRACT.md`. +3. Если меняется дерево 1С - прочитать `docs/frontend/SFERA_METADATA_TREE_CONTRACT.md`. +4. Если меняются настройки проекта - прочитать `docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md`. +5. Если контракт устарел - сначала обновить контракт, затем код. +6. Все UI-изменения фиксировать в `docs/frontend/SFERA_FRONTEND_CHANGELOG.md`. + +Frontend SFERA нельзя переводить в dashboard, CRM или файловый редактор. Принятая модель сохраняется: + +- SFERA = metadata-first semantic configurator for 1C; +- основной экран = IDE последнего проекта; +- проект выбирается сверху; +- левая панель = дерево текущего проекта; +- основная конфигурация и расширения = configuration-like roots одного уровня; +- центр = рабочая область; +- правая панель = контекстные свойства; +- низ = открытые объекты, tools и status. + +Для 1C-specific поведения использовать официальную документацию: + +- ITS; +- v8.1c.ru; +- 1C DN; +- локальные knowledge packs. + +ITS credentials передаются только через `.env.local`: + +```dotenv +SFERA_ITS_URL= +SFERA_ITS_USERNAME= +SFERA_ITS_PASSWORD= +``` + +Запрещено: + +- хранить реальные ITS credentials в репозитории; +- писать реальные логины или пароли в markdown; +- писать реальные логины или пароли в Dockerfile; +- выводить реальные логины или пароли в logs; +- коммитить `.env.local` и `.env.*.local`. diff --git a/docs/architecture/ARCHITECTURE_INDEX.md b/docs/architecture/ARCHITECTURE_INDEX.md new file mode 100644 index 0000000..693762c --- /dev/null +++ b/docs/architecture/ARCHITECTURE_INDEX.md @@ -0,0 +1,104 @@ +# Architecture Index + +## Core +- SIR +- Rust Parser + - `rust/crates/bsl-parser` + - JSON CLI contract: `cargo run -p bsl-parser -- ` + - output sections: `procedures`, `calls`, `queries`, `writes`, `diagnostics` +- Semantic Kernel +- Projection Engine +- Incremental Indexer + - project-level delta rebuild for 1C `.bsl` and `.xml` + - preserves metadata object links and object-level impact consistency + - refreshes Neo4j projection after incremental updates for already-projected projects +- Impact Engine + - routine-level impact + - 1C object-level impact from metadata owner to attributes/tabular sections/tabular section columns/modules/routines/tables/writes/forms/commands/command handlers + - role access included in object impact + - in-memory and Neo4j API surfaces + +## 1C Native +- Designer CLI adapter primary +- EDT optional +- EPF/CFE agent later +- XML metadata extraction + - Catalog / Document / Register / CommonModule + - ExchangePlan / ScheduledJob / BusinessProcess / Task / Role + - Form / Command / Attribute / TabularSection / Element + - Role rights as `GRANTS_ACCESS` edges + - metadata object `CONTAINS` BSL module links from 1C export paths + - Form commands linked to BSL handlers with `HANDLES` + - Object-scoped UI API for 1C forms, commands, elements, and handlers + - Scheduled jobs linked to routines with `RUNS` + - Integration topology from BSL and XML ExchangePlan metadata + - BSL integrations as `INTEGRATION_ENDPOINT` nodes and `USES_INTEGRATION` edges + +## Versioning +- Semantic Object Store primary +- Git optional adapter + +## Knowledge +- Global / Workspace / Project / Session scopes +- Knowledge packs + - BSP/vendor documentation pack import + - pack/vendor metadata enrichment for records +- Vendor configs +- BSP detection +- 1C schema knowledge coverage + - review findings for schema nodes without knowledge records +- Pattern mining + - repeated table read/write patterns + - repeated routine IO shapes + +## Collaboration +- Users / workspaces / projects +- Tasks / active task context / change sessions +- Comments / discussions + - project comments API + - target-scoped discussion lookup +- Activity feed +- 1C object ownership + - project ownership API + - object-scoped owner lookup + - persisted ownership assignments + +## Governance +- RBAC +- 1C role rights graph + - object -> roles access API + - role -> objects access API + - project report security summary + - review warnings for objects without role access +- Integration governance + - project report integration counters + - review findings for outbound external integration endpoints +- Schema governance + - project report counters for attributes, tabular sections, columns, and empty tabular sections + - review findings for tabular sections without columns + - review hints for tabular sections without common subject columns +- UI governance + - review findings for form commands with missing BSL handlers +- Ownership governance + - project report ownership counters + - review findings for 1C objects without an assigned owner +- Privacy modes +- Privacy classification + - project privacy marker API + - object-scoped privacy lookup + - review hints for sensitive 1C fields without classification + - project report privacy counters +- AI governance + - answer policy gate for knowledge context, privacy markers, token budget, and external model calls +- AI usage governance + - AI usage event API + - project/user/model/operation usage summaries + - token limit policy endpoint + - project report AI usage counters +- Token usage limits + +## Operations +- Jobs / workers / queues +- Admin console +- Observability +- Marketplace/download center diff --git a/docs/codex-ui-guidelines.md b/docs/codex-ui-guidelines.md new file mode 100644 index 0000000..a9bafd2 --- /dev/null +++ b/docs/codex-ui-guidelines.md @@ -0,0 +1,72 @@ +# Codex UI Guidelines для SFERA + +## Роль Codex + +Codex должен работать как senior frontend engineer + product designer. + +Он обязан: +- соблюдать design system +- использовать русский язык интерфейса и команд по умолчанию +- предусматривать выбор английского языка интерфейса +- не генерировать случайные стили +- переиспользовать компоненты +- писать TypeScript +- не ломать архитектуру +- добавлять loading/error/empty states +- учитывать права доступа +- думать о масштабируемости IDE/authoring-среды для 1С + +## Перед генерацией экрана Codex должен определить + +1. Какая 1С-сущность или IDE-сущность? +2. Какие действия доступны пользователю? +3. Какие статусы есть? +4. Какие поля обязательные? +5. Нужен ли editor, designer, graph, table, inspector или diff? +6. Нужен ли AI Copilot? +7. Нужны ли права доступа? +8. Нужна ли история изменений? +9. Нужна ли интеграция с внешним источником? +10. Нужно ли preview/diff/apply для изменения 1С-кода или metadata? + +## Запреты + +Codex НЕ должен: +- использовать inline styles +- создавать хаотичные цвета +- использовать Bootstrap +- делать огромный компонент на 1000 строк +- хранить business logic в JSX +- игнорировать loading states +- игнорировать empty states +- генерировать mock API без явной пометки +- смешивать entity-компоненты и базовый UI + +## Обязательные states + +Каждый экран должен иметь: + +- loading +- error +- empty +- success +- permission denied +- dirty form / unsaved changes +- semantic diff / preview +- guarded apply result + +## UI quality checklist + +Перед финалом Codex обязан проверить: + +- интерфейс адаптивный +- все кнопки имеют понятный action +- статусы представлены Badge +- опасные действия требуют confirmation +- таблицы имеют фильтры +- формы валидируются через Zod +- редактор/дизайнер имеет problems panel и состояние несохранённых изменений +- дата/время форматируются единообразно +- AI действия показывают token/cost impact +- AI-подсказки учитывают текущий BSL-код, объект 1С, переменные, реквизиты, формы и связи +- есть audit trail для важных действий diff --git a/docs/codex_tasks/SPRINT_1_SIR.md b/docs/codex_tasks/SPRINT_1_SIR.md new file mode 100644 index 0000000..6898c6d --- /dev/null +++ b/docs/codex_tasks/SPRINT_1_SIR.md @@ -0,0 +1,34 @@ +# SPRINT 1 — SIR Core + +## Цель + +Создать `packages/sir`. + +## Files + +- `enums.py` +- `source_ref.py` +- `lineage.py` +- `nodes.py` +- `edges.py` +- `diagnostics.py` +- `references.py` +- `snapshot.py` +- `delta.py` +- `validation.py` +- `serialization.py` +- `hashing.py` + +## DoD + +```bash +pytest packages/sir/tests +``` + +Должно проходить: + +- snapshot validation ok; +- dangling edge detected; +- serialization roundtrip; +- snapshot hash deterministic; +- diagnostics/unresolved references serializable. diff --git a/docs/codex_tasks/SPRINT_2_RUST_PARSER.md b/docs/codex_tasks/SPRINT_2_RUST_PARSER.md new file mode 100644 index 0000000..65c6b6a --- /dev/null +++ b/docs/codex_tasks/SPRINT_2_RUST_PARSER.md @@ -0,0 +1,27 @@ +# SPRINT 2 — Rust BSL Parser MVP + +## Цель + +`rust/crates/bsl-parser` должен возвращать `ParsedSemanticUnit`: + +- procedures; +- functions; +- calls; +- queries; +- query tables; +- writes; +- diagnostics. + +## Важное + +Поддержать RU/EN keywords. + +## MVP ограничение + +Можно начать с deterministic line-based parser. Позже заменить на полноценный lexer/parser. + +## DoD + +```bash +cd rust && cargo test +``` diff --git a/docs/codex_tasks/SPRINT_3_SEMANTIC_KERNEL.md b/docs/codex_tasks/SPRINT_3_SEMANTIC_KERNEL.md new file mode 100644 index 0000000..7d7742f --- /dev/null +++ b/docs/codex_tasks/SPRINT_3_SEMANTIC_KERNEL.md @@ -0,0 +1,27 @@ +# SPRINT 3 — Semantic Kernel + +## Цель + +`packages/semantic-kernel` конвертирует parsed result в SIR snapshot. + +## Вход + +`.bsl` файлы. + +## Выход + +`SirSnapshot` с nodes/edges: + +- MODULE; +- PROCEDURE/FUNCTION; +- QUERY; +- TABLE/REGISTER; +- DECLARES; +- CALLS; +- OWNS_QUERY; +- READS_TABLE; +- WRITES. + +## DoD + +`index_project(path)` возвращает валидный snapshot. diff --git a/docs/codex_tasks/SPRINT_4_PROJECTION.md b/docs/codex_tasks/SPRINT_4_PROJECTION.md new file mode 100644 index 0000000..2bad91a --- /dev/null +++ b/docs/codex_tasks/SPRINT_4_PROJECTION.md @@ -0,0 +1,17 @@ +# SPRINT 4 — Neo4j Projection + +## Цель + +`SirSnapshot → Neo4j graph`. + +## Queries + +- find procedures; +- find callers; +- find callees; +- find query tables; +- find writes. + +## Rule + +Only `projection-engine` can mutate Neo4j. diff --git a/docs/codex_tasks/SPRINT_5_INCREMENTAL.md b/docs/codex_tasks/SPRINT_5_INCREMENTAL.md new file mode 100644 index 0000000..a0ef73f --- /dev/null +++ b/docs/codex_tasks/SPRINT_5_INCREMENTAL.md @@ -0,0 +1,13 @@ +# SPRINT 5 — Incremental Indexer + +## Цель + +Изменился один `.bsl` файл — пересобираем только fragment и применяем delta. + +## Components + +- source hash; +- change detector; +- SirDelta builder; +- snapshot transition; +- projection delta. diff --git a/docs/component-architecture.md b/docs/component-architecture.md new file mode 100644 index 0000000..75848d3 --- /dev/null +++ b/docs/component-architecture.md @@ -0,0 +1,167 @@ +# Component Architecture + +## Рекомендуемая структура + +```txt +src/ + app/ + (auth)/ + (workspace)/ + dashboard/ + projects/ + objects/ + graph/ + editor/ + designer/ + review/ + impact/ + knowledge/ + integrations/ + jobs/ + ai/ + settings/ + components/ + ui/ + layout/ + data-table/ + editor/ + designer/ + graph/ + command/ + ai/ + entities/ + one-c-projects/ + one-c-objects/ + bsl-modules/ + forms/ + reports/ + roles/ + features/ + one-c-projects/ + semantic-graph/ + bsl-editor/ + object-designer/ + form-designer/ + report-designer/ + impact-analysis/ + review/ + ai-authoring/ + ai-usage/ + integrations/ + scheduled-jobs/ + lib/ + api/ + auth/ + permissions/ + validators/ + formatters/ + one-c/ + store/ + styles/ +``` + +## Правило разделения + +### `components/ui` + +Только базовые shadcn-like компоненты: +- Button +- Input +- Dialog +- Drawer +- Badge +- Card +- Tabs + +### `components/editor` + +IDE primitives: +- BslEditor +- ProblemsPanel +- ReferencesPanel +- OutlinePanel +- SemanticDiffView +- CompletionList + +### `components/designer` + +Object/form/report designer primitives: +- ObjectTree +- MetadataInspector +- FormCanvas +- FormElementPalette +- PropertiesInspector +- ReportDesigner + +### `components/entities` + +Переиспользуемые 1С entity-компоненты: +- OneCProjectCard +- OneCObjectBadge +- ObjectKindBadge +- RoleAccessBadge +- ReviewSeverityBadge +- SnapshotStatusBadge + +### `features` + +Полные feature-модули: +- список 1С-проектов +- дерево конфигурации +- карточка объекта 1С +- BSL editor workspace +- дизайнер формы +- дизайнер отчёта +- semantic graph +- impact analysis +- AI authoring panel +- AI usage dashboard + +## Data Table стандарт + +Каждая таблица должна иметь: + +- search +- filters +- saved views +- column visibility +- sorting +- pagination / virtualization +- row actions +- bulk actions +- export +- audit-friendly row details + +## IDE Page Standard + +Каждая IDE-страница строится по шаблону: + +```txt +PageHeader +Toolbar +ObjectTree +PrimaryEditorOrDesigner +RightInspector +ProblemsPanel +SemanticDiffPreview +AIAssistantContext +``` + +## Naming conventions + +```txt +OneCProjectList +OneCObjectTree +BslEditorWorkspace +BslCompletionPanel +FormDesignerCanvas +MetadataPropertiesInspector +SemanticDiffPreview +AiAuthoringPanel +``` + +Не использовать абстрактные имена вроде: +- MainTable +- CustomCard +- ModalWindow +- BigForm diff --git a/docs/design-system.md b/docs/design-system.md new file mode 100644 index 0000000..b6b291b --- /dev/null +++ b/docs/design-system.md @@ -0,0 +1,207 @@ +# Design System SFERA + +## UI концепция + +**SFERA — Enterprise AI Operating System** + +Интерфейс должен ощущаться как: +- Linear +- Stripe Dashboard +- Notion +- Attio +- ClickUp 3.0 +- Plane +- VS Code / JetBrains IDE для authoring-сценариев 1С + +SFERA не CRM. Основной UI — это современная IDE/операционная среда для 1С: semantic workspace, редактор кода, дерево объектов, дизайнер форм/отчётов, инспектор свойств, diff/preview/apply и AI-помощник. + +Классический 1С Конфигуратор используется как reference workflow, а не как visual style. Мы берём рабочие паттерны 1С-разработчика: дерево конфигурации, вкладки объектов, модуль/форма/свойства/события, правый инспектор, нижние панели диагностики и поиск. Визуально это должно быть современно, плотно, спокойно и удобно для долгой работы. + +## Визуальный стиль + +- чистый enterprise minimalism +- dark/light режим +- спокойные нейтральные цвета +- акцентный цвет для действий +- cards with soft shadows +- rounded-2xl +- минимальный glassmorphism только для важных overlay +- плотная, но не перегруженная информационная сетка + +## Layout principles + +### Главная структура + +```txt +AppShell +├── Sidebar +├── Topbar +├── CommandPalette +├── Workspace +│ ├── PageHeader +│ ├── Toolbar +│ ├── ContentGrid +│ └── RightInspector +├── EditorWorkspace +│ ├── ObjectTree +│ ├── WorkspaceModeBar +│ ├── CodeEditor +│ ├── FormDesigner +│ ├── PropertiesInspector +│ ├── EventsInspector +│ ├── VersionsPanel +│ ├── DocumentationPanel +│ ├── KnowledgePanel +│ ├── LearningPanel +│ ├── ProblemsPanel +│ └── SemanticDiff +└── AI Copilot Panel +``` + +## Основные зоны + +### Sidebar + +- Dashboard +- Проекты 1С +- Объекты 1С +- Редактор BSL +- Дизайнер объектов +- Дизайнер форм +- Отчёты +- Семантический граф +- Impact analysis +- Review +- Знания +- AI +- Интеграции +- Регламентные задания +- Настройки + +### Topbar + +- поиск +- command palette +- быстрые действия +- уведомления +- профиль +- переключение проекта/организации + +### Right Inspector + +Контекстная панель для: +- объекта 1С +- процедуры или функции +- формы, команды или элемента формы +- реквизита или табличной части +- отчёта +- AI анализа +- истории изменений +- связанных сущностей + +## Компонентные правила + +### Карточки + +- `rounded-2xl` +- `border` +- `bg-card` +- `shadow-sm` +- padding минимум `p-4` + +### Таблицы + +- sticky header +- фильтры +- saved views +- быстрый поиск +- column visibility +- bulk actions +- inline status badge +- row details через drawer/inspector + +### Формы + +- разделять на logical sections +- использовать progressive disclosure +- показывать validation inline +- сохранять drafts +- audit trail для важных изменений + +## Цветовые токены + +```txt +background +foreground +card +card-foreground +muted +muted-foreground +border +input +primary +primary-foreground +secondary +destructive +warning +success +info +``` + +## Статусы + +### Задача + +```txt +Новая +В работе +На проверке +Выполнена +Отменена +Просрочена +``` + +### Сделка + +```txt +Активна +Неактивна +На бординге +Ожидает документов +Приостановлена +Закрыта +``` + +### Терминал + +```txt +Подключен +Не подключен +Отключен банком +Ошибка настройки +``` + +## AI UX + +AI должен быть не отдельной страницей, а частью workflow: + +- AI Copilot справа +- подсказки в карточках +- inline completion в BSL editor +- context-aware suggestions по текущим переменным, реквизитам, табличным частям, форме и объекту 1С +- генерация кода, объектов, форм, команд и отчётов через preview/diff/apply +- объяснение текущего кода и структуры объекта +- генерация безопасных изменений 1С +- продолжение кода по текущему контексту +- объяснение изменений +- статистика токенов и лимитов + +## Knowledge, Docs, Training UX + +SFERA должна показывать знания рядом с местом работы, а не прятать их в отдельную wiki: + +- документация объекта, формы, отчёта и бизнес-правила доступны из IDE-контекста; +- база знаний связывается с lineage объекта, процедурами, запросами и событиями формы; +- training/onboarding показывает рекомендации по текущему коду, стандартам команды и типовым ошибкам; +- AI отвечает только с учётом доступных знаний, прав и privacy policy; +- history/versions объясняют, почему объект менялся, какими задачами и решениями это было связано. diff --git a/docs/frontend-stack.md b/docs/frontend-stack.md new file mode 100644 index 0000000..f45c2b1 --- /dev/null +++ b/docs/frontend-stack.md @@ -0,0 +1,81 @@ +# Frontend Stack для SFERA + +## Core + +```txt +Next.js +React +TypeScript +Tailwind CSS +shadcn/ui +Radix UI +lucide-react +``` + +## Data layer + +```txt +TanStack Query +Zustand +Zod +React Hook Form +``` + +## Tables / Grids + +```txt +TanStack Table +TanStack Virtual +``` + +Использовать для: +- 1С-проектов +- объектов 1С +- процедур и функций +- форм и команд +- ролей и прав +- review findings +- журналов изменений +- AI usage статистики +- лимитов +- интеграций + +## Charts + +```txt +Recharts +Apache ECharts +``` + +Для простых dashboard — Recharts. +Для тяжелой аналитики и сложных графиков — ECharts. + +## Animations + +```txt +Framer Motion +``` + +Использовать аккуратно: +- открытие панелей +- command palette +- sidebar +- drawer +- карточки задач +- state transitions + +## UI generation tools + +```txt +v0 by Vercel +shadcn/ui +shadcn/studio +Cursor +Codex +``` + +## Почему не Ant Design / Bootstrap + +Ant Design подходит для быстрых корпоративных систем, но SFERA должна выглядеть как современный AI enterprise workspace, а не как старая админка. + +Bootstrap и старые admin templates не использовать как основу. diff --git a/docs/frontend/SFERA_FRONTEND_CHANGELOG.md b/docs/frontend/SFERA_FRONTEND_CHANGELOG.md new file mode 100644 index 0000000..a7b4481 --- /dev/null +++ b/docs/frontend/SFERA_FRONTEND_CHANGELOG.md @@ -0,0 +1,391 @@ +# SFERA Frontend Changelog + +## Правило + +Каждое изменение frontend должно фиксироваться здесь. + +Формат: + +```text +Дата: +Автор/Codex task: +Что изменено: +Какие файлы: +Затронутые экраны: +Изменен ли UI contract: +Нужны ли новые smoke tests: +``` + +## Записи + +### 2026-05-11 + +Initial UI contract created. + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Корневой маршрут frontend переведен на IDE последнего проекта; существующий экран настройки проекта вынесен на `/project-settings`; Top Project Bar дополнен настройками проекта, созданием проекта, уведомлениями и профилем; smoke-тесты обновлены под IDE-first модель и новый route настроек проекта. +Какие файлы: `frontend/sfera-web/src/app/page.tsx`, `frontend/sfera-web/src/app/project-settings/page.tsx`, `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/lib/i18n.ts`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: основной вход frontend, IDE workspace, project settings +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, HTML smoke покрывает redirect `/` -> IDE и доступность `/project-settings` + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Fallback metadata tree приведен к контрактной модели: проект содержит top-level `Основная конфигурация`, `Расширение: <Имя>`, `SFERA`, `Среды`; расширение использует тот же configuration-like каркас без fake-объектов. +Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs` +Затронутые экраны: IDE workspace, левая панель metadata tree +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, HTML smoke проверяет ключевые top-level узлы левой панели + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Server-side metadata tree приведен к той же top-level модели для lazy/large-project режима; пути раскрытия теперь идут через `main-configuration`, а lazy tree сохраняет раскрытие `Основная конфигурация`. +Какие файлы: `services/api-server/src/api_server/main.py`, `services/api-server/tests/test_api.py`, `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx` +Затронутые экраны: IDE workspace, lazy metadata tree +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, API tests покрывают структуру, HTML smoke покрывает видимые top-level узлы + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Project Settings sidebar переименован из wizard в контрактный экран настроек, добавлен список разделов настроек, AI policy и ITS/documentation access с безопасными env placeholders без реальных credentials; default privacy для нового fallback проекта изменен на `METADATA_ONLY`. +Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/src/app/project-settings/page.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs` +Затронутые экраны: Project Settings, Top Project Bar, Import Center +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, HTML smoke проверяет Project Settings и ITS env placeholders + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Lazy metadata tree получил полный маппинг contract-first иконок на существующие 1C SVG assets, чтобы top-level проект, основная конфигурация, ветки metadata, группы макетов/событий/движений, бизнес-процессы, задачи и внешние источники не ссылались на отсутствующие файлы. +Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx` +Затронутые экраны: IDE workspace, lazy metadata tree +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, существующий editor smoke покрывает lazy metadata tree shell + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Lazy metadata tree очищен от старого `dashboard` route variant; все переходы из дерева теперь строятся напрямую на `/editor`, включая SFERA overview как `mode=overview`. +Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx`, `frontend/sfera-web/src/components/editor/ide-workspace.tsx` +Затронутые экраны: IDE workspace, lazy metadata tree +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, существующий editor smoke покрывает IDE route + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: `/project-settings` закреплен как экран Project Settings при любом статусе проекта; INDEXED-проект больше не подменяет настройки старым workbench, поэтому настройки проекта остаются доступны из Top Project Bar по контракту. +Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, project setup smoke обновлен под contract-first Project Settings route + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: IDE workspace получил contract-first управление панелями: левая навигация сворачивается и меняет ширину, правая Context Inspector и нижняя tool panel сворачиваются, добавлены горячие клавиши `Alt+1`, `Alt+2`, `Alt+3`, `Ctrl+Tab`, `Ctrl+Shift+Tab`, `Ctrl+W`. +Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs` +Затронутые экраны: IDE workspace, Left Navigation Panel, Main Workspace, Right Context Inspector, Bottom Tool Panel, Open Objects Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, editor smoke расширен проверкой contract layout markers + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Runtime smoke расширен интерактивной проверкой contract controls: `Alt+1`, `Alt+2`, `Alt+3` скрывают соответствующие панели, rail/buttons возвращают их, `Ctrl+Tab` и `Ctrl+Shift+Tab` переключают открытые объекты; после переходов между editor modes нижняя tool panel сворачивается для focused editor workflows. +Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, панель открытых объектов, левая/правая/нижняя панели +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, runtime smoke обновлен + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Open Objects Bar получил fallback-набор IDE tabs (`Обзор`, `Модуль`, `Форма`, `TASK-123`) для пустого или минимального metadata tree, чтобы workspace сохранял contract-first модель переключаемых открытых объектов. +Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, Open Objects Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, runtime smoke проверяет минимум два переключаемых объекта + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: IDE workspace убран жесткий `min-h-[760px]`, из-за которого нижняя tool panel и fixed status bar могли перекрывать рабочую область и перехватывать клики в metadata editor на невысоких viewport. +Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx` +Затронутые экраны: IDE workspace, Main Workspace, Bottom Tool Panel, Status Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, runtime smoke ловит перекрытие кликов + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Top Project Bar получил настоящий global search input; IDE workspace обрабатывает `Ctrl+K` для фокуса глобального поиска и `F5` для запуска проверки с открытием bottom tool panel и статусом запуска. +Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: Top Project Bar, IDE workspace, Bottom Tool Panel +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, runtime smoke расширен проверкой `Ctrl+K` и `F5` + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Fallback Left Navigation Panel получил поиск по дереву, фильтры `Все / 1C / SFERA / Среды`, отдельный scroll marker и сохранение раскрытия веток через `localStorage`. +Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, Left Navigation Panel +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой поиска/фильтров fallback tree + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Open Objects Bar получил pin/close controls, `Ctrl+W` закрывает активный незакрепленный объект, состояние закрытых и закрепленных объектов сохраняется в `localStorage` и восстанавливается для проекта. +Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, Open Objects Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой pin/close/persist поведения + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Open Objects Bar поднят над рабочей областью (`z-index`) и сделан `shrink-0`, чтобы Monaco/editor canvas не перекрывал pin/close controls и не перехватывал клики. +Какие файлы: `frontend/sfera-web/src/components/editor/ide-workspace.tsx` +Затронутые экраны: IDE workspace, Open Objects Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, runtime smoke ловит перекрытие кликов + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Project Settings получил недостающие контрактные секции `Пользователи и доступ`, `Интеграции задач`, `Docker/runtime adapter`, `Audit`, `Backup/restore`; sidebar anchors обновлены под эти секции, без хранения credentials. +Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, существующие smoke расширены проверкой полного набора settings sections + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Status Bar приведен к полному набору контрактных индикаторов, добавлен `Current user`, стабильные `data-status-item` markers и горизонтальный overflow для узких viewport. +Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, Status Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, editor smoke и runtime smoke расширены проверкой status markers + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Источники структуры 1С дополнены `REFERENCE_CONFIGURATION` end-to-end: backend import source registry/preflight, frontend selector/action button/source configurator и smoke checks. +Какие файлы: `services/api-server/src/api_server/main.py`, `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings, Import Center +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, существующие smoke расширены проверкой reference configuration source + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Metadata tree дополнен контрактными configuration-like roots для context/reference источников: при `CONTEXT_ONLY` добавляется `Context-only configuration`, при `REFERENCE_CONFIGURATION` добавляется `Reference configuration` с тем же каркасом веток, что у основной конфигурации/расширений. +Какие файлы: `services/api-server/src/api_server/main.py`, `services/api-server/tests/test_api.py` +Затронутые экраны: IDE workspace, левая панель metadata tree (lazy/server data) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, покрыто API tests для metadata tree response + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: В `LazyMetadataTree` добавлен настоящий virtual scroll для списка видимых узлов (viewport-based windowing с overscan), чтобы левая панель масштабировалась на больших деревьях без полной отрисовки всех root-level элементов. +Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx` +Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, существующий `smoke:editor` проходит; typecheck зеленый + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Runtime smoke расширен проверкой контрактного scroll-контейнера левой панели (`data-virtual-scroll` для lazy tree или `data-fallback-tree-scroll` для fallback tree), чтобы регресс virtual scroll ловился автоматически. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, левая панель metadata tree +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: API test coverage дерева метаданных расширено для `CONTEXT_CONFIGURATION`: добавлен тест, подтверждающий появление `Context-only configuration` как configuration-like root с контрактным набором первых веток (`Сведения`, `Общие`, `Константы`). +Какие файлы: `services/api-server/tests/test_api.py` +Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, покрыто API tests + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: В `LazyMetadataTree` добавлены контрактные фильтры левой панели (`Все / 1C / SFERA / Среды`) для lazy/server режима, чтобы поведение фильтрации было единым с fallback tree. +Какие файлы: `frontend/sfera-web/src/components/editor/lazy-metadata-tree.tsx` +Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, существующий runtime smoke проходит; typecheck зеленый + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Runtime smoke расширен проверкой lazy-tree фильтров: при наличии `data-lazy-tree-filter` тест переключает `SFERA`/`All` и подтверждает доступность узла `SFERA`, чтобы зафиксировать поведение новых фильтров. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, левая панель metadata tree (lazy mode) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Project Settings runtime smoke усилен проверкой отображения `.env.local` в секции `ITS/documentation access`, чтобы policy "credentials only via .env.local" оставалась закрепленной на UI-уровне. +Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings (`ITS/documentation access`) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: HTML smoke (`smoke:editor`) усилен контрактными маркерами Top Project Bar на корневом IDE-экране: добавлены проверки `Компания`, `Среда`, `Задача`, `Ctrl+K`, `API доступен`, `Агент онлайн`. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs` +Затронутые экраны: основной IDE экран, Top Project Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий editor smoke + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: HTML smoke для `/project-settings` расширен security-маркерами секции `ITS/documentation access`: добавлены проверки `.env.local` и placeholder `<set locally>` вместе с `SFERA_ITS_USERNAME`. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs` +Затронутые экраны: Project Settings (`ITS/documentation access`) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий editor smoke + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Добавлен защитный API-тест на metadata tree: для обычных источников (`XML_DUMP`) в корне проекта не должны появляться contract-only roots `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION`. +Какие файлы: `services/api-server/tests/test_api.py` +Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, покрыто API tests + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Runtime smoke расширен проверкой горячей клавиши `Ctrl+W`: тест выбирает немодульный открытый объект (если доступен), закрывает его через `Ctrl+W` и проверяет, что tab удален без runtime ошибок; сценарий стабилизирован возвратом к module-tab при необходимости. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, Open Objects Bar, горячие клавиши +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: ITS security-policy smoke-покрытие расширено: в HTML smoke добавлены `SFERA_ITS_URL`/`SFERA_ITS_PASSWORD`, в runtime smoke `Project Settings` добавлены проверки `SFERA_ITS_URL`, `SFERA_ITS_PASSWORD` и presence примера ITS URL через `input[value*='its.1c.ru/db/v838doc']`. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings (`ITS/documentation access`) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:project-setup` + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: HTML smoke расширен англоязычной проверкой корневого IDE-экрана (`lang=en`) для Top Project Bar: `Workspace`, `Env`, `Task`, `Ctrl+K`, `API online`, `Agent online`. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs` +Затронутые экраны: основной IDE экран, Top Project Bar (EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий editor smoke + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Добавлен API-тест порядка top-level узлов metadata tree: при `CONTEXT_ONLY` и `REFERENCE_CONFIGURATION` соответствующие configuration-like roots должны располагаться перед `SFERA` в корне проекта. +Какие файлы: `services/api-server/tests/test_api.py` +Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, покрыто API tests + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: Runtime smoke расширен проверкой восстановления `Open Objects Bar` после перезагрузки: тест сохраняет состояние закрытых/закрепленных табов, делает `page.reload`, подтверждает сохранность `localStorage` и проверяет, что закрытый таб снова скрыт после применения состояния. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, Open Objects Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke + +Дата: 2026-05-11 +Автор/Codex task: Codex +Что изменено: API tests для `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION` расширены проверкой lazy-режима (`object_limit_per_branch=0`): условные configuration-like roots должны присутствовать не только в полном, но и в lazy metadata tree response. +Какие файлы: `services/api-server/tests/test_api.py` +Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, покрыто API tests + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: API-тест порядка корневых узлов расширен и на lazy metadata tree: для `CONTEXT_ONLY` и `REFERENCE_CONFIGURATION` условные configuration-like roots должны располагаться перед `SFERA` как в полном, так и в lazy-ответе (`object_limit_per_branch=0`). +Какие файлы: `services/api-server/tests/test_api.py` +Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, покрыто API tests + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: Runtime smoke расширен проверкой состава `Bottom Tool Panel`: тест подтверждает видимость вкладок `Проблемы`, `Semantic diff`, `Вывод`, `История`, `Тесты`, `AI` после открытия нижней панели. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: IDE workspace, Bottom Tool Panel +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий runtime smoke + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: HTML smoke расширен англоязычной проверкой `Project Settings` (`lang=en`): закреплены `Project Settings`, `Import Center`, `Task/session policy`, `Docker/runtime adapter`, `ITS/documentation access`, `Audit`, `Backup/restore` и ITS env placeholders. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs` +Затронутые экраны: Project Settings (EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий editor smoke + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: Защитный API-тест для обычных источников (`XML_DUMP`) расширен и на lazy metadata tree: `CONTEXT_CONFIGURATION` и `REFERENCE_CONFIGURATION` не должны появляться в корне ни полного, ни lazy-ответа. +Какие файлы: `services/api-server/tests/test_api.py` +Затронутые экраны: IDE workspace, левая панель metadata tree (server/lazy data) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, покрыто API tests + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: Runtime smoke `Project Settings` расширен англоязычным сценарием (`lang=en`): подтверждаются `Task/session policy`, `Docker/runtime adapter`, `ITS/documentation access`, `Audit`, `Backup/restore` и ITS env placeholders на реальном интерактивном экране. +Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings (EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: Runtime smoke IDE расширен англоязычным сценарием (`lang=en`) для Top Project Bar и status bar; дополнительно smoke фиксирован на desktop viewport `1680x1050`, чтобы контрактные desktop-элементы вроде `Task` проверялись в реальном видимом layout. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: основной IDE экран, Top Project Bar, Status Bar (EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий editor runtime smoke + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: EN runtime smoke `Project Settings` расширен проверкой `REFERENCE_CONFIGURATION` и кнопки `Reference config`, чтобы import/source contract был закреплен и в английском интерактивном сценарии. +Какие файлы: `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings (EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: EN runtime smoke IDE расширен проверкой `Bottom Tool Panel`: в английском сценарии подтверждаются вкладки `Problems`, `Semantic diff`, `Output`, `Change history`, `Tests`, `AI`. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: основной IDE экран, Bottom Tool Panel (EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий editor runtime smoke + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: Кнопки действий `Project Settings` получили стабильный маркер `data-import-action=:`; runtime smoke переведен на этот маркер и EN-сценарий теперь интерактивно запускает `Source preflight`, а не зависит от русского текста кнопки. +Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings, Import Center (RU/EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий project-setup runtime smoke + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: HTML smoke для `Project Settings` (RU/EN) расширен проверкой стабильных action markers `data-import-action="REFERENCE_CONFIGURATION:import"` и `data-import-action="XML_DUMP:check"`, чтобы import actions ловились быстрым контуром без Playwright. +Какие файлы: `frontend/sfera-web/scripts/smoke-editor-modes.mjs` +Затронутые экраны: Project Settings, Import Center (RU/EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлен существующий editor smoke + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: `Top Project Bar` получил стабильные `data-*` маркеры для logo, selectors, actions, status badges, language switcher и profile button; `Badge` обновлен с passthrough `HTMLAttributes`, чтобы `data-*` атрибуты доходили до DOM. HTML и runtime smoke IDE переведены на эти маркеры. Дополнительно runtime smoke после reload явно возвращается на module-tab перед проверкой Monaco. +Какие файлы: `frontend/sfera-web/src/components/layout/app-shell.tsx`, `frontend/sfera-web/src/components/ui/badge.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-editor-runtime.mjs` +Затронутые экраны: основной IDE экран, Top Project Bar, Open Objects Bar +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:editor:runtime` + +Дата: 2026-05-12 +Автор/Codex task: Codex +Что изменено: `Project Settings` секции получили стабильный маркер `data-settings-section`; HTML и runtime smoke переведены на него для ключевых разделов `task-session-policy`, `docker-runtime-adapter`, `its-documentation-access` в RU/EN сценариях. +Какие файлы: `frontend/sfera-web/src/components/project-setup/project-setup-client.tsx`, `frontend/sfera-web/scripts/smoke-editor-modes.mjs`, `frontend/sfera-web/scripts/smoke-project-setup.mjs` +Затронутые экраны: Project Settings (RU/EN UI) +Изменен ли UI contract: нет +Нужны ли новые smoke tests: нет, обновлены существующие `smoke:editor` и `smoke:project-setup` diff --git a/docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md b/docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md new file mode 100644 index 0000000..3df349f --- /dev/null +++ b/docs/frontend/SFERA_FRONTEND_PRODUCT_CONTRACT.md @@ -0,0 +1,35 @@ +# SFERA Frontend Product Contract + +SFERA - это серверная semantic IDE-платформа для 1С, а не dashboard, CRM или файловый редактор. + +## Главная модель + +- Проект выбирается в верхней панели. +- Пользователь долго работает внутри одного проекта. +- Основной экран - IDE workspace последнего проекта. +- Если проекта нет - пустой workspace с выбором или созданием проекта. +- Левая панель - навигация по текущему проекту. +- Центр - рабочая область. +- Правая панель - контекстные свойства. +- Нижняя зона - открытые объекты, служебные панели и status bar. + +## Product Principles + +SFERA должна быть metadata-first: в 1С дерево объектов конфигурации представляет прикладное решение как древовидную структуру логически связанных объектов. + +Расширения являются configuration-like структурами: расширение похоже на обычную конфигурацию и тоже представляется деревом объектов. + +Формы - visual-first: формы 1С предназначены для просмотра и редактирования данных и могут принадлежать объектам конфигурации или быть общими. + +Окно объекта конфигурации в 1С предназначено для редактирования свойств, управления подчиненными объектами и настройки взаимодействия объектов. SFERA должна расширять эту модель, а не заменять ее dashboard-карточками. + +## Official 1C Documentation + +При проектировании 1C-specific поведения использовать официальные источники: + +- ITS; +- v8.1c.ru; +- 1C DN; +- локальные knowledge packs. + +ITS credentials нельзя хранить в документации или репозитории. Доступ передается только через `.env.local`. diff --git a/docs/frontend/SFERA_IDE_UI_CONTRACT.md b/docs/frontend/SFERA_IDE_UI_CONTRACT.md new file mode 100644 index 0000000..e739c74 --- /dev/null +++ b/docs/frontend/SFERA_IDE_UI_CONTRACT.md @@ -0,0 +1,152 @@ +# SFERA IDE UI Contract + +## 1. Основной экран + +После входа открывается: + +- последний проект пользователя; +- либо пустой IDE shell, если проекта нет. + +Проект выбирается только в верхней панели. + +Запрещено: + +- показывать список проектов в левой панели; +- делать dashboard главным экраном; +- показывать fake-данные без импортированного проекта. + +## 2. Главный Layout + +Экран состоит из: + +```text +Top Project Bar +Left Navigation Panel +Main Workspace +Right Context Inspector +Open Objects Bar +Bottom Tool Panel +Status Bar +``` + +## 3. Top Project Bar + +Содержит: + +- SFERA logo; +- Workspace selector; +- Project selector; +- Project settings button; +- Create project button; +- Environment selector; +- Active task selector; +- Global search; +- Agent/API status; +- Notifications; +- Language; +- User profile. + +Пример: + +```text +SFERA | Workspace v | Project v | Настройки | + Проект | Env v | Task v | Search... +``` + +## 4. Левая Панель + +Левая панель - навигация текущего проекта. + +Она содержит: + +```text +Проект: ERP Demo +├── Основная конфигурация +├── Расширение: <Имя> +├── Расширение: <Имя> +├── SFERA +└── Среды +``` + +Левая панель должна: + +- сворачиваться; +- менять ширину; +- поддерживать поиск; +- поддерживать фильтры; +- поддерживать lazy loading; +- поддерживать virtual scroll; +- сохранять состояние раскрытия узлов. + +## 5. Центр + +Центр - основная рабочая область. + +Там открываются: + +- Object Workspace; +- Code Workspace; +- Form Designer; +- Report Designer; +- СКД Designer; +- Layout Designer; +- Project Settings; +- Task Workspace; +- Review Workspace; +- Runtime Workspace; +- Knowledge Workspace. + +## 6. Правая Панель + +Правая панель - Context Inspector. + +Она показывает свойства выбранного объекта, элемента формы, процедуры, задачи, отчета, регистра, расширения. + +Она не является навигацией. + +## 7. Open Objects Bar + +Внизу отображается панель открытых объектов: + +```text +[Документ.ЗаказКлиента] [ФормаДокумента] [Модуль объекта] [TASK-123] +``` + +Поддерживает: + +- быстрое переключение; +- закрытие; +- закрепление; +- восстановление после перезагрузки. + +## 8. Bottom Tool Panel + +Сворачиваемая служебная панель: + +- Проблемы; +- Semantic diff; +- Вывод; +- История; +- Тесты; +- AI. + +## 9. Status Bar + +- Snapshot; +- Agent; +- Parser; +- Diagnostics; +- Active Task; +- Privacy; +- AI tokens; +- Current user. + +## 10. Горячие Клавиши + +- `Alt+1` - левая панель; +- `Alt+2` - правая панель; +- `Alt+3` - нижняя панель; +- `Ctrl+Tab` - следующий открытый объект; +- `Ctrl+Shift+Tab` - предыдущий объект; +- `Ctrl+W` - закрыть текущий объект; +- `Ctrl+K` - глобальный поиск; +- `F5` - запустить проверку. diff --git a/docs/frontend/SFERA_METADATA_TREE_CONTRACT.md b/docs/frontend/SFERA_METADATA_TREE_CONTRACT.md new file mode 100644 index 0000000..5da9fd7 --- /dev/null +++ b/docs/frontend/SFERA_METADATA_TREE_CONTRACT.md @@ -0,0 +1,301 @@ +# SFERA Metadata Tree Contract + +## 1. Верхний Уровень + +```text +Проект +├── Основная конфигурация +├── Расширение: +├── Расширение: +├── SFERA +└── Среды +``` + +## 2. ConfigurationLikeRoot + +Один компонент используется для: + +- основной конфигурации; +- расширений; +- context-only конфигураций; +- reference конфигураций. + +Типы: + +- `MAIN_CONFIGURATION`; +- `EXTENSION`; +- `CONTEXT_CONFIGURATION`; +- `REFERENCE_CONFIGURATION`. + +## 3. Структура ConfigurationLikeRoot + +- Сведения; +- Общие; +- Константы; +- Справочники; +- Документы; +- Журналы документов; +- Перечисления; +- Отчеты; +- Обработки; +- Планы видов характеристик; +- Планы счетов; +- Планы видов расчета; +- Регистры сведений; +- Регистры накопления; +- Регистры бухгалтерии; +- Регистры расчета; +- Бизнес-процессы; +- Задачи 1С; +- Внешние источники данных. + +## 4. Узел "Общие" + +- Подсистемы; +- Общие модули; +- Параметры сеанса; +- Роли; +- Общие реквизиты; +- Планы обмена; +- Критерии отбора; +- Подписки на события; +- Регламентные задания; +- Боты; +- Функциональные опции; +- Параметры функциональных опций; +- Определяемые типы; +- Хранилища настроек; +- Общие команды; +- Группы команд; +- Общие формы; +- Общие макеты; +- Общие картинки; +- XDTO-пакеты; +- Web-сервисы; +- HTTP-сервисы; +- WS-ссылки; +- WebSocket-клиенты; +- Сервисы интеграции; +- Цвета палитры; +- Элементы стиля; +- Стили; +- Языки. + +## 5. Object Tree Templates + +### Справочник + +- Обзор; +- Свойства; +- Реквизиты; +- Табличные части; +- Формы; +- Команды; +- Макеты; +- Модуль объекта; +- Модуль менеджера; +- Права; +- Данные; +- Где используется; +- Кто читает; +- Кто записывает; +- Версии; +- Проверки. + +### Документ + +- Обзор; +- Свойства; +- Реквизиты; +- Табличные части; +- Формы; +- Команды; +- Макеты; +- Движения; +- Модуль объекта; +- Модуль менеджера; +- Права; +- Данные; +- Где используется; +- Кто создает; +- Кто проводит; +- Версии; +- Проверки. + +### Регистр Сведений + +- Обзор; +- Свойства; +- Измерения; +- Ресурсы; +- Реквизиты; +- Формы; +- Команды; +- Макеты; +- Модуль набора записей; +- Модуль менеджера; +- Права; +- Данные; +- Кто читает; +- Кто записывает; +- Версии; +- Проверки. + +### Регистр Накопления + +- Обзор; +- Свойства; +- Измерения; +- Ресурсы; +- Реквизиты; +- Формы; +- Команды; +- Макеты; +- Модуль набора записей; +- Модуль менеджера; +- Права; +- Данные; +- Кто читает; +- Кто записывает; +- Документы-регистраторы; +- Версии; +- Проверки. + +### Отчет + +- Обзор; +- Свойства; +- СКД; +- Формы; +- Команды; +- Макеты; +- Модуль объекта; +- Права; +- Данные; +- Версии; +- Проверки. + +### Обработка + +- Обзор; +- Свойства; +- Формы; +- Команды; +- Макеты; +- Модуль объекта; +- Права; +- Данные; +- Интеграции; +- Версии; +- Проверки. + +### Общий Модуль + +- Обзор; +- Свойства; +- Процедуры; +- Функции; +- Экспортные методы; +- Запросы; +- Записи; +- Вызовы; +- Кто вызывает; +- Транзакции; +- Runtime; +- Версии; +- Проверки. + +### Форма + +- Дизайнер формы; +- Свойства; +- Реквизиты формы; +- Элементы; +- Команды; +- События; +- Модуль формы; +- Связи с объектом; +- Данные; +- Версии; +- Проверки. + +### Роль + +- Обзор; +- Свойства; +- Права на объекты; +- Права на реквизиты; +- Права на табличные части; +- RLS; +- Унаследованные права; +- Отличия от default rights; +- Пользователи с ролью; +- Проверки безопасности; +- Версии; +- Данные. + +### HTTP-Сервис + +- Обзор; +- Свойства; +- URL-шаблоны; +- Методы; +- Обработчики; +- Контракты JSON; +- Безопасность; +- Runtime; +- Тестовые запросы; +- Версии; +- Проверки. + +### План Обмена + +- Обзор; +- Свойства; +- Узлы; +- Состав обмена; +- Авторегистрация; +- Правила регистрации; +- Формы; +- Команды; +- Модуль объекта; +- Модуль менеджера; +- Runtime; +- Данные; +- Версии; +- Проверки. + +### Регламентное Задание + +- Обзор; +- Свойства; +- Расписание; +- Обработчик; +- Параметры; +- Runtime; +- Связанные интеграции; +- Версии; +- Проверки. + +## 6. Узел "Данные" + +Узел "Данные" добавляется к объектам, где это применимо. + +Режимы: + +- `METADATA_ONLY`; +- `SANITIZED_SAMPLE`; +- `TEST_DATA`; +- `FULL_DATA`. + +По умолчанию: + +- `METADATA_ONLY`. + +Правила: + +- `FULL_DATA` только по RBAC; +- `FULL_DATA` всегда audit logged; +- AI не получает данные без explicit approval; +- данные привязаны к environment; +- данные маскируются по умолчанию. diff --git a/docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md b/docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md new file mode 100644 index 0000000..28438c4 --- /dev/null +++ b/docs/frontend/SFERA_PROJECT_SETTINGS_CONTRACT.md @@ -0,0 +1,194 @@ +# SFERA Project Settings Contract + +## 1. Назначение + +Настройки проекта - один из главных экранов SFERA. + +Открывается из Top Project Bar через кнопку рядом с Project selector. + +## 2. Разделы Настроек + +```text +Основные сведения +Источники структуры 1С +Импорт конфигурации +Среды +Агенты +Расширения +Knowledge sources +Privacy +AI policy +Task/session policy +Пользователи и доступ +Интеграции задач +Docker/runtime adapter +ITS/documentation access +Audit +Backup/restore +``` + +## 3. Основные Сведения + +Поля: + +- Название проекта; +- Код проекта; +- Описание; +- Workspace; +- Владелец; +- Тип проекта; +- Язык интерфейса; +- Язык кода 1С по умолчанию: русский / английский; +- Версия платформы; +- Режим совместимости. + +## 4. Источники Структуры 1С + +Поддерживаемые источники: + +- `.cf` файл; +- `.cfe` файл; +- XML dump; +- Live infobase через Designer CLI; +- EPF agent snapshot; +- CFE agent snapshot; +- EDT project; +- Архив выгрузки; +- BSL/XML file tree; +- Context-only configuration; +- Reference configuration. + +Для каждого источника: + +- тип; +- статус; +- последний импорт; +- последняя ошибка; +- версия платформы; +- режим совместимости; +- количество объектов; +- количество модулей; +- количество форм; +- количество расширений. + +## 5. Среды + +- Dev; +- Test; +- Stage; +- Prod. + +Для среды: + +- тип; +- подключение; +- агент; +- источник данных; +- privacy mode; +- разрешение data preview; +- версия платформы; +- активные расширения. + +## 6. Агенты + +- EPF agent; +- CFE agent; +- runtime agent; +- diagnostic agent. + +Поля: + +- agent id; +- version; +- environment; +- last heartbeat; +- status; +- compatibility; +- download/update. + +## 7. Расширения + +Таблица: + +- имя; +- версия; +- назначение; +- активно; +- безопасный режим; +- защита от опасных действий; +- область действия; +- источник; +- последний import; +- статус применимости. + +Действия: + +- загрузить `.cfe`; +- получить из live base; +- обновить snapshot; +- проверить применимость; +- сравнить с основной конфигурацией; +- построить effective configuration. + +## 8. ITS/Documentation Access + +Документация 1С используется для проверки 1С-specific поведения. + +Источники: + +- ITS; +- v8.1c.ru; +- 1C DN; +- локальные knowledge packs. + +ITS credentials нельзя хранить в репозитории. + +Использовать только переменные окружения: + +```dotenv +SFERA_ITS_URL= +SFERA_ITS_USERNAME= +SFERA_ITS_PASSWORD= +``` + +Локальный файл: + +```text +.env.local +``` + +Пример для локальной настройки: + +```dotenv +SFERA_ITS_URL=https://its.1c.ru/db/v838doc#browse:13:-1:7 +SFERA_ITS_USERNAME= +SFERA_ITS_PASSWORD= +``` + +Запрещено: + +- коммитить логин или пароль; +- писать логин или пароль в markdown; +- писать логин или пароль в Dockerfile; +- выводить логин или пароль в logs. + +## 9. Privacy + +- `METADATA_ONLY`; +- `SANITIZED_SAMPLE`; +- `TEST_DATA`; +- `FULL_DATA`. + +По умолчанию: + +- `METADATA_ONLY`. + +## 10. Task/Session Policy + +- `STRICT`; +- `SOFT`; +- `LOCAL_DEV`. + +Enterprise default: + +- `STRICT`. diff --git a/docs/operations/STAND_RUNBOOK.md b/docs/operations/STAND_RUNBOOK.md new file mode 100644 index 0000000..2936da4 --- /dev/null +++ b/docs/operations/STAND_RUNBOOK.md @@ -0,0 +1,282 @@ +# SFERA Stand Runbook + +## Network API + +- API: `http://192.168.200.60:8000` +- Swagger: `http://192.168.200.60:8000/docs` +- Health: `GET /health` +- Summary: `GET /admin/summary` + +## Docker + +This OS runs inside a VM. Do not install or use a local Docker Engine here. + +Use the shared Docker host for Docker/integration stands: + +```bash +docker -H ssh://test-docker ps +``` + +Shared host: + +- SSH alias: `test-docker` / `docker-test` +- Host: `docker-test.cin.su` +- User: `test` + +Integrated SFERA testing must be deployed on `docker-test`, including both backend/server +services and the frontend service. Do not fall back to local Docker Engine for project testing. + +## Neo4j + +Neo4j runs on `docker-test` as container `sfera-neo4j`. + +- Browser: `http://docker-test.cin.su:17474` +- Bolt: `bolt://docker-test.cin.su:17687` +- User: `neo4j` +- Password: `password` + +API uses: + +```text +NEO4J_URI=bolt://docker-test.cin.su:17687 +NEO4J_USER=neo4j +NEO4J_PASSWORD=password +``` + +## Rust BSL Parser + +Build the parser locally: + +```bash +cd rust +cargo build -p bsl-parser +``` + +API indexing consumes the Rust JSON contract automatically when the built parser is found at +`rust\target\debug\bsl-parser.exe`. To force a specific parser binary, set: + +```text +SFERA_BSL_PARSER=rust\target\debug\bsl-parser.exe +``` + +If no parser binary is configured or auto-discovered, `semantic-kernel` uses the built-in Python parser fallback. + +## Runtime Adapter / 1C Access + +`sfera-runtime-adapter` is a separate container/service. It must stay separate from `sfera-api`. + +Modes: + +```text +RUNTIME_ADAPTER_MODE=mock +RUNTIME_ADAPTER_MODE=local_1c +RUNTIME_ADAPTER_MODE=remote_worker +``` + +`mock` is the default Docker mode and does not require a 1C platform inside Linux containers. `local_1c` can normalize EDT/XML/file-tree sources without executing Designer. For `.cf`, `.cfe`, archive, and live infobase sources it first returns a safe `designer_dump_planned` response unless execution is explicitly enabled on a trusted worker. + +Platform discovery: + +- Set `ONEC_DESIGNER_PATH` when the worker has a known Designer CLI path. +- If it is empty, runtime-adapter tries common install roots such as `C:\Program Files\1cv8\*\bin\1cv8.exe`. +- Set `ONEC_DISABLE_AUTO_DISCOVERY=true` to turn discovery off in tests. +- Check `GET /runtime/platform` for `platform_found`, `designer_path`, `discovered_paths`, capabilities, and diagnostics. + +Credentials rule: + +- Do not store live 1C credentials in repository files, compose files, docs, fixtures, or logs. +- Use `credentials_ref` such as `runtime://prompt/live-upo` or a real vault reference. +- Runtime dump plans redact password-like keys in connection strings before returning diagnostics. + +Useful local checks, without storing secrets: + +```powershell +Test-Path "C:\EDT\projects\iFCM-UPO" +Invoke-WebRequest -UseBasicParsing -Uri "http://192.168.200.95/upo/ru_RU/" -TimeoutSec 10 +Get-ChildItem "C:\Program Files\1cv8","C:\Program Files (x86)\1cv8" -Recurse -Filter 1cv8.exe -ErrorAction SilentlyContinue +``` + +## Smoke Flow + +```bash +POST /projects/demo/index +POST /projects/{project_id}/incremental/file +POST /projects/demo/graph/neo4j/project +GET /projects/demo/graph/neo4j/callees/Проведение +GET /projects/demo/graph/neo4j/writes/Проведение +GET /projects/{project_id}/objects/impact/{object_name} +GET /projects/{project_id}/objects/attributes/{object_name} +GET /projects/{project_id}/objects/schema/{object_name} +GET /projects/{project_id}/objects/tabular-sections/{object_name} +GET /projects/{project_id}/objects/tabular-sections/{object_name}/columns +GET /projects/{project_id}/objects/ui/{object_name} +GET /projects/{project_id}/graph/neo4j/objects/attributes/{object_name} +GET /projects/{project_id}/graph/neo4j/objects/schema/{object_name} +GET /projects/{project_id}/graph/neo4j/objects/tabular-sections/{object_name} +GET /projects/{project_id}/graph/neo4j/objects/tabular-sections/{object_name}/columns +GET /projects/{project_id}/graph/neo4j/objects/impact/{object_name} +GET /projects/{project_id}/graph/neo4j/objects/ui/{object_name} +GET /projects/{project_id}/access/objects/{object_name}/roles +GET /projects/{project_id}/access/roles/{role_name}/objects +GET /projects/{project_id}/jobs/scheduled +GET /projects/{project_id}/integrations +GET /projects/{project_id}/graph/neo4j/integrations +GET /projects/{project_id}/graph/neo4j/integrations/{integration_name}/modules +GET /projects/{project_id}/graph/neo4j/access/objects/{object_name}/roles +GET /projects/{project_id}/graph/neo4j/access/roles/{role_name}/objects +POST /knowledge/packs +GET /knowledge/packs +GET /projects/{project_id}/knowledge/schema-coverage +GET /projects/{project_id}/patterns +POST /projects/{project_id}/comments +GET /projects/{project_id}/comments +GET /projects/{project_id}/comments/{target_id} +POST /projects/{project_id}/ownership +GET /projects/{project_id}/ownership +GET /projects/{project_id}/objects/ownership/{object_name} +POST /projects/{project_id}/privacy/markers +GET /projects/{project_id}/privacy/markers +GET /projects/{project_id}/objects/privacy/{object_name} +POST /ai/usage +GET /ai/usage +GET /ai/usage/summary +GET /ai/policy +POST /projects/{project_id}/ai/answer-policy +GET /projects/{project_id}/review +GET /projects/{project_id}/report +GET /graph/neo4j/status +``` + +## Frontend + +Frontend app: + +```text +Z:\codex\SFERA\frontend\sfera-web +``` + +Use the mapped `Z:` drive. It points to `\\nas\MST` and avoids Windows tooling issues with UNC current directories: + +```bat +cd /d Z:\codex\SFERA\frontend\sfera-web +npm run dev +``` + +Always run frontend `npm` commands from the mapped `Z:` drive. Do not use `\\nas\MST\...` as the current directory: Windows `cmd.exe` does not support UNC current directories and falls back to `C:\Windows`, which makes npm scripts fail with missing `package.json`. + +Default URL: + +```text +http://192.168.200.60:3000 +``` + +Editor direct links: + +```text +http://192.168.200.60:3000/editor?project=demo&mode=module +http://192.168.200.60:3000/editor?project=demo&mode=form +http://192.168.200.60:3000/editor?project=demo&mode=events +http://192.168.200.60:3000/editor?project=demo&mode=learning +``` + +Lightweight frontend smoke check against the running stand: + +```bat +cd /d Z:\codex\SFERA\frontend\sfera-web +npm run smoke:editor +``` + +Browser runtime smoke check against the running stand: + +```bat +cd /d Z:\codex\SFERA\frontend\sfera-web +npm run smoke:editor:runtime +``` + +Project Setup / Import Center runtime smoke check against the running stand: + +```bat +cd /d Z:\codex\SFERA\frontend\sfera-web +npm run smoke:project-setup +``` + +Full editor smoke check: + +```bat +cd /d Z:\codex\SFERA\frontend\sfera-web +npm run smoke:editor:all +``` + +Override the checked frontend URL when needed: + +```bat +set SFERA_WEB_URL=http://docker-test.cin.su:3000 +npm run smoke:editor:all +``` + +`smoke:editor` checks server-rendered HTML for the overview and editor modes and retries briefly while a freshly started stand settles. `smoke:editor:runtime` launches the installed Chrome/Edge through `playwright-core`, catches browser runtime errors, verifies Monaco in module mode, opens the Versions tab, clicks a version row, checks full version payload details, and exercises metadata draft preview/apply through the API. `smoke:project-setup` prepares the `default` project through the web API proxy, verifies the new Project Setup / IDE Shell route, and saves a metadata draft to workspace history. Set `SFERA_BROWSER_PATH` if Chrome/Edge is installed in a non-standard location. + +Docker health smoke can include the Project Setup browser smoke: + +```powershell +.\scripts\smoke-test-docker.ps1 ` + -ApiUrl http://docker-test.cin.su:8000 ` + -WebUrl http://docker-test.cin.su:3000 ` + -Neo4jUrl http://docker-test.cin.su:7474 ` + -QdrantUrl http://docker-test.cin.su:6333 ` + -ObjectStorageUrl http://docker-test.cin.su:9000 ` + -IncludeProjectSetupSmoke +``` + +The frontend resolves the API endpoint in this order: + +1. `SFERA_API_URL` +2. `NEXT_PUBLIC_SFERA_API_URL` +3. the current panel host with API port `8000` + +Examples: + +```text +http://192.168.200.60:3000 -> http://192.168.200.60:8000 +http://docker-test.cin.su:3000 -> http://docker-test.cin.su:8000 +http://127.0.0.1:3001 -> http://localhost:8000 +``` + +If the API moves to another address or port, set: + +```text +SFERA_API_URL=http://api-host:8080 +``` + +If only the derived API port changes, set: + +```text +SFERA_API_PORT=8080 +``` + +Do not use `127.0.0.1:8000` as the panel default, because browsers are normally opened from another computer in the LAN. Full Docker stands should run on `docker-test`; local mode is only for the current API + Next.js development loop without a local Docker Engine. + +Browser-side editor actions call the API directly, so API CORS must allow the panel origin. By default the API allows localhost, LAN `192.168.*.*` origins, and `docker-test.cin.su`. Override with `SFERA_CORS_ORIGIN_REGEX` only when the stand moves to a different trusted host pattern. + +Expected demo projection: + +```text +nodes: 5 +edges: 6 +``` + +After a project has been projected once to Neo4j, `POST /projects/{project_id}/incremental/file` automatically applies the SIR delta to that project's Neo4j graph. Check `neo4j_projected` / `neo4j_error` in the response. + +Object impact includes 1C role access when XML contains role rights, for example `Role -> Right object="Документ.ЗаказПокупателя"`. + +Knowledge packs are stored in `knowledge_packs`; importing a BSP/vendor pack also persists enriched `knowledge` records with `pack:{pack_id}` and `vendor:{vendor}` tags for search and coverage. + +Pattern mining is available via `GET /projects/{project_id}/patterns?min_support=2` and reports repeated table reads/writes and repeated routine read/write shapes. + +Ownership is stored in `collaboration_ownership` and is scoped by project + target lineage. Project review reports `Missing 1C object owner` for root 1C objects without an assigned owner; project report includes ownership and unowned-object counters. + +Privacy markers are stored in `privacy_markers` and are scoped by project + target lineage. Review reports `Unclassified sensitive 1C field` for likely sensitive 1C attributes such as ИНН, паспорт, телефон, email, адрес when no privacy classification exists. + +AI usage records are stored in `ai_usage`. Use `GET /ai/usage/summary?project_id=...` for dashboard counters and `GET /ai/policy?user_id=...` before AI actions to show token limits and remaining allowance. + +AI answer policy is available via `POST /projects/{project_id}/ai/answer-policy`. It does not generate an answer; it returns `allowed`, blocking reasons, warnings, matching knowledge records, privacy markers, and remaining token budget. diff --git a/docs/roadmap/COMPLETION_PLAN.md b/docs/roadmap/COMPLETION_PLAN.md new file mode 100644 index 0000000..30e31f3 --- /dev/null +++ b/docs/roadmap/COMPLETION_PLAN.md @@ -0,0 +1,167 @@ +# SFERA Completion Plan + +Дата аудита: 2026-05-10. + +Этот план фиксирует путь к завершению SFERA как продукта. Он не подменяет +`IMPLEMENTATION_ORDER.md`, а добавляет проверяемые критерии готовности и текущий статус. + +## Текущее состояние + +SFERA уже содержит рабочий backend/API, Rust BSL parser, SIR, semantic kernel, +projection/incremental контур, runtime/governance/knowledge/collaboration пакеты и Next.js IDE. + +Текущая проверенная база: + +- Python/API tests: `161 passed`. +- Rust tests: `14 passed`. +- Frontend `typecheck`: passed. +- Frontend production `next build`: passed. +- Editor smoke: passed. +- Editor runtime smoke: passed. + +## Definition Of Done + +Проект считается завершённым для production-ready milestone, когда выполнены все пункты: + +1. Все фазы из `IMPLEMENTATION_ORDER.md` имеют deterministic implementation без placeholder/stub. +2. Все parser bugs покрыты golden fixtures. +3. SIR snapshot validates для BSL/XML metadata projects. +4. Projection and incremental update pass against in-memory and Neo4j-compatible contracts. +5. API exposes project, semantic, governance, knowledge, collaboration and IDE workflows. +6. Frontend builds production bundle and passes editor smoke/runtime checks. +7. Stand runbook is executable on local/NAS and shared Docker host. +8. A single verification command can reproduce core/backend/Rust/frontend checks. + +## Phase Plan + +### Phase 1 — Semantic Core + +Status: mostly complete. + +Completed: + +- `packages/sir`. +- `rust/crates/bsl-parser`. +- Rust `query-parser` foundation. +- Rust `semantic-engine` foundation. +- `packages/semantic-kernel`. +- `packages/projection-engine`. +- `packages/incremental-indexer`. +- Golden fixtures for mixed RU/EN syntax, calls, queries, writes, object writes and recordset writes. +- Same-module routine resolution priority for duplicate routine names. +- SIR diagnostics for malformed BSL routine/query boundaries. +- Incremental diagnostic refresh for changed BSL fragments. +- Routine `Экспорт` / `Export` flags preserved in SIR node attributes. +- BSL control-flow fixture for calls/writes inside loops and try/except blocks. +- Form event handler links from XML metadata to BSL routines. + +Remaining: + +- Keep parser and XML fixtures expanding as new 1C export patterns are encountered. + +### Phase 2 — Object Runtime + +Status: implemented with tests, needs broader fixtures. + +Completed: + +- XML metadata fixtures preserve register dimensions/resources as SIR attributes. +- Semantic versioning classifies object rename/move/update changes. +- Object impact includes form event handlers and their register writes. +- XML fixtures cover child-element forms, commands and role rights. +- Query intelligence reports register read/write dependencies. +- Transaction topology groups routines by written register target. +- Object impact can include scheduled-job integration endpoints from the owning module. + +Remaining: + +- Add more impact/review fixtures for object-level dependency edge cases as new patterns are found. + +### Phase 3 — Runtime Intelligence + +Status: implemented with tests, needs integration depth. + +Remaining: + +- Expand transaction/query intelligence with register movement patterns. +- Connect UI semantics to editor panels and review findings. +- Add scheduled job and integration cross-links to impact reports. + +### Phase 4 — Knowledge System + +Status: implemented with tests. + +Remaining: + +- Add import fixtures for larger BSP/vendor packs. +- Add coverage reports by metadata subtree. + +### Phase 5 — Collaboration + +Status: implemented with tests. + +Remaining: + +- Enforce task/session binding for mutations outside Phase 1 placeholders. +- Add UI flow coverage for comments/ownership/activity. + +### Phase 6 — Governance/Operations + +Status: implemented with tests. + +Remaining: + +- Verify full stand runbook on `test-docker`. +- Add backup/restore and migration smoke checks. + +### Phase 7 — 1C IDE / Authoring + +Status: working Next.js IDE exists and passes smoke; advanced authoring remains product work. + +Completed: + +- Backend and typed frontend API client for symbol search, go to definition and find references. + +Remaining: + +- Wire editor actions for go to definition, find references and symbol search into IDE panels. +- Complete semantic autocomplete from SIR + metadata context. +- Complete guarded apply with preview, semantic diff, impact, review, RBAC/privacy and version record. +- Complete object/form/report designer flows. +- Add browser smoke for key authoring flows. + +### AI Layer + +Status: intentionally gated until semantic truth is stronger. + +Remaining: + +- Add answer/generation policy enforcement to every AI-facing endpoint. +- Add prompt/context builders over SIR, metadata, knowledge, privacy and task/session. +- Add preview-only AI code generation and guarded apply workflow. + +## Execution Order From Here + +1. Keep all current green checks green with `scripts/check_all.ps1`. +2. Finish Phase 1 hardening fixtures and diagnostics. +3. Expand Phase 2/3 fixtures around metadata, impact, query and runtime topology. +4. Finish guarded apply and object-level authoring API. +5. Finish IDE authoring UI and smoke coverage. +6. Add AI pair-programmer only after guarded apply is deterministic. +7. Verify full stand on local/NAS and shared Docker host. + +## Verification + +Use: + +```powershell +.\scripts\check_all.ps1 +``` + +Expected checks: + +- `cargo test && cargo build -p bsl-parser` +- `uv run pytest` +- `npm run typecheck` +- `next build` +- optional frontend smoke checks when API/frontend stand is running. diff --git a/docs/roadmap/IMPLEMENTATION_ORDER.md b/docs/roadmap/IMPLEMENTATION_ORDER.md new file mode 100644 index 0000000..04ccba0 --- /dev/null +++ b/docs/roadmap/IMPLEMENTATION_ORDER.md @@ -0,0 +1,123 @@ +# Реальный порядок реализации + +## Phase 1 — Semantic Core + +1. `packages/sir` +2. `rust/crates/bsl-parser` + - deterministic BSL parser; + - JSON CLI contract for Python semantic-kernel integration. +3. `packages/semantic-kernel` + - current Python parser remains compatible; + - consumes Rust parser JSON as canonical BSL parse source when the CLI is configured or auto-discovered; + - metadata object to BSL module links via `CONTAINS`. +4. `packages/projection-engine` +5. `packages/incremental-indexer` + +## Phase 2 — Object Runtime + +1. `packages/one-c-normalizer` + - BSL source normalization; + - XML metadata extraction for core 1C objects. +2. `packages/semantic-versioning` +3. `packages/semantic-search` +4. `packages/impact-engine` +5. `packages/review-engine` + +## Phase 3 — Runtime Intelligence + +1. `runtime-overlays` +2. `transaction-topology` +3. `query-intelligence` +4. `ui-semantics` +5. `integration-topology` +6. `job-topology` + +## Phase 4 — Knowledge System + +1. global/workspace/project knowledge; ✅ +2. BSP/vendor docs; ✅ +3. pattern mining; ✅ +4. knowledge coverage; ✅ +5. AI answer policy. ✅ + +## Phase 5 — Collaboration + +1. users/workspaces/projects; ✅ +2. tasks/sessions; ✅ +3. comments/discussions; ✅ +4. activity feed; ✅ +5. ownership. ✅ + +## Phase 6 — Governance/Operations + +RBAC ✅, privacy ✅, AI usage ✅, jobs ✅, observability ✅, reports ✅, marketplace ✅, licensing ✅, admin ✅. + +## Phase 7 — 1C IDE / Authoring + +Reference workflow: берём лучшие рабочие паттерны 1С Конфигуратора, но реализуем их как современную AI IDE. Обязательны дерево конфигурации, вкладки открытых объектов, режимы модуль/форма/свойства/события, инспектор, нижние панели проблем/output/diff и быстрый поиск. Дополнительно SFERA должна объединять версии, документацию, знания, обучение, audit и guarded apply. + +1. BSL editor foundation: + - syntax highlighting; + - diagnostics; + - outline; + - go to definition; + - find references; + - symbol search. +2. Semantic autocomplete: + - current procedure/function context; + - local variables and parameters; + - object attributes; + - tabular sections and columns; + - form elements and commands; + - known 1C platform APIs; + - mixed Russian/English 1C syntax. +3. AI pair programmer: + - code continuation; + - procedure/function generation; + - query generation; + - register movement generation; + - command/form handler generation; + - explanation of proposed code. +4. 1C object designer: + - create/update document/catalog/register/common module metadata; + - create/update attributes and tabular sections; + - create/update commands, forms, form elements and reports. +5. Semantic diff and guarded apply: + - preview every manual or AI change; + - impact analysis before apply; + - review findings before apply; + - privacy/RBAC checks; + - object-level version record; + - rollback point. +6. IDE-grade UX: + - editor workspace; + - object tree; + - mode bar: module/form/properties/events/versions/docs/knowledge/training; + - properties inspector; + - form/report designer; + - terminal/command palette; + - AI assistant panel; + - problems/references/output panels. + +7. Documentation/knowledge/training inside IDE: + - docs linked to objects, forms, reports, events and routines; + - project/vendor/BSP knowledge available next to the code; + - team patterns, decisions and examples surfaced by current context; + - learning hints for the selected object and available variables; + - search across code, metadata, docs, versions and discussions. + +## Frontend/UI Gate + +Перед началом UI-этапа перечитать и применить актуальные требования: + +- `docs/design-system.md` +- `docs/codex-ui-guidelines.md` +- `docs/ui-ux-roadmap.md` +- `docs/component-architecture.md` +- `docs/frontend-stack.md` +- `prompts/system-frontend-architect.md` +- `prompts/ui-generation-prompt.md` + +Ключевой принцип: SFERA UI должен ощущаться как современная Enterprise AI IDE / Operating System для 1С, а не legacy CRM. Каждый экран обязан иметь AppShell-compatible layout, loading/error/empty/permission states, адаптивность, права доступа, audit trail для важных действий, таблицы с фильтрами/saved views/bulk actions и AI token/cost impact для AI-действий. Для authoring-экранов обязательны editor/object tree/properties inspector/problems/diff/preview/apply states. + +Язык UI/команд: русский по умолчанию, но каждый пользовательский экран должен иметь выбор английского интерфейса. Команды в интерфейсе также проектируются с русским вариантом по умолчанию и английским вариантом как доступным режимом. 1С-код может смешивать русские и английские ключевые слова в одном тексте; parser/review/UI не должны считать это ошибкой. diff --git a/docs/ui-ux-roadmap.md b/docs/ui-ux-roadmap.md new file mode 100644 index 0000000..40e19d7 --- /dev/null +++ b/docs/ui-ux-roadmap.md @@ -0,0 +1,96 @@ +# UI/UX Roadmap SFERA + +SFERA UI — это современная IDE/операционная среда для 1С, а не CRM. + +Для authoring-экранов 1С Конфигуратор является источником сильных workflow-паттернов: дерево конфигурации, вкладки открытых объектов, режимы модуль/форма/свойства/события, правый инспектор и нижние панели. SFERA не повторяет legacy-внешний вид, а переносит эти паттерны в современную AI IDE. + +## Этап 1 — Foundation + +- AppShell +- Sidebar +- Topbar +- theme tokens +- auth layout +- workspace layout +- command palette +- базовый 1С dashboard +- permissions scaffold +- audit trail scaffold + +## Этап 2 — 1С Semantic Workspace + +- дерево проектов 1С +- дерево объектов конфигурации +- SIR snapshots +- semantic graph view +- object details inspector +- impact analysis +- review findings +- knowledge coverage +- роли и права 1С +- privacy markers + +## Этап 3 — IDE Workspace + +- BSL code editor +- рабочие режимы: модуль, форма, свойства, события, версии, документация, знания, обучение +- подсветка синтаксиса +- diagnostics/problems panel +- outline +- go to definition +- find references +- rename/refactor preview +- semantic search +- command palette для IDE-действий + +## Этап 4 — AI Pair Programmer + +- inline code completion +- продолжение BSL-кода по текущему контексту +- подсказки по доступным переменным, параметрам, реквизитам, табличным частям и формам +- генерация процедур, функций, запросов и движений регистров +- генерация обработчиков команд и форм +- объяснение предложенного кода +- token/cost impact перед AI-действием +- AI decision audit +- объяснение текущих переменных, доступных реквизитов, событий формы и связанных объектов перед генерацией + +## Этап 5 — Object/Form/Report Designer + +- создание и изменение документов, справочников, регистров и общих модулей +- создание реквизитов и табличных частей +- создание команд +- visual form designer +- form elements inspector +- command handler binding +- report designer +- metadata diff + +## Этап 5.5 — Documentation, Knowledge, Training + +- документация объекта и формы рядом с редактором +- связь знаний с lineage, процедурами, запросами, событиями и задачами +- командные паттерны и стандарты кодирования 1С +- обучение разработчика на текущем объекте: что можно безопасно написать, какие переменные доступны, какие риски есть +- поиск по документации, базе знаний, версиям, обсуждениям и изменениям + +## Этап 6 — Guarded Apply + +- preview всех изменений +- semantic diff +- impact analysis до применения +- review до применения +- RBAC/privacy checks +- object-level version record +- task/session binding +- rollback point + +## Этап 7 — Runtime And Operations + +- регламентные задания +- интеграции +- runtime overlays +- operations jobs +- observability +- marketplace/download center +- license/admin panels diff --git a/docs/vscode-cursor-extensions.md b/docs/vscode-cursor-extensions.md new file mode 100644 index 0000000..fbb01f6 --- /dev/null +++ b/docs/vscode-cursor-extensions.md @@ -0,0 +1,49 @@ +# VSCode / Cursor Extensions + +## Обязательно + +```txt +Tailwind CSS IntelliSense +ESLint +Prettier +Pretty TypeScript Errors +Error Lens +GitLens +``` + +## Для UI + +```txt +shadcn/studio +v0 integration / paste workflow +Figma for VS Code +Iconify IntelliSense +``` + +## Для качества кода + +```txt +SonarLint +Import Cost +TypeScript Importer +Path Intellisense +``` + +## Для AI workflow + +```txt +Cursor +GitHub Copilot +Continue +Codeium / Windsurf, если используется отдельно +``` + +## Рекомендация + +Основной UI генерировать через: + +```txt +v0 → вставка в проект → Codex refactor → Cursor review +``` + +Codex не должен генерировать финальный UI без design system rules. diff --git a/examples/bsl/demo_module.bsl b/examples/bsl/demo_module.bsl new file mode 100644 index 0000000..6067124 --- /dev/null +++ b/examples/bsl/demo_module.bsl @@ -0,0 +1,13 @@ +Процедура Проведение() + ПроверитьОстатки(); + Движения.ОстаткиТоваров.Записать(); +КонецПроцедуры + +Процедура ПроверитьОстатки() + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + Остатки.Номенклатура + ИЗ + РегистрНакопления.ОстаткиТоваров КАК Остатки"; +КонецПроцедуры diff --git a/frontend/sfera-web/README.md b/frontend/sfera-web/README.md new file mode 100644 index 0000000..767995d --- /dev/null +++ b/frontend/sfera-web/README.md @@ -0,0 +1,71 @@ +# SFERA Web + +Next.js frontend for the SFERA 1C semantic workspace. + +## Run On This NAS Workspace + +Use the mapped `R:` drive. It points to `\\nas\MST` and avoids Windows tooling issues with UNC current directories. + +```bat +cd /d R:\codex\SFERA\frontend\sfera-web +npm run dev +``` + +Do not run `npm` from the UNC path `\\nas\MST\...`. Windows starts `cmd.exe` in `C:\Windows` for UNC current directories, so package scripts cannot find `package.json`. + +The app resolves the API endpoint in this order: + +1. `SFERA_API_URL` +2. `NEXT_PUBLIC_SFERA_API_URL` +3. the current panel host with API port `8000` + +Examples: + +- `http://192.168.200.60:3000` -> `http://192.168.200.60:8000` +- `http://docker-test.cin.su:3000` -> `http://docker-test.cin.su:8000` +- `http://127.0.0.1:3001` -> `http://localhost:8000` + +If the stand moves to another API port, set: + +```text +SFERA_API_URL=http://api-host:8080 +``` + +You can also override only the derived port: + +```text +SFERA_API_PORT=8080 +``` + +## Checks + +```bat +cd /d R:\codex\SFERA\frontend\sfera-web +node_modules\.bin\tsc.cmd -p tsconfig.json --noEmit +node_modules\.bin\next.cmd build +npm run smoke:editor +npm run smoke:editor:runtime +npm run smoke:project-setup +``` + +`npm run smoke:editor` checks the running stand URL. By default it uses `http://192.168.200.60:3000` and verifies that the overview stays a dashboard while editor modes open directly: + +- `mode=module` +- `mode=form` +- `mode=events` +- `mode=learning` + +Use `SFERA_WEB_URL` to point the smoke check at another host or port. The HTML smoke retries each page briefly while a freshly started stand settles. + +`npm run smoke:editor:runtime` opens the running editor in an installed Chrome/Edge through `playwright-core`. It catches browser runtime failures such as Monaco `Runtime TypeError`, verifies that Monaco renders in `mode=module`, opens `mode=versions`, clicks a version row, checks full version payload details, and exercises metadata draft preview/apply through the API. + +`npm run smoke:project-setup` checks the new Project Setup / Import Center flow. It prepares the `default` project through the web API proxy, verifies that the indexed Project IDE Shell opens, and exercises metadata draft preview/save to workspace history. + +By default the runtime smoke uses the installed Chrome/Edge paths on this Windows stand. Override when needed: + +```text +SFERA_BROWSER_PATH=C:\Path\To\chrome.exe +SFERA_WEB_URL=http://docker-test.cin.su:3000 +``` + +Use `npm run smoke:editor:all` to run both the HTML smoke and browser runtime smoke. Browser-side editor actions require API CORS for the panel origin; the API allows LAN panel origins, localhost, and `docker-test.cin.su` by default. The Project Setup smoke uses the Next.js `/api/sfera/...` proxy and therefore also verifies frontend-to-backend routing. diff --git a/frontend/sfera-web/next-env.d.ts b/frontend/sfera-web/next-env.d.ts new file mode 100644 index 0000000..830fb59 --- /dev/null +++ b/frontend/sfera-web/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/frontend/sfera-web/next.config.mjs b/frontend/sfera-web/next.config.mjs new file mode 100644 index 0000000..7d08ffa --- /dev/null +++ b/frontend/sfera-web/next.config.mjs @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true +}; + +export default nextConfig; diff --git a/frontend/sfera-web/package-lock.json b/frontend/sfera-web/package-lock.json new file mode 100644 index 0000000..ac1c5d9 --- /dev/null +++ b/frontend/sfera-web/package-lock.json @@ -0,0 +1,6487 @@ +{ + "name": "sfera-web", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sfera-web", + "version": "0.1.0", + "dependencies": { + "@monaco-editor/react": "^4.7.0", + "@tanstack/react-table": "^8.21.3", + "clsx": "^2.1.1", + "lucide-react": "^0.468.0", + "monaco-editor": "^0.55.1", + "next": "^15.0.4", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwind-merge": "^2.5.5", + "zod": "^3.24.1", + "zustand": "^5.0.2" + }, + "devDependencies": { + "@types/node": "^22.10.2", + "@types/react": "^19.0.1", + "@types/react-dom": "^19.0.2", + "autoprefixer": "^10.4.20", + "eslint": "^9.16.0", + "eslint-config-next": "^15.0.4", + "playwright-core": "^1.59.1", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.16", + "typescript": "^5.7.2" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emnapi/core": { + "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, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "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, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@monaco-editor/loader": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.7.0.tgz", + "integrity": "sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==", + "license": "MIT", + "dependencies": { + "state-local": "^1.0.6" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz", + "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==", + "license": "MIT", + "dependencies": { + "@monaco-editor/loader": "^1.5.0" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@next/env": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.18.tgz", + "integrity": "sha512-hAV85Ckd9QR6RvH04MEKwsfLTksvFpO47j9xwtoIuvuPnlwecpSi+uZTtm8HirVbtlI2Fnz//xpcSTjFdyJk+g==", + "license": "MIT" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.18.tgz", + "integrity": "sha512-w4MYq8M26a8PNrfto0JosLf5/3ssln1rsyP96g2DkC8uFVymStM5DLSz5ElxxrPRg2XnTMnFo3kREFlhYvxhWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "3.3.1" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.18.tgz", + "integrity": "sha512-w0WvQf1n+txiwns/9pwIQteCJpZTbxzO2SE0FLcwuD4v0WEh1JPOjdyxWL21XwJsdpx8cFRjyzxzCS/siP7HcQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.18.tgz", + "integrity": "sha512-znn71QmDuxm+BOaglihMZfvyySMnNljkVIY5Z2TCssBmm+WqL6c19VhtH5ktFkHa8EZ2bnTUpcNcmNSQsg67og==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.18.tgz", + "integrity": "sha512-yPPe5MNL+igZUa+OsqQJisqSfh6oarIuA1Q0BDxljGJhRQyZeP+WRHh7rs/jZUGMh5aY0YdIjXZG0VohkKkUdw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.18.tgz", + "integrity": "sha512-glaCczEWIrHsokFZ3pP08U4BpKxwIdnT+txdOM32OBgpL9Yw4aqx8NejmgtZQZOdstQ5f0L3CasIZudzCuD+nw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.18.tgz", + "integrity": "sha512-oUfg2EgJmU3R0OCOWiokGFUTvZiPfXtriXiuF3YNxRoROCdgvTedHIzYoeKH34gsZxS/V7mHbfq2hpAHwhH1/A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.18.tgz", + "integrity": "sha512-JLxSP3KTd9iu/bvUMQxH7RJo9xKSHf55/6RPE4a6FTSZygGn7uvZbCej0AHXydwkggQGSD9UddSjwv6Xz5ESfA==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.18.tgz", + "integrity": "sha512-ir1v7enP52K2HNz3tQQvwF+x7VNxBk1ciiZ18WBPvxf4C59IqdfmHPJYK3vH7rSxpuCVw/8C712wTXNAtEp+NA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.18.tgz", + "integrity": "sha512-LIu5me6QTANCd25E7I5uIEfvgQ06RK7tvHAbYo3zCb3VpxQEPvMcSpd87NwUABDT6MbGPdEGR5VRiK4PPTJhQg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.16.1.tgz", + "integrity": "sha512-TvZbIpeKqGQQ7X0zSCvPH9riMSFQFSggnfBjFZ1mEoILW+UuXCKwOoPcgjMwiUtRqFZ8jWhPJc4um14vC6I4ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.18.tgz", + "integrity": "sha512-9v00a+dn2yWVsYDEunWC4g/TcRKVq3r8N5FuZp7u0SGrPvdN9c2yXI9bBuf5Fl0hNCb+QTIePTn5pJs2pwBOQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.2.tgz", + "integrity": "sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/type-utils": "8.59.2", + "@typescript-eslint/utils": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.59.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.2.tgz", + "integrity": "sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.2.tgz", + "integrity": "sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.59.2", + "@typescript-eslint/types": "^8.59.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.2.tgz", + "integrity": "sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.2.tgz", + "integrity": "sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.2.tgz", + "integrity": "sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2", + "@typescript-eslint/utils": "8.59.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.2.tgz", + "integrity": "sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.2.tgz", + "integrity": "sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.59.2", + "@typescript-eslint/tsconfig-utils": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/visitor-keys": "8.59.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "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": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.2.tgz", + "integrity": "sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.2", + "@typescript-eslint/types": "8.59.2", + "@typescript-eslint/typescript-estree": "8.59.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.2.tgz", + "integrity": "sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "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" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.4.tgz", + "integrity": "sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.28", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.28.tgz", + "integrity": "sha512-Ic44hnOtFIgravCunj1ifSoQPSUrkNiJuH9Mf6jr2jjoA74icqV8wU0KuadXeOR8zuIJMOoTv0GuQjZ9ZYNMeA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "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": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "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" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001792", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz", + "integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "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" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "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/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dompurify": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.353", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.353.tgz", + "integrity": "sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", + "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-next": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.18.tgz", + "integrity": "sha512-HuoJU6uUPD00eyiud78IBnT4HLhztFj2V+ild2Uon5ZUrYZKe0Olu2QRD99e9IgL4/H1eg5Onka3BsfRW2U0Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/eslint-plugin-next": "15.5.18", + "@rushstack/eslint-patch": "^1.10.3", + "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^5.0.0" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "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": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.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", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lucide-react": { + "version": "0.468.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz", + "integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/monaco-editor": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", + "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "license": "MIT", + "dependencies": { + "dompurify": "3.2.7", + "marked": "14.0.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "15.5.18", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.18.tgz", + "integrity": "sha512-eKL8zUJkX9Y5lE+RX/2YJoItVdGlIscyVyboeD9wSpp0PaGqjoA4tTpT2qPqz9ax+5IzGESyLSeZ/RCwbSZ2uQ==", + "license": "MIT", + "dependencies": { + "@next/env": "15.5.18", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.5.18", + "@next/swc-darwin-x64": "15.5.18", + "@next/swc-linux-arm64-gnu": "15.5.18", + "@next/swc-linux-arm64-musl": "15.5.18", + "@next/swc-linux-x64-gnu": "15.5.18", + "@next/swc-linux-x64-musl": "15.5.18", + "@next/swc-win32-arm64-msvc": "15.5.18", + "@next/swc-win32-x64-msvc": "15.5.18", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/node-releases": { + "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" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "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", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "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/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/playwright-core": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", + "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-import/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "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/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.6" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.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/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.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.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/state-local": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", + "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/tailwind-merge": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", + "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/tailwindcss/node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "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/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "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": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zustand": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.13.tgz", + "integrity": "sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/frontend/sfera-web/package.json b/frontend/sfera-web/package.json new file mode 100644 index 0000000..8f17a78 --- /dev/null +++ b/frontend/sfera-web/package.json @@ -0,0 +1,41 @@ +{ + "name": "sfera-web", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --hostname 0.0.0.0 --port 3000", + "build": "next build", + "start": "next start --hostname 0.0.0.0 --port 3000", + "lint": "next lint", + "smoke:editor": "node scripts/smoke-editor-modes.mjs", + "smoke:editor:all": "npm run smoke:editor && npm run smoke:editor:runtime", + "smoke:editor:runtime": "node scripts/smoke-editor-runtime.mjs", + "smoke:project-setup": "node scripts/smoke-project-setup.mjs", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@monaco-editor/react": "^4.7.0", + "@tanstack/react-table": "^8.21.3", + "clsx": "^2.1.1", + "lucide-react": "^0.468.0", + "monaco-editor": "^0.55.1", + "next": "^15.0.4", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwind-merge": "^2.5.5", + "zod": "^3.24.1", + "zustand": "^5.0.2" + }, + "devDependencies": { + "@types/node": "^22.10.2", + "@types/react": "^19.0.1", + "@types/react-dom": "^19.0.2", + "autoprefixer": "^10.4.20", + "eslint": "^9.16.0", + "eslint-config-next": "^15.0.4", + "playwright-core": "^1.59.1", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.16", + "typescript": "^5.7.2" + } +} diff --git a/frontend/sfera-web/postcss.config.mjs b/frontend/sfera-web/postcss.config.mjs new file mode 100644 index 0000000..5c84425 --- /dev/null +++ b/frontend/sfera-web/postcss.config.mjs @@ -0,0 +1,8 @@ +const config = { + plugins: { + tailwindcss: {}, + autoprefixer: {} + } +}; + +export default config; diff --git a/frontend/sfera-web/public/icons/1c-metadata/LICENSE.MetadataViewer1C.md b/frontend/sfera-web/public/icons/1c-metadata/LICENSE.MetadataViewer1C.md new file mode 100644 index 0000000..8899922 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/LICENSE.MetadataViewer1C.md @@ -0,0 +1,25 @@ +The MIT License (MIT) +===================== + +Copyright © 2026 Andrew Ponomarev + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the “Software”), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/frontend/sfera-web/public/icons/1c-metadata/README.md b/frontend/sfera-web/public/icons/1c-metadata/README.md new file mode 100644 index 0000000..4b157c8 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/README.md @@ -0,0 +1,9 @@ +1C-like metadata icons +====================== + +Source: MetadataViewer1C by Andrew Ponomarev +Repository: https://github.com/asweetand-a11y/MetadataViewer1C +License: MIT, see LICENSE.MetadataViewer1C.md + +These SVGs are used as a visually similar open-source icon set for SFERA's 1C metadata tree. +They are not extracted from the 1C:Enterprise Configurator executable or distribution. diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/accountingFlag.svg b/frontend/sfera-web/public/icons/1c-metadata/light/accountingFlag.svg new file mode 100644 index 0000000..651cdfa --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/accountingFlag.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/accountingRegister.svg b/frontend/sfera-web/public/icons/1c-metadata/light/accountingRegister.svg new file mode 100644 index 0000000..2c01bf0 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/accountingRegister.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/accumulationRegister.svg b/frontend/sfera-web/public/icons/1c-metadata/light/accumulationRegister.svg new file mode 100644 index 0000000..2d1b8b4 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/accumulationRegister.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/attribute.svg b/frontend/sfera-web/public/icons/1c-metadata/light/attribute.svg new file mode 100644 index 0000000..2e7f08f --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/attribute.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/businessProcess.svg b/frontend/sfera-web/public/icons/1c-metadata/light/businessProcess.svg new file mode 100644 index 0000000..75b4042 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/businessProcess.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/calculationRegister.svg b/frontend/sfera-web/public/icons/1c-metadata/light/calculationRegister.svg new file mode 100644 index 0000000..43a7042 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/calculationRegister.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/catalog.svg b/frontend/sfera-web/public/icons/1c-metadata/light/catalog.svg new file mode 100644 index 0000000..76ce186 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/catalog.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfAccount.svg b/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfAccount.svg new file mode 100644 index 0000000..2b6961d --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfAccount.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfCalculationType.svg b/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfCalculationType.svg new file mode 100644 index 0000000..20b22a9 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfCalculationType.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfCharacteristicType.svg b/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfCharacteristicType.svg new file mode 100644 index 0000000..cb4e3d3 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/chartsOfCharacteristicType.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/column.svg b/frontend/sfera-web/public/icons/1c-metadata/light/column.svg new file mode 100644 index 0000000..7163935 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/column.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/command.svg b/frontend/sfera-web/public/icons/1c-metadata/light/command.svg new file mode 100644 index 0000000..1148384 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/command.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/common.svg b/frontend/sfera-web/public/icons/1c-metadata/light/common.svg new file mode 100644 index 0000000..999de3b --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/common.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/commonModule.svg b/frontend/sfera-web/public/icons/1c-metadata/light/commonModule.svg new file mode 100644 index 0000000..fac7f34 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/commonModule.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/constant.svg b/frontend/sfera-web/public/icons/1c-metadata/light/constant.svg new file mode 100644 index 0000000..ec12f4b --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/constant.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/dataProcessor.svg b/frontend/sfera-web/public/icons/1c-metadata/light/dataProcessor.svg new file mode 100644 index 0000000..fab992d --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/dataProcessor.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/dimension.svg b/frontend/sfera-web/public/icons/1c-metadata/light/dimension.svg new file mode 100644 index 0000000..3061b0a --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/dimension.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/document.svg b/frontend/sfera-web/public/icons/1c-metadata/light/document.svg new file mode 100644 index 0000000..949a376 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/document.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/documentJournal.svg b/frontend/sfera-web/public/icons/1c-metadata/light/documentJournal.svg new file mode 100644 index 0000000..ffd82f2 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/documentJournal.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/documentNumerator.svg b/frontend/sfera-web/public/icons/1c-metadata/light/documentNumerator.svg new file mode 100644 index 0000000..a4682f1 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/documentNumerator.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/editManager.svg b/frontend/sfera-web/public/icons/1c-metadata/light/editManager.svg new file mode 100644 index 0000000..1bbf634 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/editManager.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/editObject.svg b/frontend/sfera-web/public/icons/1c-metadata/light/editObject.svg new file mode 100644 index 0000000..bf049f0 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/editObject.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/enum.svg b/frontend/sfera-web/public/icons/1c-metadata/light/enum.svg new file mode 100644 index 0000000..5f7331d --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/enum.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/eventSubscription.svg b/frontend/sfera-web/public/icons/1c-metadata/light/eventSubscription.svg new file mode 100644 index 0000000..894cffa --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/eventSubscription.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/exchangePlan.svg b/frontend/sfera-web/public/icons/1c-metadata/light/exchangePlan.svg new file mode 100644 index 0000000..7ca9972 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/exchangePlan.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/extDimensionAccountingFlag.svg b/frontend/sfera-web/public/icons/1c-metadata/light/extDimensionAccountingFlag.svg new file mode 100644 index 0000000..b034b05 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/extDimensionAccountingFlag.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/externalDataSource.svg b/frontend/sfera-web/public/icons/1c-metadata/light/externalDataSource.svg new file mode 100644 index 0000000..20603b3 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/externalDataSource.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/filterCriteria.svg b/frontend/sfera-web/public/icons/1c-metadata/light/filterCriteria.svg new file mode 100644 index 0000000..4bdb93b --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/filterCriteria.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/folder.svg b/frontend/sfera-web/public/icons/1c-metadata/light/folder.svg new file mode 100644 index 0000000..5f1638b --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/folder.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/form.svg b/frontend/sfera-web/public/icons/1c-metadata/light/form.svg new file mode 100644 index 0000000..244ada3 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/form.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/http.svg b/frontend/sfera-web/public/icons/1c-metadata/light/http.svg new file mode 100644 index 0000000..99eda32 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/http.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/informationRegister.svg b/frontend/sfera-web/public/icons/1c-metadata/light/informationRegister.svg new file mode 100644 index 0000000..2a3d98c --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/informationRegister.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/operation.svg b/frontend/sfera-web/public/icons/1c-metadata/light/operation.svg new file mode 100644 index 0000000..19657b6 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/operation.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/parameter.svg b/frontend/sfera-web/public/icons/1c-metadata/light/parameter.svg new file mode 100644 index 0000000..6cfb1a4 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/parameter.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/picture.svg b/frontend/sfera-web/public/icons/1c-metadata/light/picture.svg new file mode 100644 index 0000000..a429af3 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/picture.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/report.svg b/frontend/sfera-web/public/icons/1c-metadata/light/report.svg new file mode 100644 index 0000000..045ff5c --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/report.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/resource.svg b/frontend/sfera-web/public/icons/1c-metadata/light/resource.svg new file mode 100644 index 0000000..cc9be51 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/resource.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/role.svg b/frontend/sfera-web/public/icons/1c-metadata/light/role.svg new file mode 100644 index 0000000..2e12309 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/role.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/scheduledJob.svg b/frontend/sfera-web/public/icons/1c-metadata/light/scheduledJob.svg new file mode 100644 index 0000000..519cf76 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/scheduledJob.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/sequence.svg b/frontend/sfera-web/public/icons/1c-metadata/light/sequence.svg new file mode 100644 index 0000000..377f1bb --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/sequence.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/sessionParameter.svg b/frontend/sfera-web/public/icons/1c-metadata/light/sessionParameter.svg new file mode 100644 index 0000000..5c6d17e --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/sessionParameter.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/style.svg b/frontend/sfera-web/public/icons/1c-metadata/light/style.svg new file mode 100644 index 0000000..409594e --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/style.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/subsystem.svg b/frontend/sfera-web/public/icons/1c-metadata/light/subsystem.svg new file mode 100644 index 0000000..f6dac2b --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/subsystem.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/tabularSection.svg b/frontend/sfera-web/public/icons/1c-metadata/light/tabularSection.svg new file mode 100644 index 0000000..cadf870 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/tabularSection.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/task.svg b/frontend/sfera-web/public/icons/1c-metadata/light/task.svg new file mode 100644 index 0000000..7cd24fd --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/task.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/template.svg b/frontend/sfera-web/public/icons/1c-metadata/light/template.svg new file mode 100644 index 0000000..c6437e2 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/template.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/urlTemplate.svg b/frontend/sfera-web/public/icons/1c-metadata/light/urlTemplate.svg new file mode 100644 index 0000000..dad44bb --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/urlTemplate.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/ws.svg b/frontend/sfera-web/public/icons/1c-metadata/light/ws.svg new file mode 100644 index 0000000..c2fcad5 --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/ws.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/public/icons/1c-metadata/light/wsLink.svg b/frontend/sfera-web/public/icons/1c-metadata/light/wsLink.svg new file mode 100644 index 0000000..25eaf1e --- /dev/null +++ b/frontend/sfera-web/public/icons/1c-metadata/light/wsLink.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/sfera-web/scripts/smoke-editor-modes.mjs b/frontend/sfera-web/scripts/smoke-editor-modes.mjs new file mode 100644 index 0000000..6b09483 --- /dev/null +++ b/frontend/sfera-web/scripts/smoke-editor-modes.mjs @@ -0,0 +1,165 @@ +const baseUrl = process.env.SFERA_WEB_URL ?? "http://192.168.200.60:3000"; +const projectId = process.env.SFERA_PROJECT_ID ?? "demo"; +const routine = encodeURIComponent(process.env.SFERA_ROUTINE ?? "Проведение"); +const attempts = Number(process.env.SFERA_SMOKE_ATTEMPTS ?? "5"); + +const checks = [ + { + name: "root opens IDE workspace", + url: `${baseUrl}/?lang=ru&project=${projectId}`, + mustInclude: [ + "SFERA", + "data-top-project-bar", + "data-top-bar-logo", + "data-top-bar-selector=\"workspace\"", + "data-top-bar-selector=\"project\"", + "data-top-bar-selector=\"environment\"", + "data-top-bar-selector=\"active-task\"", + "data-top-bar-action=\"project-settings\"", + "data-top-bar-action=\"create-project\"", + "data-top-bar-badge=\"api-status\"", + "data-top-bar-badge=\"agent-status\"", + "data-top-bar-language", + "data-top-bar-button=\"profile\"", + "Ctrl+K", + "data-status-bar", + "data-status-item=\"current-user\"" + ], + mustNotInclude: ["Открыть в редакторе"] + }, + { + name: "root opens IDE workspace (en)", + url: `${baseUrl}/?lang=en&project=${projectId}`, + mustInclude: [ + "SFERA", + "data-top-project-bar", + "data-top-bar-logo", + "data-top-bar-selector=\"workspace\"", + "data-top-bar-selector=\"project\"", + "data-top-bar-selector=\"environment\"", + "data-top-bar-selector=\"active-task\"", + "data-top-bar-action=\"project-settings\"", + "data-top-bar-action=\"create-project\"", + "data-top-bar-badge=\"api-status\"", + "data-top-bar-badge=\"agent-status\"", + "data-top-bar-language", + "data-top-bar-button=\"profile\"", + "Ctrl+K", + "data-status-bar", + "data-status-item=\"current-user\"" + ], + mustNotInclude: ["Open in editor"] + }, + { + name: "project settings route", + url: `${baseUrl}/project-settings`, + mustInclude: [ + "Project Settings", + "Import Center", + "REFERENCE_CONFIGURATION", + "Reference config", + "data-import-action=\"REFERENCE_CONFIGURATION:import\"", + "data-import-action=\"XML_DUMP:check\"", + "data-settings-section=\"docker-runtime-adapter\"", + "data-settings-section=\"its-documentation-access\"", + "Пользователи и доступ", + "Интеграции задач", + "Docker/runtime adapter", + "ITS/documentation access", + "Audit", + "Backup/restore", + "SFERA_ITS_URL", + "SFERA_ITS_USERNAME", + "SFERA_ITS_PASSWORD", + "https://its.1c.ru/db/v838doc#browse:13:-1:7", + ".env.local", + "<set locally>" + ], + mustNotInclude: ["Открыть в редакторе"] + }, + { + name: "project settings route (en)", + url: `${baseUrl}/project-settings?lang=en`, + mustInclude: [ + "Project Settings", + "Import Center", + "REFERENCE_CONFIGURATION", + "Reference config", + "data-import-action=\"REFERENCE_CONFIGURATION:import\"", + "data-import-action=\"XML_DUMP:check\"", + "data-settings-section=\"task-session-policy\"", + "data-settings-section=\"docker-runtime-adapter\"", + "data-settings-section=\"its-documentation-access\"", + "Task/session policy", + "Docker/runtime adapter", + "ITS/documentation access", + "Audit", + "Backup/restore", + "SFERA_ITS_URL", + "SFERA_ITS_USERNAME", + "SFERA_ITS_PASSWORD", + ".env.local", + "<set locally>" + ], + mustNotInclude: ["Open in editor"] + }, + { + name: "module mode", + url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=module&routine=${routine}`, + mustInclude: ["data-ide-workspace", "data-left-navigation-panel", "data-right-context-inspector", "data-open-objects-bar", "data-open-document-pin", "data-open-document-close", "data-fallback-tree-search", "data-fallback-tree-filters", "Alt+1 Alt+2 Alt+3", "Редактор BSL", "Код модуля не загружен", "Выберите реальный модуль", "Основная конфигурация", "Расширение: <Имя>", "SFERA", "Среды"] + }, + { + name: "form mode", + url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=form&routine=${routine}`, + mustInclude: ["Дизайнер формы", "Провести и закрыть", "Товары"] + }, + { + name: "events mode", + url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=events&routine=${routine}`, + mustInclude: ["Инспектор событий", "ПриСозданииНаСервере", "ПередЗаписью"] + }, + { + name: "learning mode", + url: `${baseUrl}/editor?lang=ru&project=${projectId}&mode=learning&routine=${routine}`, + mustInclude: ["Обучение", "переменные доступны", "стандарты команды"] + } +]; + +for (const check of checks) { + let lastError; + for (let attempt = 1; attempt <= attempts; attempt += 1) { + try { + await runCheck(check); + console.log(`ok ${check.name}`); + lastError = undefined; + break; + } catch (error) { + lastError = error; + if (attempt < attempts) { + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + } + } + if (lastError) { + throw lastError; + } +} + +async function runCheck(check) { + const response = await fetch(check.url, { headers: { Accept: "text/html" } }); + if (!response.ok) { + throw new Error(`${check.name}: ${response.status} ${response.statusText}`); + } + + const html = await response.text(); + for (const expected of check.mustInclude ?? []) { + if (!html.includes(expected)) { + throw new Error(`${check.name}: missing "${expected}"`); + } + } + for (const forbidden of check.mustNotInclude ?? []) { + if (html.includes(forbidden)) { + throw new Error(`${check.name}: unexpected "${forbidden}"`); + } + } +} diff --git a/frontend/sfera-web/scripts/smoke-editor-runtime.mjs b/frontend/sfera-web/scripts/smoke-editor-runtime.mjs new file mode 100644 index 0000000..2e6f8c9 --- /dev/null +++ b/frontend/sfera-web/scripts/smoke-editor-runtime.mjs @@ -0,0 +1,292 @@ +import { chromium } from "playwright-core"; +import { existsSync } from "node:fs"; + +const baseUrl = process.env.SFERA_WEB_URL ?? "http://192.168.200.60:3000"; +const projectId = process.env.SFERA_PROJECT_ID ?? "demo"; +const uniqueSuffix = Date.now().toString(36); +const browserPath = + process.env.SFERA_BROWSER_PATH ?? + [ + "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", + "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", + "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe" + ].find((path) => existsSync(path)); + +if (!browserPath) { + throw new Error("No installed Chrome or Edge browser found. Set SFERA_BROWSER_PATH."); +} + +const runtimeErrors = []; +const browser = await chromium.launch({ + executablePath: browserPath, + headless: true +}); + +function assertNoFatalRuntimeErrors(stage) { + const fatalErrors = runtimeErrors.filter((message) => { + return ( + message.includes("Runtime TypeError") || + message.includes("Cannot read properties") || + message.includes("Unhandled Runtime Error") + ); + }); + if (fatalErrors.length > 0) { + throw new Error(`${stage} failed:\n${fatalErrors.join("\n")}`); + } +} + +async function collapseBottomPanelIfOpen(page) { + if ((await page.locator("[data-bottom-tool-panel]").count()) > 0) { + await page.keyboard.press("Alt+3"); + await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 }); + } +} + +try { + const page = await browser.newPage(); + await page.setViewportSize({ width: 1680, height: 1050 }); + page.on("pageerror", (error) => { + runtimeErrors.push(`pageerror: ${error.message}`); + }); + page.on("console", (message) => { + if (message.type() === "error") { + runtimeErrors.push(`console: ${message.text()}`); + } + }); + + const response = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=module`, { + waitUntil: "load", + timeout: 60000 + }); + if (!response?.ok()) { + throw new Error(`editor runtime smoke: ${response?.status()} ${response?.statusText()}`); + } + + await page.getByRole("heading", { name: "Редактор BSL" }).waitFor({ state: "visible", timeout: 15000 }); + await page.getByRole("heading", { name: "Семантический diff" }).waitFor({ state: "visible", timeout: 15000 }); + for (const marker of ["snapshot", "agent", "parser", "diagnostics", "active-task", "privacy", "ai-tokens", "current-user"]) { + await page.locator(`[data-status-item="${marker}"]`).waitFor({ state: "visible", timeout: 15000 }); + } + await page.locator("[data-global-search-input]").waitFor({ state: "visible", timeout: 15000 }); + await page.keyboard.press("Control+K"); + const globalSearchFocused = await page.locator("[data-global-search-input]").evaluate((input) => document.activeElement === input); + if (!globalSearchFocused) { + throw new Error("Ctrl+K did not focus global search"); + } + await page.evaluate(() => { + window.dispatchEvent(new KeyboardEvent("keydown", { key: "F5", bubbles: true, cancelable: true })); + }); + await page.locator("[data-run-check-status]").waitFor({ state: "visible", timeout: 15000 }); + await page.locator("[data-left-navigation-panel]").waitFor({ state: "visible", timeout: 15000 }); + const hasVirtualScrollContainer = + (await page.locator("[data-virtual-scroll]").count()) > 0 || + (await page.locator("[data-fallback-tree-scroll]").count()) > 0; + if (!hasVirtualScrollContainer) { + throw new Error("Left navigation panel has no virtual/fallback scroll container marker"); + } + await page.locator("[data-right-context-inspector]").waitFor({ state: "visible", timeout: 15000 }); + await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 }); + for (const tabName of ["Проблемы", "Semantic diff", "Вывод", "История", "Тесты", "AI"]) { + await page.locator("[data-bottom-tool-panel]").getByText(tabName).first().waitFor({ state: "visible", timeout: 15000 }); + } + await page.locator("[data-fallback-tree-search-input]").fill("SFERA"); + await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 }); + await page.locator("[data-fallback-tree-search-input]").fill(""); + await page.locator("[data-fallback-tree-filter='sfera']").click(); + await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 }); + await page.locator("[data-fallback-tree-filter='all']").click(); + const lazyFilterCount = await page.locator("[data-lazy-tree-filter]").count(); + if (lazyFilterCount > 0) { + await page.locator("[data-lazy-tree-filter='sfera']").click(); + await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 }); + await page.locator("[data-lazy-tree-filter='all']").click(); + } + await page.keyboard.press("Alt+1"); + await page.locator("[data-left-navigation-panel]").waitFor({ state: "detached", timeout: 15000 }); + await page.locator("[data-panel-rail]").first().click(); + await page.locator("[data-left-navigation-panel]").waitFor({ state: "visible", timeout: 15000 }); + await page.keyboard.press("Alt+2"); + await page.locator("[data-right-context-inspector]").waitFor({ state: "detached", timeout: 15000 }); + await page.locator("[data-panel-rail]").last().click(); + await page.locator("[data-right-context-inspector]").waitFor({ state: "visible", timeout: 15000 }); + await page.keyboard.press("Alt+3"); + await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 }); + await page.getByRole("button", { name: "Нижняя панель" }).click(); + await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 }); + await page.keyboard.press("Alt+3"); + await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 }); + const activeDocumentBeforeNext = await page.locator('[data-open-document][aria-pressed="true"]').first().getAttribute("data-open-document"); + const openDocumentCount = await page.locator("[data-open-document]").count(); + if (openDocumentCount < 2) { + throw new Error("Open Objects Bar has fewer than two switchable objects"); + } + await page.evaluate(() => { + window.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", ctrlKey: true, bubbles: true, cancelable: true })); + }); + const activeDocumentAfterNext = await page.locator('[data-open-document][aria-pressed="true"]').first().getAttribute("data-open-document"); + if (!activeDocumentAfterNext || activeDocumentAfterNext === activeDocumentBeforeNext) { + throw new Error("Ctrl+Tab did not switch the active open object"); + } + await page.evaluate(() => { + window.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", ctrlKey: true, shiftKey: true, bubbles: true, cancelable: true })); + }); + await page.locator(`[data-open-document="${activeDocumentBeforeNext}"][aria-pressed="true"]`).waitFor({ state: "visible", timeout: 15000 }); + await page.locator(`[data-open-document-pin="${activeDocumentAfterNext}"]`).click(); + const pinnedCloseButton = page.locator(`[data-open-document-close="${activeDocumentAfterNext}"]`); + if (!(await pinnedCloseButton.isDisabled())) { + throw new Error("Pinned open object close button is not disabled"); + } + await page.locator(`[data-open-document-pin="${activeDocumentAfterNext}"]`).click(); + await pinnedCloseButton.click(); + await page.locator(`[data-open-document="${activeDocumentAfterNext}"]`).waitFor({ state: "detached", timeout: 15000 }); + const ctrlWCandidate = await page.evaluate(() => { + const buttons = Array.from(document.querySelectorAll("[data-open-document]")); + const candidate = buttons.find((button) => button.getAttribute("data-open-document-mode") !== "module"); + return candidate?.getAttribute("data-open-document") ?? null; + }); + if (ctrlWCandidate) { + const targetTab = page.locator(`[data-open-document="${ctrlWCandidate}"]`); + await targetTab.click(); + await page.evaluate(() => { + window.dispatchEvent(new KeyboardEvent("keydown", { key: "w", ctrlKey: true, bubbles: true, cancelable: true })); + }); + await targetTab.waitFor({ state: "detached", timeout: 15000 }); + const moduleTabs = page.locator('[data-open-document-mode="module"]'); + const moduleTabCount = await moduleTabs.count(); + if (moduleTabCount > 0) { + await moduleTabs.first().click(); + } + } + const openObjectsState = await page.evaluate((storageKey) => window.localStorage.getItem(storageKey), `sfera.open-objects.${projectId}`); + if (!openObjectsState?.includes(activeDocumentAfterNext)) { + throw new Error("Open Objects Bar state was not persisted"); + } + await page.reload({ waitUntil: "load", timeout: 60000 }); + await page.getByRole("heading", { name: "Редактор BSL" }).waitFor({ state: "visible", timeout: 15000 }); + const restoredState = await page.evaluate((storageKey) => window.localStorage.getItem(storageKey), `sfera.open-objects.${projectId}`); + if (restoredState !== openObjectsState) { + throw new Error("Open Objects Bar state was not restored after reload"); + } + await page.locator(`[data-open-document="${activeDocumentAfterNext}"]`).waitFor({ state: "detached", timeout: 15000 }); + const restoredModuleTabs = page.locator('[data-open-document-mode="module"]'); + if ((await restoredModuleTabs.count()) > 0) { + await restoredModuleTabs.first().click(); + } + await page.locator(".monaco-editor").waitFor({ state: "visible", timeout: 15000 }); + await page.locator("#symbol-search-input").fill("Проверить"); + await page.locator("#symbol-search-input").press("Enter"); + await page.locator("[data-symbol-result]").first().waitFor({ state: "visible", timeout: 15000 }); + await page.locator('button[data-editor-action="find-usages"]').click(); + await page.locator("[data-symbol-references]").waitFor({ state: "visible", timeout: 15000 }); + const applyButton = page.locator('button[data-editor-action="apply-to-sfera"]'); + await applyButton.waitFor({ state: "visible", timeout: 15000 }); + if (await applyButton.isEnabled()) { + await applyButton.click(); + await page.getByText("Записано в SFERA").waitFor({ state: "visible", timeout: 15000 }); + } + assertNoFatalRuntimeErrors("editor module runtime smoke"); + + const versionsResponse = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=versions`, { + waitUntil: "load", + timeout: 60000 + }); + if (!versionsResponse?.ok()) { + throw new Error(`editor versions runtime smoke: ${versionsResponse?.status()} ${versionsResponse?.statusText()}`); + } + await page.getByRole("heading", { name: "Версии" }).waitFor({ state: "visible", timeout: 15000 }); + await collapseBottomPanelIfOpen(page); + await page.getByText("Линия версий").first().waitFor({ state: "visible", timeout: 15000 }); + const versionButtons = page.locator("button[data-version-id]"); + const versionButtonCount = await versionButtons.count(); + if (versionButtonCount > 0) { + await versionButtons.first().click(); + await page.getByText("Полные данные").waitFor({ state: "visible", timeout: 15000 }); + } + assertNoFatalRuntimeErrors("editor versions runtime smoke"); + + const rollbackButtons = page.locator('button[data-editor-action="rollback-plan"]'); + const rollbackButtonCount = await rollbackButtons.count(); + if (rollbackButtonCount > 0) { + await rollbackButtons.first().click(); + await page.locator("[data-rollback-preview]").waitFor({ state: "visible", timeout: 15000 }); + const applyRollbackButton = page.locator('button[data-editor-action="apply-rollback"]'); + await applyRollbackButton.waitFor({ state: "visible", timeout: 15000 }); + if (await applyRollbackButton.isEnabled()) { + await applyRollbackButton.click(); + await page.locator("[data-rollback-apply-message]").waitFor({ state: "visible", timeout: 15000 }); + } + } + assertNoFatalRuntimeErrors("editor rollback runtime smoke"); + + const metadataResponse = await page.goto(`${baseUrl}/editor?lang=ru&project=${encodeURIComponent(projectId)}&mode=properties`, { + waitUntil: "load", + timeout: 60000 + }); + if (!metadataResponse?.ok()) { + throw new Error(`editor metadata runtime smoke: ${metadataResponse?.status()} ${metadataResponse?.statusText()}`); + } + await page.getByRole("heading", { name: "Свойства" }).waitFor({ state: "visible", timeout: 15000 }); + await collapseBottomPanelIfOpen(page); + await page.getByLabel("Имя объекта").fill(`АвтоОбъект${uniqueSuffix}`); + await page.getByLabel("Синоним").fill(`Авто объект ${uniqueSuffix}`); + const addAttributeButton = page.locator('button[data-editor-action="add-metadata-attribute"]'); + await addAttributeButton.waitFor({ state: "visible", timeout: 15000 }); + await addAttributeButton.click(); + await page.getByRole("textbox", { name: "Имя реквизита" }).nth(1).fill("Комментарий"); + await page.getByRole("textbox", { name: "Тип" }).nth(1).fill("Строка250"); + const addFormButton = page.locator('button[data-editor-action="add-metadata-form"]'); + await addFormButton.waitFor({ state: "visible", timeout: 15000 }); + await addFormButton.click(); + await page.getByRole("textbox", { name: "Имя формы" }).last().fill(`ФормаВыбора${uniqueSuffix}`); + const addCommandButton = page.locator('button[data-editor-action="add-metadata-command"]'); + await addCommandButton.waitFor({ state: "visible", timeout: 15000 }); + await addCommandButton.click(); + await page.getByRole("textbox", { name: "Имя команды" }).last().fill(`Отправить${uniqueSuffix}`); + await page.getByRole("textbox", { name: "Обработчик" }).last().fill(`Отправить${uniqueSuffix}Команда`); + const metadataButton = page.locator('button[data-editor-action="apply-metadata-object"]'); + await metadataButton.waitFor({ state: "visible", timeout: 15000 }); + if (await metadataButton.isEnabled()) { + await metadataButton.click(); + const draftMessage = page.locator("[data-metadata-draft-message]"); + await draftMessage.waitFor({ state: "visible", timeout: 15000 }); + try { + await page.locator("[data-metadata-draft-preview]").waitFor({ state: "visible", timeout: 15000 }); + } catch (error) { + throw new Error(`metadata draft preview did not appear: ${await draftMessage.textContent()}`); + } + } + assertNoFatalRuntimeErrors("editor metadata runtime smoke"); + + const englishResponse = await page.goto(`${baseUrl}/editor?lang=en&project=${encodeURIComponent(projectId)}&mode=module`, { + waitUntil: "load", + timeout: 60000 + }); + if (!englishResponse?.ok()) { + throw new Error(`editor english runtime smoke: ${englishResponse?.status()} ${englishResponse?.statusText()}`); + } + await page.getByRole("heading", { name: "BSL Editor" }).waitFor({ state: "visible", timeout: 15000 }); + await page.locator("[data-top-project-bar]").waitFor({ state: "visible", timeout: 15000 }); + for (const selector of ["workspace", "project", "environment", "active-task"]) { + await page.locator(`[data-top-bar-selector="${selector}"]`).waitFor({ state: "visible", timeout: 15000 }); + } + for (const action of ["project-settings", "create-project"]) { + await page.locator(`[data-top-bar-action="${action}"]`).waitFor({ state: "visible", timeout: 15000 }); + } + for (const badge of ["api-status", "agent-status"]) { + await page.locator(`[data-top-bar-badge="${badge}"]`).waitFor({ state: "visible", timeout: 15000 }); + } + await page.locator("[data-top-bar-language]").waitFor({ state: "visible", timeout: 15000 }); + await page.locator('[data-top-bar-button="profile"]').waitFor({ state: "visible", timeout: 15000 }); + await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 }); + for (const tabName of ["Problems", "Semantic diff", "Output", "Change history", "Tests", "AI"]) { + await page.locator("[data-bottom-tool-panel]").getByText(tabName).first().waitFor({ state: "visible", timeout: 15000 }); + } + for (const statusMarker of ["snapshot", "agent", "parser", "diagnostics", "active-task", "privacy", "ai-tokens", "current-user"]) { + await page.locator(`[data-status-item="${statusMarker}"]`).waitFor({ state: "visible", timeout: 15000 }); + } + assertNoFatalRuntimeErrors("editor english runtime smoke"); + + console.log("ok editor runtime"); +} finally { + await browser.close(); +} diff --git a/frontend/sfera-web/scripts/smoke-project-setup.mjs b/frontend/sfera-web/scripts/smoke-project-setup.mjs new file mode 100644 index 0000000..63276a5 --- /dev/null +++ b/frontend/sfera-web/scripts/smoke-project-setup.mjs @@ -0,0 +1,152 @@ +import { chromium } from "playwright-core"; +import { existsSync } from "node:fs"; + +const baseUrl = process.env.SFERA_WEB_URL ?? "http://localhost:3000"; +const projectId = process.env.SFERA_PROJECT_ID ?? "default"; +const browserPath = + process.env.SFERA_BROWSER_PATH ?? + [ + "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", + "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", + "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe" + ].find((path) => existsSync(path)); + +if (!browserPath) { + throw new Error("No installed Chrome or Edge browser found. Set SFERA_BROWSER_PATH."); +} + +await prepareIndexedProject(); + +const runtimeErrors = []; +const browser = await chromium.launch({ + executablePath: browserPath, + headless: true +}); + +try { + const page = await browser.newPage(); + page.on("pageerror", (error) => { + runtimeErrors.push(`pageerror: ${error.message}`); + }); + page.on("console", (message) => { + if (message.type() === "error") { + runtimeErrors.push(`console: ${message.text()}`); + } + }); + + const response = await page.goto(`${baseUrl}/project-settings`, { waitUntil: "load", timeout: 60000 }); + if (!response?.ok()) { + throw new Error(`project setup smoke: ${response?.status()} ${response?.statusText()}`); + } + + await page.locator("[data-project-import-center]").waitFor({ state: "visible", timeout: 15000 }); + await page.getByRole("heading", { name: "Project Settings" }).waitFor({ state: "visible", timeout: 15000 }); + for (const section of ["Пользователи и доступ", "Интеграции задач", "Docker/runtime adapter", "Audit", "Backup/restore"]) { + await page.getByText(section).first().waitFor({ state: "visible", timeout: 15000 }); + } + for (const sectionMarker of ["docker-runtime-adapter", "its-documentation-access"]) { + await page.locator(`[data-settings-section="${sectionMarker}"]`).waitFor({ state: "visible", timeout: 15000 }); + } + await page.getByText("ITS/documentation access").first().waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("SFERA_ITS_URL").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("SFERA_ITS_USERNAME").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("SFERA_ITS_PASSWORD").waitFor({ state: "visible", timeout: 15000 }); + await page.locator("input[value*='its.1c.ru/db/v838doc']").first().waitFor({ state: "visible", timeout: 15000 }); + await page.getByText(".env.local").first().waitFor({ state: "visible", timeout: 15000 }); + await page.locator("input[value='']").first().waitFor({ state: "visible", timeout: 15000 }); + await page.locator("select").filter({ hasText: "REFERENCE_CONFIGURATION" }).first().waitFor({ state: "visible", timeout: 15000 }); + await page.getByRole("button", { name: /Reference config/ }).waitFor({ state: "visible", timeout: 15000 }); + const hasMetadataOnlyPrivacy = await page.locator("select").evaluateAll((selects) => { + return selects.some((select) => select.value === "METADATA_ONLY" || [...select.options].some((option) => option.value === "METADATA_ONLY")); + }); + if (!hasMetadataOnlyPrivacy) { + throw new Error("project setup smoke: missing METADATA_ONLY privacy mode"); + } + await page.getByText("Project Setup / Import Center").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("Режим работы с конфигурацией 1С").waitFor({ state: "visible", timeout: 15000 }); + await page.locator('[data-import-mode="FULL_REPLACE"]').waitFor({ state: "visible", timeout: 15000 }); + await page.locator('[data-run-import-mode="SYNC_PREVIEW"]').click(); + const importMode = await page.evaluate(() => window.localStorage.getItem("sfera.import.mode")); + if (importMode !== "SYNC_PREVIEW") { + throw new Error(`project setup smoke: import mode was not persisted, got ${importMode}`); + } + await page.locator('[data-run-import-mode="FULL_REPLACE"]').click(); + await page.locator("[data-import-validation-panel]").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("Не заполнен путь к источнику").waitFor({ state: "visible", timeout: 15000 }); + await page.locator('input[placeholder*="/mnt/share/project"]').fill("/tmp/nonexistent-smoke-import"); + await page.locator('[data-run-import-mode="FULL_REPLACE"]').click(); + await page.getByText("Подтвердите полное обновление").waitFor({ state: "visible", timeout: 15000 }); + await page.getByRole("button", { name: "Отмена" }).click(); + await page.locator('[data-run-import-mode="SYNC_PREVIEW"]').click(); + await page.locator('[data-import-action="XML_DUMP:check"]').click(); + await page.locator("[data-import-check-panel]").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("Source preflight").waitFor({ state: "visible", timeout: 15000 }); + + const englishResponse = await page.goto(`${baseUrl}/project-settings?lang=en`, { waitUntil: "load", timeout: 60000 }); + if (!englishResponse?.ok()) { + throw new Error(`project setup smoke (en): ${englishResponse?.status()} ${englishResponse?.statusText()}`); + } + await page.getByRole("heading", { name: "Project Settings" }).waitFor({ state: "visible", timeout: 15000 }); + for (const section of ["Task/session policy", "Docker/runtime adapter", "ITS/documentation access", "Audit", "Backup/restore"]) { + await page.getByText(section).first().waitFor({ state: "visible", timeout: 15000 }); + } + for (const sectionMarker of ["task-session-policy", "docker-runtime-adapter", "its-documentation-access"]) { + await page.locator(`[data-settings-section="${sectionMarker}"]`).waitFor({ state: "visible", timeout: 15000 }); + } + await page.locator("select").filter({ hasText: "REFERENCE_CONFIGURATION" }).first().waitFor({ state: "visible", timeout: 15000 }); + await page.getByRole("button", { name: /Reference config/ }).waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("SFERA_ITS_URL").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("SFERA_ITS_USERNAME").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("SFERA_ITS_PASSWORD").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText(".env.local").first().waitFor({ state: "visible", timeout: 15000 }); + await page.locator("input[value='']").first().waitFor({ state: "visible", timeout: 15000 }); + await page.locator('[data-import-action="XML_DUMP:check"]').click(); + await page.locator("[data-import-check-panel]").waitFor({ state: "visible", timeout: 15000 }); + await page.getByText("Source preflight").waitFor({ state: "visible", timeout: 15000 }); + + assertNoFatalRuntimeErrors(); + console.log("ok project setup runtime"); +} finally { + await browser.close(); +} + +async function prepareIndexedProject() { + await postJson(`/api/sfera/projects/${encodeURIComponent(projectId)}/settings`, { + name: "SFERA Smoke Project", + structure_source: "XML_DUMP", + platform_version: "8.3.24", + compatibility_mode: "8.3.20" + }); + await postJson(`/api/sfera/projects/${encodeURIComponent(projectId)}/imports/XML_DUMP`, { + source: "XML_DUMP", + metadata: { + platform_version: "8.3.24", + compatibility_mode: "8.3.20" + } + }); +} + +async function postJson(path, body) { + const response = await fetch(`${baseUrl}${path}`, { + method: "POST", + headers: { Accept: "application/json", "Content-Type": "application/json" }, + body: JSON.stringify(body) + }); + if (!response.ok) { + throw new Error(`${path}: ${response.status} ${await response.text()}`); + } + return response.json(); +} + +function assertNoFatalRuntimeErrors() { + const fatalErrors = runtimeErrors.filter((message) => { + return ( + message.includes("Runtime TypeError") || + message.includes("Cannot read properties") || + message.includes("Unhandled Runtime Error") + ); + }); + if (fatalErrors.length > 0) { + throw new Error(`project setup runtime smoke failed:\n${fatalErrors.join("\n")}`); + } +} diff --git a/frontend/sfera-web/src/app/api/sfera/[...path]/route.ts b/frontend/sfera-web/src/app/api/sfera/[...path]/route.ts new file mode 100644 index 0000000..b352e5e --- /dev/null +++ b/frontend/sfera-web/src/app/api/sfera/[...path]/route.ts @@ -0,0 +1,79 @@ +import { resolveApiUrl } from "@/lib/api"; + +type RouteContext = { + params: Promise<{ path: string[] }>; +}; + +export async function GET(request: Request, context: RouteContext) { + return proxy(request, context); +} + +export async function POST(request: Request, context: RouteContext) { + return proxy(request, context); +} + +export async function PUT(request: Request, context: RouteContext) { + return proxy(request, context); +} + +export async function PATCH(request: Request, context: RouteContext) { + return proxy(request, context); +} + +export async function DELETE(request: Request, context: RouteContext) { + return proxy(request, context); +} + +export async function OPTIONS(request: Request, context: RouteContext) { + return proxy(request, context); +} + +export async function HEAD(request: Request, context: RouteContext) { + return proxy(request, context); +} + +async function proxy(request: Request, context: RouteContext) { + const { path } = await context.params; + const apiUrl = resolveApiUrl(request.headers.get("host")); + const sourceUrl = new URL(request.url); + const target = `${apiUrl}/${path.join("/")}${sourceUrl.search}`; + const method = request.method; + const hasBody = method !== "GET" && method !== "HEAD" && request.body !== null; + const body = hasBody ? await request.arrayBuffer() : undefined; + const contentType = request.headers.get("Content-Type"); + const accept = request.headers.get("Accept") ?? "application/json"; + const publicHost = request.headers.get("x-forwarded-host") ?? request.headers.get("host"); + const publicProto = request.headers.get("x-forwarded-proto") ?? "http"; + const publicOrigin = publicHost ? `${publicProto}://${publicHost}` : sourceUrl.origin; + + const headers: Record = { + Accept: accept, + "X-Sfera-Public-Origin": publicOrigin + }; + if (hasBody) { + headers["Content-Type"] = contentType ?? "application/json"; + } + + const response = await fetch(target, { + method, + cache: "no-store", + headers, + body + }); + const responseHeaders: Record = { + "Content-Type": response.headers.get("Content-Type") ?? "application/json" + }; + const contentDisposition = response.headers.get("Content-Disposition"); + if (contentDisposition) { + responseHeaders["Content-Disposition"] = contentDisposition; + } + const cacheControl = response.headers.get("Cache-Control"); + if (cacheControl) { + responseHeaders["Cache-Control"] = cacheControl; + } + + return new Response(response.body, { + status: response.status, + headers: responseHeaders + }); +} diff --git a/frontend/sfera-web/src/app/editor/page.tsx b/frontend/sfera-web/src/app/editor/page.tsx new file mode 100644 index 0000000..980011b --- /dev/null +++ b/frontend/sfera-web/src/app/editor/page.tsx @@ -0,0 +1,113 @@ +import { AlertTriangle } from "lucide-react"; +import { headers } from "next/headers"; + +import { IdeWorkspace } from "@/components/editor/ide-workspace"; +import { AppShell } from "@/components/layout/app-shell"; +import { Card } from "@/components/ui/card"; +import { + getApiHealth, + getProjects, + getProjectWorkspaceData, + resolveApiUrl, + type ProjectSummary +} from "@/lib/api"; +import { messages, normalizeLanguage, type UiLanguage } from "@/lib/i18n"; + +export default async function EditorPage({ + searchParams +}: Readonly<{ + searchParams?: Promise<{ lang?: string; mode?: string; project?: string; routine?: string }>; +}>) { + const params = await searchParams; + const language = normalizeLanguage(params?.lang); + const requestHeaders = await headers(); + const apiUrl = resolveApiUrl(requestHeaders.get("host")); + const bootstrap = await loadEditorBootstrap(apiUrl, language, params?.project); + const projectData = + bootstrap.status === "ok" && bootstrap.projectId ? await getProjectWorkspaceData(bootstrap.projectId, apiUrl, params?.routine, params?.mode) : null; + + return ( + +
+ {bootstrap.status === "error" ? ( + + ) : projectData ? ( + + ) : ( + + )} +
+
+ ); +} + +async function loadEditorBootstrap(apiUrl: string, language: UiLanguage, projectId?: string): Promise< + | { status: "ok"; projectId: string | undefined; projects: ProjectSummary[] } + | { status: "error"; error: string } +> { + try { + const [projectsResponse] = await Promise.all([getProjects(apiUrl), getApiHealth(apiUrl)]); + const projects = uniqueProjects(projectsResponse); + return { status: "ok", projectId: projectId || pickDefaultProject(projectsResponse), projects }; + } catch (error) { + return { + status: "error", + error: error instanceof Error ? error.message : messages[language].unknownApiError + }; + } +} + +function ErrorState({ + message, + language +}: Readonly<{ + message: string; + language: UiLanguage; +}>) { + const t = messages[language]; + + return ( +
+ +
+
+
+
+ ); +} + +function pickDefaultProject(projects: ProjectSummary[]) { + return ( + projects.find((project) => project.project_id === "ifcm-upo")?.project_id ?? + projects.find((project) => project.project_id !== "demo")?.project_id ?? + projects.at(-1)?.project_id ?? + projects.find((project) => project.project_id === "demo")?.project_id + ); +} + +function uniqueProjects(projects: ProjectSummary[]) { + const byId = new Map(); + for (const project of projects) { + const projectId = project.project_id.trim(); + if (projectId) { + byId.set(projectId, { ...project, project_id: projectId, name: project.name || projectId }); + } + } + return Array.from(byId.values()).sort((left, right) => (left.name || left.project_id).localeCompare(right.name || right.project_id, "ru")); +} diff --git a/frontend/sfera-web/src/app/globals.css b/frontend/sfera-web/src/app/globals.css new file mode 100644 index 0000000..fb966c4 --- /dev/null +++ b/frontend/sfera-web/src/app/globals.css @@ -0,0 +1,70 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --background: 210 20% 98%; + --foreground: 222 47% 11%; + --card: 0 0% 100%; + --card-foreground: 222 47% 11%; + --muted: 210 17% 94%; + --muted-foreground: 215 16% 47%; + --border: 214 20% 88%; + --input: 214 20% 88%; + --primary: 198 93% 32%; + --primary-foreground: 0 0% 100%; + --secondary: 168 42% 39%; + --secondary-foreground: 0 0% 100%; + --destructive: 0 72% 45%; + --warning: 38 92% 48%; + --success: 142 54% 36%; + --info: 214 84% 56%; +} + +.dark { + --background: 220 24% 10%; + --foreground: 210 20% 96%; + --card: 220 20% 14%; + --card-foreground: 210 20% 96%; + --muted: 220 16% 20%; + --muted-foreground: 215 15% 66%; + --border: 220 16% 24%; + --input: 220 16% 24%; + --primary: 194 80% 46%; + --primary-foreground: 0 0% 100%; + --secondary: 164 52% 43%; + --secondary-foreground: 0 0% 100%; + --destructive: 0 72% 51%; + --warning: 38 92% 52%; + --success: 142 54% 42%; + --info: 214 84% 62%; +} + +* { + box-sizing: border-box; +} + +html { + background: hsl(var(--background)); +} + +body { + min-height: 100vh; + margin: 0; + background: hsl(var(--background)); + color: hsl(var(--foreground)); + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + letter-spacing: 0; +} + +button, +input, +select, +textarea { + font: inherit; +} + +::selection { + background: hsl(var(--primary) / 0.18); +} diff --git a/frontend/sfera-web/src/app/health/route.ts b/frontend/sfera-web/src/app/health/route.ts new file mode 100644 index 0000000..d5fde18 --- /dev/null +++ b/frontend/sfera-web/src/app/health/route.ts @@ -0,0 +1,3 @@ +export async function GET() { + return Response.json({ status: "ok", service: "sfera-web" }); +} diff --git a/frontend/sfera-web/src/app/layout.tsx b/frontend/sfera-web/src/app/layout.tsx new file mode 100644 index 0000000..00b1040 --- /dev/null +++ b/frontend/sfera-web/src/app/layout.tsx @@ -0,0 +1,16 @@ +import type { Metadata } from "next"; +import type React from "react"; +import "./globals.css"; + +export const metadata: Metadata = { + title: "SFERA", + description: "Semantic 1C operating workspace" +}; + +export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { + return ( + + {children} + + ); +} diff --git a/frontend/sfera-web/src/app/page.tsx b/frontend/sfera-web/src/app/page.tsx new file mode 100644 index 0000000..3dd0fd8 --- /dev/null +++ b/frontend/sfera-web/src/app/page.tsx @@ -0,0 +1,22 @@ +import { redirect } from "next/navigation"; + +export default async function HomePage({ + searchParams +}: Readonly<{ + searchParams?: Promise<{ lang?: string; mode?: string; project?: string; routine?: string }>; +}>) { + const params = await searchParams; + const nextParams = new URLSearchParams(); + if (params?.lang === "en") { + nextParams.set("lang", "en"); + } + for (const key of ["project", "mode", "routine"] as const) { + const value = params?.[key]; + if (value) { + nextParams.set(key, value); + } + } + const suffix = nextParams.size > 0 ? `?${nextParams.toString()}` : ""; + + redirect(`/editor${suffix}`); +} diff --git a/frontend/sfera-web/src/app/project-settings/page.tsx b/frontend/sfera-web/src/app/project-settings/page.tsx new file mode 100644 index 0000000..0744236 --- /dev/null +++ b/frontend/sfera-web/src/app/project-settings/page.tsx @@ -0,0 +1,80 @@ +import { headers } from "next/headers"; + +import { ProjectSetupClient, type ProjectSetup } from "@/components/project-setup/project-setup-client"; +import { getProjects, resolveApiUrl } from "@/lib/api"; + +export default async function ProjectSettingsPage({ + searchParams +}: Readonly<{ searchParams?: Promise<{ project?: string; new?: string }> }>) { + const requestHeaders = await headers(); + const params = searchParams ? await searchParams : {}; + if (params.new === "1") { + return ; + } + const apiUrl = resolveApiUrl(requestHeaders.get("host")); + const projectId = normalizeProjectId(params.project); + const setup = await loadSetup(apiUrl, projectId); + + return ; +} + +function newProjectSetup(): ProjectSetup { + return { + project_id: "__new__", + status: "NOT_CONFIGURED", + message: "Новый проект. Заполните основные параметры и сохраните.", + settings: defaultProjectSettings(""), + current_source: null, + last_import: null, + import_history: [], + import_sources: [] + }; +} + +async function loadSetup(apiUrl: string, projectId: string): Promise { + try { + const response = await fetch(`${apiUrl}/projects/${encodeURIComponent(projectId)}/setup`, { cache: "no-store" }); + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); + } + return response.json(); + } catch { + const projects = await getProjects(apiUrl).catch(() => []); + const fallbackProjectId = projects.at(0)?.project_id ?? "default"; + if (fallbackProjectId !== projectId) { + return loadSetup(apiUrl, fallbackProjectId); + } + return { + project_id: fallbackProjectId, + status: "NOT_CONFIGURED", + message: "Проект не проиндексирован. Выберите способ получения структуры конфигурации.", + settings: defaultProjectSettings("SFERA Project"), + current_source: null, + last_import: null, + import_history: [], + import_sources: [] + }; + } +} + +function defaultProjectSettings(name = "SFERA Project") { + return { + name, + configuration_source: null, + structure_source: null, + platform_version: null, + compatibility_mode: null, + extensions: [], + environments: {}, + agent: {}, + server_import: {}, + privacy_mode: "METADATA_ONLY", + knowledge_sources: [], + task_session_policy: {} + }; +} + +function normalizeProjectId(projectId?: string) { + const trimmed = projectId?.trim(); + return trimmed || "default"; +} diff --git a/frontend/sfera-web/src/components/editor/ide-workspace.tsx b/frontend/sfera-web/src/components/editor/ide-workspace.tsx new file mode 100644 index 0000000..878c899 --- /dev/null +++ b/frontend/sfera-web/src/components/editor/ide-workspace.tsx @@ -0,0 +1,4559 @@ +"use client"; + +import { + Bot, + Brain as BrainIcon, + Braces, + CheckCircle2, + ChevronDown, + Code2, + Copy, + Database as DatabaseIcon, + Filter, + FlaskConical, + FileText, + FileCode2, + GitCompareArrows, + GraduationCap, + History, + Layers3, + ListTree, + Lock, + Maximize2, + Monitor, + MoreVertical, + PanelBottom, + PanelRight, + Pin, + Plus, + Search, + Sparkles, + TriangleAlert, + X +} from "lucide-react"; +import { useEffect, useMemo, useRef, useState } from "react"; +import type React from "react"; + +import { LazyMetadataTree } from "@/components/editor/lazy-metadata-tree"; +import { Badge } from "@/components/ui/badge"; +import { Card } from "@/components/ui/card"; +import { + applyAuthoringChangeSet, + getAuthoringSemanticDiffPreview, + applyAuthoringMetadataObject, + applyAuthoringRollback, + getAuthoringMetadataObjectPreview, + getBslCompletions, + getLineageVersions, + getProjectSymbolDefinition, + getProjectFlowchart, + getProjectSymbolReferences, + getVersionDiff, + getAuthoringRollbackPreview, + searchProjectSymbols, + type AuthoringMetadataObjectDraft, + type BslCompletionItem, + type MetadataTreeNode, + type MetadataTypeSpec, + type FlowchartNode, + type ProjectFlowchart, + type SymbolReferences, + type SymbolResult, + type getProjectWorkspaceData, + resolveApiUrl, + type SirNode +} from "@/lib/api"; +import { messages, type UiLanguage } from "@/lib/i18n"; + +type ProjectWorkspaceData = Awaited>; +type AuthoringChange = ProjectWorkspaceData["authoringChanges"][number]; +type ProjectVersion = ProjectWorkspaceData["projectVersions"][number]; +type VersionDetail = Awaited>[number]; +type VersionDiff = Awaited>; +type WorkspaceMode = "overview" | "module" | "form" | "properties" | "events" | "versions" | "documentation" | "knowledge" | "learning" | "flowchart"; +type OpenDocument = { + id: string; + mode: WorkspaceMode; + label: string; + meta: string; + icon: React.ComponentType<{ className?: string }>; +}; +type OneCIconKind = + | "attribute" + | "business-process" + | "catalog" + | "command" + | "common" + | "constant" + | "document" + | "exchange-plan" + | "event" + | "enum" + | "external-source" + | "extension" + | "form" + | "integration" + | "journal" + | "language" + | "layout" + | "module" + | "palette" + | "plan" + | "processing" + | "register" + | "report" + | "role" + | "scheduled-job" + | "service" + | "settings" + | "subsystem" + | "tabular" + | "task" + | "tree" + | "web"; + +const oneCIconFiles: Record = { + attribute: "attribute.svg", + "business-process": "businessProcess.svg", + catalog: "catalog.svg", + command: "command.svg", + common: "common.svg", + constant: "constant.svg", + document: "document.svg", + event: "eventSubscription.svg", + "exchange-plan": "exchangePlan.svg", + enum: "enum.svg", + "external-source": "externalDataSource.svg", + extension: "folder.svg", + form: "form.svg", + integration: "ws.svg", + journal: "documentJournal.svg", + language: "style.svg", + layout: "template.svg", + module: "commonModule.svg", + palette: "picture.svg", + plan: "chartsOfAccount.svg", + processing: "dataProcessor.svg", + register: "accumulationRegister.svg", + report: "report.svg", + role: "role.svg", + "scheduled-job": "scheduledJob.svg", + service: "http.svg", + settings: "parameter.svg", + subsystem: "subsystem.svg", + tabular: "tabularSection.svg", + task: "task.svg", + tree: "folder.svg", + web: "http.svg" +}; + +const sampleCode = [ + "// Код модуля не загружен.", + "// Выберите реальный модуль в дереве проекта или выполните индексирование с исходниками BSL." +]; + +const suggestedCode = [ + "// AI-подсказка появится после выбора реального контекста." +]; + +const outlineItems = [ + "Выберите модуль в дереве" +]; + +const knownObjectKinds = new Set([ + "CATALOG", + "DOCUMENT", + "REGISTER", + "COMMON_MODULE", + "EXCHANGE_PLAN", + "EVENT_SUBSCRIPTION", + "SCHEDULED_JOB", + "BUSINESS_PROCESS", + "TASK", + "FORM", + "COMMAND", + "ATTRIBUTE", + "TABULAR_SECTION", + "PROCEDURE", + "FUNCTION" +]); + +function versionToSummary(version: { + version_id: string; + lineage_id: string; + semantic_id: string; + object_hash: string; + parent_version_id?: string | null; + task_id?: string | null; + session_id?: string | null; +}): ProjectVersion { + return { + version_id: version.version_id, + lineage_id: version.lineage_id, + semantic_id: version.semantic_id, + object_hash: version.object_hash, + parent_version_id: version.parent_version_id ?? null, + task_id: version.task_id ?? null, + session_id: version.session_id ?? null + }; +} + +export function IdeWorkspace({ + data, + initialMode, + language, + routineName +}: Readonly<{ + data: ProjectWorkspaceData; + initialMode?: string; + language: UiLanguage; + routineName?: string; +}>) { + const t = messages[language]; + const treeNodes = data.exportSnapshot?.nodes ?? []; + const objectNodes = treeNodes.filter((node) => knownObjectKinds.has(node.kind)).slice(0, 14); + const selectedObject = + objectNodes.find((node) => node.lineage_id === data.authoringPreview?.context.object?.lineage_id) ?? + objectNodes[0]; + const selectedMetadataNode = + data.selectedMetadataNode ?? + findMetadataTreeNode(data.metadataTree?.root, routineName) ?? + flattenMetadataTree(data.metadataTree?.root, 1)[0]; + const problems = data.review.slice(0, 3); + const [activeMode, setActiveMode] = useState(() => normalizeWorkspaceMode(initialMode)); + const [authoringChanges, setAuthoringChanges] = useState(data.authoringChanges); + const [projectVersions, setProjectVersions] = useState(data.projectVersions); + const [isLeftPanelOpen, setIsLeftPanelOpen] = useState(true); + const [isRightPanelOpen, setIsRightPanelOpen] = useState(true); + const [isBottomPanelOpen, setIsBottomPanelOpen] = useState(true); + const [leftPanelWidth, setLeftPanelWidth] = useState(null); + const [checkStatus, setCheckStatus] = useState(null); + const [closedOpenDocumentIds, setClosedOpenDocumentIds] = useState>(() => new Set()); + const [pinnedOpenDocumentIds, setPinnedOpenDocumentIds] = useState>(() => new Set()); + const leftPanelRef = useRef(null); + const workspaceData = { ...data, authoringChanges, projectVersions }; + const registerAuthoringChange = (change: AuthoringChange, version?: ProjectVersion) => { + setAuthoringChanges((current) => [change, ...current.filter((item) => item.change_id !== change.change_id)]); + if (version) { + setProjectVersions((current) => [version, ...current.filter((item) => item.version_id !== version.version_id)]); + } + }; + const workspaceModes: Array<{ id: WorkspaceMode; label: string; icon: React.ComponentType<{ className?: string }> }> = [ + { id: "module", label: t.moduleMode, icon: Code2 }, + { id: "form", label: t.formMode, icon: Layers3 }, + { id: "properties", label: t.propertiesMode, icon: PanelRight }, + { id: "events", label: t.eventsMode, icon: Braces }, + { id: "flowchart", label: language === "ru" ? "Блок-схема" : "Flowchart", icon: GitCompareArrows }, + { id: "versions", label: t.versionsMode, icon: History }, + { id: "documentation", label: t.documentationMode, icon: FileText }, + { id: "knowledge", label: t.knowledgeMode, icon: Sparkles }, + { id: "learning", label: t.learningMode, icon: GraduationCap } + ]; + const allOpenDocuments = useMemo(() => buildOpenDocuments(data.metadataTree?.root, language), [data.metadataTree?.root, language]); + const openDocuments = useMemo(() => { + const visible = allOpenDocuments.filter((document) => pinnedOpenDocumentIds.has(document.id) || !closedOpenDocumentIds.has(document.id)); + return visible.length > 0 ? visible : allOpenDocuments.slice(0, 1); + }, [allOpenDocuments, closedOpenDocumentIds, pinnedOpenDocumentIds]); + + useEffect(() => { + setAuthoringChanges(data.authoringChanges); + setProjectVersions(data.projectVersions); + setClosedOpenDocumentIds(new Set()); + setPinnedOpenDocumentIds(new Set()); + setCheckStatus(null); + setActiveMode(normalizeWorkspaceMode(initialMode)); + }, [data.projectId, data.authoringChanges, data.projectVersions, initialMode]); + + useEffect(() => { + try { + const saved = JSON.parse(window.localStorage.getItem(workspacePanelStorageKey(data.projectId)) ?? "{}") as { + leftOpen?: boolean; + rightOpen?: boolean; + bottomOpen?: boolean; + leftWidth?: number; + }; + setIsLeftPanelOpen(saved.leftOpen ?? true); + setIsRightPanelOpen(saved.rightOpen ?? true); + setIsBottomPanelOpen(saved.bottomOpen ?? true); + setLeftPanelWidth(saved.leftWidth && saved.leftWidth >= 240 ? Math.min(saved.leftWidth, 520) : null); + } catch { + setIsLeftPanelOpen(true); + setIsRightPanelOpen(true); + setIsBottomPanelOpen(true); + setLeftPanelWidth(null); + } + }, [data.projectId]); + + useEffect(() => { + const payload = { + leftOpen: isLeftPanelOpen, + rightOpen: isRightPanelOpen, + bottomOpen: isBottomPanelOpen, + leftWidth: leftPanelWidth + }; + window.localStorage.setItem(workspacePanelStorageKey(data.projectId), JSON.stringify(payload)); + }, [data.projectId, isBottomPanelOpen, isLeftPanelOpen, isRightPanelOpen, leftPanelWidth]); + + useEffect(() => { + const panel = leftPanelRef.current; + if (!panel || !isLeftPanelOpen) { + return; + } + const observer = new ResizeObserver(([entry]) => { + const width = Math.round(entry.contentRect.width); + if (width >= 240 && width <= 520) { + setLeftPanelWidth(width); + } + }); + observer.observe(panel); + return () => observer.disconnect(); + }, [isLeftPanelOpen]); + + useEffect(() => { + try { + const saved = window.localStorage.getItem(openObjectsStorageKey(data.projectId)); + if (!saved) { + return; + } + const parsed = JSON.parse(saved) as { closed?: string[]; pinned?: string[] }; + setClosedOpenDocumentIds(new Set(parsed.closed ?? [])); + setPinnedOpenDocumentIds(new Set(parsed.pinned ?? [])); + } catch { + setClosedOpenDocumentIds(new Set()); + setPinnedOpenDocumentIds(new Set()); + } + }, [data.projectId]); + + useEffect(() => { + window.localStorage.setItem( + openObjectsStorageKey(data.projectId), + JSON.stringify({ closed: [...closedOpenDocumentIds], pinned: [...pinnedOpenDocumentIds] }) + ); + }, [closedOpenDocumentIds, data.projectId, pinnedOpenDocumentIds]); + + function closeOpenDocument(documentId: string) { + const target = openDocuments.find((document) => document.id === documentId); + if (!target || pinnedOpenDocumentIds.has(documentId) || openDocuments.length <= 1) { + return; + } + const currentIndex = Math.max(0, openDocuments.findIndex((document) => document.id === documentId)); + const nextDocument = openDocuments[currentIndex + 1] ?? openDocuments[currentIndex - 1] ?? openDocuments[0]; + setClosedOpenDocumentIds((current) => new Set([...current, documentId])); + if (target.mode === activeMode && nextDocument?.id !== target.id) { + switchMode(nextDocument.mode, setActiveMode); + } + } + + function togglePinnedOpenDocument(documentId: string) { + setPinnedOpenDocumentIds((current) => { + const next = new Set(current); + if (next.has(documentId)) { + next.delete(documentId); + } else { + next.add(documentId); + } + return next; + }); + setClosedOpenDocumentIds((current) => { + const next = new Set(current); + next.delete(documentId); + return next; + }); + } + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + const target = event.target as HTMLElement | null; + const isEditableTarget = + target?.tagName === "INPUT" || + target?.tagName === "TEXTAREA" || + target?.tagName === "SELECT" || + target?.isContentEditable; + + if (event.altKey && !event.ctrlKey && !event.metaKey) { + if (event.key === "1") { + event.preventDefault(); + setIsLeftPanelOpen((current) => !current); + } else if (event.key === "2") { + event.preventDefault(); + setIsRightPanelOpen((current) => !current); + } else if (event.key === "3") { + event.preventDefault(); + setIsBottomPanelOpen((current) => !current); + } + } + + if (!event.ctrlKey && !event.altKey && !event.metaKey && event.key === "F5") { + event.preventDefault(); + setIsBottomPanelOpen(true); + setCheckStatus(language === "ru" ? "Проверка запущена" : "Check started"); + return; + } + + if (isEditableTarget || event.altKey || event.metaKey || !event.ctrlKey) { + if (event.ctrlKey && !event.altKey && !event.metaKey && event.key.toLowerCase() === "k") { + event.preventDefault(); + document.querySelector("[data-global-search-input]")?.focus(); + } + return; + } + + if (event.key.toLowerCase() === "k") { + event.preventDefault(); + document.querySelector("[data-global-search-input]")?.focus(); + } else if (event.key === "Tab") { + event.preventDefault(); + switchOpenDocument(event.shiftKey ? -1 : 1, activeMode, openDocuments, setActiveMode); + } else if (event.key.toLowerCase() === "w") { + event.preventDefault(); + const activeDocument = openDocuments.find((document) => document.mode === activeMode); + if (activeDocument) { + closeOpenDocument(activeDocument.id); + } + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [activeMode, language, openDocuments, pinnedOpenDocumentIds]); + + return ( +
+
+ {isLeftPanelOpen ? ( +
+ +
+ ) : ( + setIsLeftPanelOpen(true)} + /> + )} +
+
+ setIsBottomPanelOpen((current) => !current)} + onToggleLeft={() => setIsLeftPanelOpen((current) => !current)} + onToggleRight={() => setIsRightPanelOpen((current) => !current)} + /> +
+ +
+
+ {isBottomPanelOpen ? : null} +
+ {isRightPanelOpen ? ( +
+ + + + +
+ ) : ( + setIsRightPanelOpen(true)} + /> + )} +
+
+
+
+ {openDocuments.map((document) => { + const isPinned = pinnedOpenDocumentIds.has(document.id); + const isActive = activeMode === document.mode; + return ( +
+ + + +
+ ); + })} + + {routineName ?? t.bslEditor} + +
+
+ ); +} + +function WorkspaceChrome({ + checkStatus, + isBottomPanelOpen, + isLeftPanelOpen, + isRightPanelOpen, + language, + onToggleBottom, + onToggleLeft, + onToggleRight +}: Readonly<{ + checkStatus: string | null; + isBottomPanelOpen: boolean; + isLeftPanelOpen: boolean; + isRightPanelOpen: boolean; + language: UiLanguage; + onToggleBottom: () => void; + onToggleLeft: () => void; + onToggleRight: () => void; +}>) { + return ( +
+ + + + {checkStatus ? ( +
{checkStatus}
+ ) : ( +
Alt+1 Alt+2 Alt+3
+ )} +
+ ); +} + +function IconToggle({ + active, + ariaLabel, + icon: Icon, + onClick +}: Readonly<{ active: boolean; ariaLabel: string; icon: React.ComponentType<{ className?: string }>; onClick: () => void }>) { + return ( + + ); +} + +function PanelRail({ + ariaLabel, + icon: Icon, + onClick +}: Readonly<{ ariaLabel: string; icon: React.ComponentType<{ className?: string }>; onClick: () => void }>) { + return ( + + ); +} + +function switchOpenDocument( + direction: -1 | 1, + activeMode: WorkspaceMode, + openDocuments: Array<{ mode: WorkspaceMode }>, + setActiveMode: (mode: WorkspaceMode) => void +) { + if (openDocuments.length === 0) { + return; + } + const currentIndex = Math.max(0, openDocuments.findIndex((document) => document.mode === activeMode)); + const nextIndex = (currentIndex + direction + openDocuments.length) % openDocuments.length; + switchMode(openDocuments[nextIndex].mode, setActiveMode); +} + +function openObjectsStorageKey(projectId: string) { + return `sfera.open-objects.${projectId}`; +} + +function workspacePanelStorageKey(projectId: string) { + return `sfera.workspace-panels.${projectId}`; +} + +function normalizeWorkspaceMode(value: string | undefined): WorkspaceMode { + const allowedModes = new Set([ + "overview", + "module", + "form", + "properties", + "events", + "flowchart", + "versions", + "documentation", + "knowledge", + "learning" + ]); + + return allowedModes.has(value as WorkspaceMode) ? (value as WorkspaceMode) : "module"; +} + +function switchMode(nextMode: WorkspaceMode, setActiveMode: (mode: WorkspaceMode) => void) { + setActiveMode(nextMode); + + const url = new URL(window.location.href); + url.searchParams.set("mode", nextMode); + window.history.replaceState(null, "", url); +} + +function buildOpenDocuments(root: MetadataTreeNode | undefined, language: UiLanguage) { + const t = messages[language]; + const nodes = flattenMetadataTree(root, 6); + const fallbackDocuments = [ + { id: "overview", mode: "overview" as WorkspaceMode, label: t.overview, meta: t.projectWorkspace, icon: FileText }, + { id: "flowchart", mode: "flowchart" as WorkspaceMode, label: language === "ru" ? "Блок-схема" : "Flowchart", meta: language === "ru" ? "Связи конфигурации" : "Configuration links", icon: GitCompareArrows }, + { id: "module", mode: "module" as WorkspaceMode, label: t.moduleMode, meta: t.bslEditor, icon: Code2 }, + { id: "form", mode: "form" as WorkspaceMode, label: t.formMode, meta: t.formDesigner, icon: Layers3 }, + { id: "task", mode: "knowledge" as WorkspaceMode, label: "TASK-123", meta: t.activeTask, icon: Bot } + ]; + if (nodes.length === 0) { + return fallbackDocuments; + } + + const documents = nodes.map((node) => ({ + id: node.id, + mode: modeForMetadataNode(node), + label: node.label, + meta: node.kind, + icon: iconForMetadataNode(node) + })); + const existingModes = new Set(documents.map((document) => document.mode)); + return [ + ...documents, + ...fallbackDocuments.filter((document) => !existingModes.has(document.mode)) + ].slice(0, 6); +} + +function flattenMetadataTree(root: MetadataTreeNode | undefined, limit: number) { + const result: MetadataTreeNode[] = []; + const visit = (node: MetadataTreeNode) => { + if (result.length >= limit) { + return; + } + if (node.qualified_name && node.kind !== "CONFIGURATOR" && node.kind !== "COMMON") { + result.push(node); + } + for (const child of node.children) { + visit(child); + if (result.length >= limit) { + return; + } + } + }; + if (root) { + visit(root); + } + return result; +} + +function findMetadataTreeNode(root: MetadataTreeNode | undefined, routineName?: string) { + if (!root || !routineName) { + return undefined; + } + const normalizedRoutine = routineName.toLocaleLowerCase("ru-RU"); + const stack = [root]; + while (stack.length > 0) { + const node = stack.pop()!; + const qualifiedName = node.qualified_name?.toLocaleLowerCase("ru-RU"); + if (node.label.toLocaleLowerCase("ru-RU") === normalizedRoutine || qualifiedName === normalizedRoutine) { + return node; + } + stack.push(...node.children); + } + return undefined; +} + +function childLabelsByName(node: MetadataTreeNode | undefined, groupName: string) { + const group = node?.children.find((child) => child.label === groupName); + return group?.children.map((child) => child.label) ?? []; +} + +function childGroupCountByName(node: MetadataTreeNode | undefined, groupName: string) { + return node?.children.find((child) => child.label === groupName)?.count ?? 0; +} + +function modeForMetadataNode(node: MetadataTreeNode): WorkspaceMode { + const value = `${node.kind} ${node.label} ${node.icon}`.toLocaleLowerCase("ru-RU"); + if (value.includes("form") || value.includes("форма")) { + return "form"; + } + if (value.includes("event") || value.includes("событ")) { + return "events"; + } + if (value.includes("flowchart") || value.includes("блок-схем")) { + return "flowchart"; + } + return "module"; +} + +function iconForMetadataNode(node: MetadataTreeNode): React.ComponentType<{ className?: string }> { + const value = `${node.kind} ${node.label} ${node.icon}`.toLocaleLowerCase("ru-RU"); + if (value.includes("form") || value.includes("форма")) { + return Layers3; + } + if (value.includes("register") || value.includes("регистр")) { + return DatabaseIcon; + } + if (value.includes("event") || value.includes("событ")) { + return Braces; + } + if (value.includes("flowchart") || value.includes("блок-схем")) { + return GitCompareArrows; + } + if (value.includes("knowledge") || value.includes("знан")) { + return BrainIcon; + } + return FileCode2; +} + +function ObjectTree({ + data, + language, + title, + nodes, + selectedObject +}: Readonly<{ + data: ProjectWorkspaceData; + language: UiLanguage; + title: string; + nodes: SirNode[]; + selectedObject?: SirNode; +}>) { + const t = messages[language]; + const projectId = data.projectId; + const [query, setQuery] = useState(""); + const [treeFilter, setTreeFilter] = useState<"all" | "metadata" | "sfera" | "environments">("all"); + const normalizedQuery = normalizeTreeSearch(query); + const commonSectionIcons = Object.fromEntries(commonMetadataSections.map((item) => [item.label, item.iconKind])); + const commonSections = (data.metadataCatalog?.common_branch_children ?? commonMetadataSections.map((item) => item.label)).map((label) => ({ + label, + iconKind: commonSectionIcons[label] ?? kindForTreeLabel(label) + })); + const metadataTypes = data.metadataCatalog?.types.filter((spec) => !["COMMON", "COMMON_MODULE", "EXTENSION"].includes(spec.code)) ?? fallbackMetadataTypeSpecs; + const filteredNodes = filterSirNodesForTree(nodes, normalizedQuery); + const filteredCommonSections = commonSections.filter((item) => matchesTreeSearch(item.label, normalizedQuery)); + const filteredMetadataTypes = metadataTypes.filter((spec) => { + const specNodes = filteredNodes.filter((node) => nodeMatchesMetadataSpec(node, spec)); + return matchesTreeSearch(`${spec.tree_branch} ${spec.russian_name} ${spec.code}`, normalizedQuery) || specNodes.length > 0; + }); + const showMetadataTree = treeFilter === "all" || treeFilter === "metadata"; + const showSferaTree = treeFilter === "all" || treeFilter === "sfera"; + const showEnvironmentTree = treeFilter === "all" || treeFilter === "environments"; + const sferaSections = [t.aiHandlers, t.semanticRules, t.reviewPolicies, t.knowledgeBindings, t.agentCommands, t.rollbackTemplates].filter((item) => matchesTreeSearch(item, normalizedQuery)); + const sferaWorkspaces = ["Задачи", "Проверки", "Версии и изменения", "Инциденты", "Runtime", "Знания", "Документация", "Паттерны", "Релизы", "Агенты"].filter((item) => matchesTreeSearch(item, normalizedQuery)); + const environments = ["Dev", "Test", "Stage", "Prod"].filter((item) => matchesTreeSearch(item, normalizedQuery)); + const useServerTree = Boolean(data.metadataTree && (nodes.length === 0 || (data.snapshot?.node_count ?? 0) > 20000)); + + if (useServerTree && data.metadataTree) { + return ( + + ); + } + + return ( + + ); +} + +function normalizeTreeSearch(value: string) { + return value.trim().toLocaleLowerCase("ru-RU"); +} + +function matchesTreeSearch(value: string, query: string) { + return query.length === 0 || value.toLocaleLowerCase("ru-RU").includes(query); +} + +function filterSirNodesForTree(nodes: SirNode[], query: string) { + if (!query) { + return nodes; + } + return nodes.filter((node) => matchesTreeSearch(`${node.name} ${node.kind} ${node.qualified_name}`, query)); +} + +function ConfigurationLikeRoot({ + commonSections, + language, + metadataTypes, + nodes, + projectId, + selectedObject, + title +}: Readonly<{ + commonSections: Array<{ label: string; iconKind: OneCIconKind }>; + language: UiLanguage; + metadataTypes: MetadataTypeSpec[]; + nodes: SirNode[]; + projectId: string; + selectedObject?: SirNode; + title: string; +}>) { + return ( + + + + {commonSections.map((item) => ( + + ))} + + {metadataTypes.map((spec) => ( + + ))} + + ); +} + +function ServerMetadataTreeNode({ + language, + node, + projectId +}: Readonly<{ + language: UiLanguage; + node: MetadataTreeNode; + projectId: string; +}>) { + const iconKind = isOneCIconKind(node.icon) ? node.icon : kindForTreeLabel(node.label); + const title = node.count > 0 ? `${node.label} (${node.count})` : node.label; + if (node.children.length === 0) { + return ( + + ); + } + + return ( + + {node.children.map((child) => ( + + ))} + + ); +} + +function CommonMetadataSection({ + iconKind, + language, + nodes, + projectId, + title +}: Readonly<{ + iconKind: OneCIconKind; + language: UiLanguage; + nodes: SirNode[]; + projectId: string; + title: string; +}>) { + const sectionNodes = nodes.filter((node) => nodeMatchesCommonSection(node, title)); + if (sectionNodes.length === 0) { + return ; + } + + return ( + + {sectionNodes.map((node) => ( + + ))} + + ); +} + +function MetadataTypeBranch({ + language, + nodes, + projectId, + selectedObject, + spec +}: Readonly<{ + language: UiLanguage; + nodes: SirNode[]; + projectId: string; + selectedObject?: SirNode; + spec: MetadataTypeSpec; +}>) { + const objectNodes = nodes.filter((node) => nodeMatchesMetadataSpec(node, spec)); + const iconKind = iconKindForMetadataSpec(spec); + const propertySummary = spec.properties?.slice(0, 5).join(", "); + const actionSummary = spec.context_actions?.slice(0, 4).join(", "); + + return ( + 0} iconKind={iconKind} storageScope={projectId} title={spec.tree_branch}> + {propertySummary ? ( +
+ Свойства: {propertySummary} +
+ ) : null} + {actionSummary ? ( +
+ Действия: {actionSummary} +
+ ) : null} + {objectNodes.map((node) => ( + + {[...spec.child_groups, ...spec.module_kinds, "Версии", "Проверки", "Инциденты", "Знания"].map((group) => ( + + ))} + + ))} +
+ ); +} + +function editorHref(language: UiLanguage, projectId: string, mode: WorkspaceMode, routine: string) { + return `/editor?lang=${language}&project=${encodeURIComponent(projectId)}&mode=${mode}&routine=${encodeURIComponent(routine)}`; +} + +const fallbackMetadataTypeSpecs: MetadataTypeSpec[] = [ + { code: "CONSTANT", russian_name: "Константа", tree_branch: "Константы", icon: "constant", child_groups: ["Формы", "Команды", "Права"], module_kinds: [] }, + { code: "CATALOG", russian_name: "Справочник", tree_branch: "Справочники", icon: "catalog", child_groups: ["Реквизиты", "Табличные части", "Формы", "Команды", "Макеты", "Права", "Предопределенные данные"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "DOCUMENT", russian_name: "Документ", tree_branch: "Документы", icon: "document", child_groups: ["Реквизиты", "Табличные части", "Формы", "Команды", "Макеты", "Права", "Движения", "Последовательности", "Нумераторы"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "DOCUMENT_JOURNAL", russian_name: "Журнал документов", tree_branch: "Журналы документов", icon: "journal", child_groups: ["Графы", "Формы", "Команды", "Макеты", "Права"], module_kinds: ["Модуль менеджера"] }, + { code: "ENUM", russian_name: "Перечисление", tree_branch: "Перечисления", icon: "enum", child_groups: ["Значения", "Формы", "Команды", "Макеты", "Права"], module_kinds: ["Модуль менеджера"] }, + { code: "REPORT", russian_name: "Отчет", tree_branch: "Отчеты", icon: "report", child_groups: ["Реквизиты", "Табличные части", "Формы", "Команды", "Макеты", "Табличные документы", "СКД", "Варианты отчета", "Настройки", "Хранилище вариантов", "Хранилище настроек", "Справка", "Права"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "DATA_PROCESSOR", russian_name: "Обработка", tree_branch: "Обработки", icon: "processing", child_groups: ["Реквизиты", "Табличные части", "Формы", "Команды", "Макеты", "Права"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "CHART_OF_CHARACTERISTIC_TYPES", russian_name: "План видов характеристик", tree_branch: "Планы видов характеристик", icon: "plan", child_groups: ["Реквизиты", "Табличные части", "Формы", "Команды", "Макеты", "Права", "Предопределенные данные"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "CHART_OF_ACCOUNTS", russian_name: "План счетов", tree_branch: "Планы счетов", icon: "plan", child_groups: ["Признаки учета", "Признаки учета субконто", "Табличные части", "Формы", "Команды", "Макеты", "Права", "Предопределенные данные"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "CHART_OF_CALCULATION_TYPES", russian_name: "План видов расчета", tree_branch: "Планы видов расчета", icon: "plan", child_groups: ["Реквизиты", "Табличные части", "Вытесняющие виды расчета", "Ведущие виды расчета", "Базовые виды расчета", "Формы", "Команды", "Макеты", "Права"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "INFORMATION_REGISTER", russian_name: "Регистр сведений", tree_branch: "Регистры сведений", icon: "register", child_groups: ["Измерения", "Ресурсы", "Реквизиты", "Формы", "Команды", "Макеты", "Кто пишет", "Кто читает", "Права"], module_kinds: ["Модуль набора записей", "Модуль менеджера"] }, + { code: "ACCUMULATION_REGISTER", russian_name: "Регистр накопления", tree_branch: "Регистры накопления", icon: "register", child_groups: ["Измерения", "Ресурсы", "Реквизиты", "Формы", "Команды", "Макеты", "Кто пишет", "Кто читает", "Права"], module_kinds: ["Модуль набора записей", "Модуль менеджера"] }, + { code: "ACCOUNTING_REGISTER", russian_name: "Регистр бухгалтерии", tree_branch: "Регистры бухгалтерии", icon: "register", child_groups: ["Измерения", "Ресурсы", "Реквизиты", "Признаки учета", "Признаки учета субконто", "Формы", "Команды", "Макеты", "Права"], module_kinds: ["Модуль набора записей", "Модуль менеджера"] }, + { code: "CALCULATION_REGISTER", russian_name: "Регистр расчета", tree_branch: "Регистры расчета", icon: "register", child_groups: ["Измерения", "Ресурсы", "Реквизиты", "Перерасчеты", "Формы", "Команды", "Макеты", "Права"], module_kinds: ["Модуль набора записей", "Модуль менеджера"] }, + { code: "BUSINESS_PROCESS", russian_name: "Бизнес-процесс", tree_branch: "Бизнес-процессы", icon: "business-process", child_groups: ["Реквизиты", "Табличные части", "Карта маршрута", "Точки маршрута", "Формы", "Команды", "Макеты", "Права"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "TASK", russian_name: "Задача 1С", tree_branch: "Задачи", icon: "task", child_groups: ["Реквизиты", "Табличные части", "Адресация", "Формы", "Команды", "Макеты", "Права"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "EXCHANGE_PLAN", russian_name: "План обмена", tree_branch: "Планы обмена", icon: "exchange-plan", child_groups: ["Реквизиты", "Команды", "Права"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "EVENT_SUBSCRIPTION", russian_name: "Подписка на событие", tree_branch: "Подписки на события", icon: "event", child_groups: ["События"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "SCHEDULED_JOB", russian_name: "Регламентное задание", tree_branch: "Регламентные задания", icon: "scheduled-job", child_groups: ["Команды", "Права"], module_kinds: ["Модуль объекта", "Модуль менеджера"] }, + { code: "EXTERNAL_DATA_SOURCE", russian_name: "Внешний источник данных", tree_branch: "Внешние источники данных", icon: "external-source", child_groups: ["Таблицы", "Кубы", "Функции", "Формы", "Команды", "Макеты"], module_kinds: [] }, + { code: "WEB_SERVICE", russian_name: "Web-сервис", tree_branch: "Web-сервисы", icon: "service", child_groups: ["Операции", "Параметры", "Модуль"], module_kinds: [] }, + { code: "HTTP_SERVICE", russian_name: "HTTP-сервис", tree_branch: "HTTP-сервисы", icon: "service", child_groups: ["Шаблоны URL", "Методы", "Модуль"], module_kinds: [] }, + { code: "WS_REFERENCE", russian_name: "WS-ссылка", tree_branch: "WS-ссылки", icon: "service", child_groups: ["Операции", "Параметры"], module_kinds: [] }, + { code: "WEBSOCKET_CLIENT", russian_name: "WebSocket-клиент", tree_branch: "WebSocket-клиенты", icon: "service", child_groups: ["Модуль"], module_kinds: [] }, + { code: "INTEGRATION_SERVICE", russian_name: "Сервис интеграции", tree_branch: "Сервисы интеграции", icon: "service", child_groups: ["Каналы", "Сообщения", "Модуль"], module_kinds: [] }, + { code: "BOT", russian_name: "Бот", tree_branch: "Боты", icon: "service", child_groups: ["Команды", "Модуль"], module_kinds: [] } + ]; + +const commonMetadataSections: Array<{ label: string; iconKind: OneCIconKind }> = [ + { label: "Подсистемы", iconKind: "subsystem" }, + { label: "Общие модули", iconKind: "module" }, + { label: "Параметры сеанса", iconKind: "settings" }, + { label: "Роли", iconKind: "role" }, + { label: "Общие реквизиты", iconKind: "attribute" }, + { label: "Планы обмена", iconKind: "exchange-plan" }, + { label: "Критерии отбора", iconKind: "settings" }, + { label: "Подписки на события", iconKind: "event" }, + { label: "Регламентные задания", iconKind: "scheduled-job" }, + { label: "Боты", iconKind: "service" }, + { label: "Функциональные опции", iconKind: "settings" }, + { label: "Параметры функциональных опций", iconKind: "settings" }, + { label: "Определяемые типы", iconKind: "plan" }, + { label: "Хранилища настроек", iconKind: "settings" }, + { label: "Общие команды", iconKind: "command" }, + { label: "Группы команд", iconKind: "command" }, + { label: "Общие формы", iconKind: "form" }, + { label: "Общие макеты", iconKind: "layout" }, + { label: "Общие картинки", iconKind: "layout" }, + { label: "XDTO-пакеты", iconKind: "integration" }, + { label: "Web-сервисы", iconKind: "web" }, + { label: "HTTP-сервисы", iconKind: "web" }, + { label: "WS-ссылки", iconKind: "web" }, + { label: "WebSocket-клиенты", iconKind: "web" }, + { label: "Сервисы интеграции", iconKind: "integration" }, + { label: "Цвета палитры", iconKind: "palette" }, + { label: "Элементы стиля", iconKind: "palette" }, + { label: "Стили", iconKind: "palette" }, + { label: "Языки", iconKind: "language" } +]; + +function iconKindForMetadataSpec(spec: MetadataTypeSpec): OneCIconKind { + return isOneCIconKind(spec.icon) ? spec.icon : kindForTreeLabel(spec.tree_branch); +} + +function isOneCIconKind(value: string): value is OneCIconKind { + return value in oneCIconFiles; +} + +function modeForTreeGroup(group: string): WorkspaceMode { + const value = group.toLowerCase(); + if (value.includes("форм")) return "form"; + if (value.includes("событ")) return "events"; + if (value.includes("верс")) return "versions"; + if (value.includes("знан")) return "knowledge"; + return "module"; +} + +function nodeMatchesCommonSection(node: SirNode, sectionTitle: string): boolean { + const kind = node.kind.toUpperCase(); + const qualifiedName = normalizeQualifiedName(node.qualified_name); + if (sectionTitle === "Общие модули") return kind === "COMMON_MODULE" || qualifiedName.startsWith("общиймодуль."); + if (sectionTitle === "Роли") return kind === "ROLE" || qualifiedName.startsWith("роль."); + if (sectionTitle === "Планы обмена") return kind === "EXCHANGE_PLAN" || qualifiedName.startsWith("планобмена."); + if (sectionTitle === "Подписки на события") return kind === "EVENT_SUBSCRIPTION" || qualifiedName.startsWith("подписканасобытие."); + if (sectionTitle === "Регламентные задания") return kind === "SCHEDULED_JOB" || qualifiedName.startsWith("регламентноезадание."); + if (sectionTitle === "Общие формы") return kind === "FORM" && qualifiedName.startsWith("общаяформа."); + if (sectionTitle === "Общие команды") return kind === "COMMAND" && qualifiedName.startsWith("общаякоманда."); + if (sectionTitle === "HTTP-сервисы") return qualifiedName.startsWith("httpсервис.") || qualifiedName.startsWith("http-сервис."); + if (sectionTitle === "Web-сервисы") return qualifiedName.startsWith("webсервис.") || qualifiedName.startsWith("web-сервис."); + if (sectionTitle === "WS-ссылки") return qualifiedName.startsWith("wsссылка.") || qualifiedName.startsWith("ws-ссылка."); + return false; +} + +function nodeMatchesMetadataSpec(node: SirNode, spec: MetadataTypeSpec): boolean { + const kind = node.kind.toUpperCase(); + const qualifiedName = normalizeQualifiedName(node.qualified_name); + const topLevel = isTopLevelMetadataQualifiedName(qualifiedName); + switch (spec.code) { + case "CONSTANT": + return topLevel && qualifiedName.startsWith("константа."); + case "CATALOG": + return kind === "CATALOG" || (topLevel && qualifiedName.startsWith("справочник.")); + case "DOCUMENT": + return kind === "DOCUMENT" || (topLevel && qualifiedName.startsWith("документ.")); + case "DOCUMENT_JOURNAL": + return topLevel && qualifiedName.startsWith("журналдокументов."); + case "ENUM": + return topLevel && qualifiedName.startsWith("перечисление."); + case "REPORT": + return topLevel && (qualifiedName.startsWith("отчет.") || qualifiedName.startsWith("отчёт.")); + case "DATA_PROCESSOR": + return topLevel && qualifiedName.startsWith("обработка."); + case "CHART_OF_CHARACTERISTIC_TYPES": + return topLevel && qualifiedName.startsWith("планвидовхарактеристик."); + case "CHART_OF_ACCOUNTS": + return topLevel && qualifiedName.startsWith("плансчетов."); + case "CHART_OF_CALCULATION_TYPES": + return topLevel && (qualifiedName.startsWith("планвидоврасчета.") || qualifiedName.startsWith("планвидоврасчёта.")); + case "INFORMATION_REGISTER": + return topLevel && qualifiedName.startsWith("регистрсведений."); + case "ACCUMULATION_REGISTER": + return topLevel && qualifiedName.startsWith("регистрнакопления."); + case "ACCOUNTING_REGISTER": + return topLevel && qualifiedName.startsWith("регистрбухгалтерии."); + case "CALCULATION_REGISTER": + return topLevel && (qualifiedName.startsWith("регистррасчета.") || qualifiedName.startsWith("регистррасчёта.")); + case "BUSINESS_PROCESS": + return kind === "BUSINESS_PROCESS" || (topLevel && qualifiedName.startsWith("бизнеспроцесс.")); + case "TASK": + return kind === "TASK" || (topLevel && qualifiedName.startsWith("задача.")); + case "EXTERNAL_DATA_SOURCE": + return topLevel && qualifiedName.startsWith("внешнийисточникданных."); + case "EXCHANGE_PLAN": + return kind === "EXCHANGE_PLAN" || topLevel && qualifiedName.startsWith("планобмена."); + case "EVENT_SUBSCRIPTION": + return kind === "EVENT_SUBSCRIPTION" || topLevel && qualifiedName.startsWith("подписканасобытие."); + case "SCHEDULED_JOB": + return kind === "SCHEDULED_JOB" || topLevel && qualifiedName.startsWith("регламентноезадание."); + default: + return false; + } +} + +function normalizeQualifiedName(value: string) { + return value.toLowerCase().replace(/\s+/g, ""); +} + +function isTopLevelMetadataQualifiedName(value: string) { + return (value.match(/\./g)?.length ?? 0) === 1; +} + +function kindForTreeLabel(label: string): OneCIconKind { + const value = label.toLowerCase(); + if (value.includes("справочник")) return "catalog"; + if (value.includes("документ") && !value.includes("журнал")) return "document"; + if (value.includes("журнал")) return "journal"; + if (value.includes("перечислен")) return "enum"; + if (value.includes("отчет") || value.includes("отчёт")) return "report"; + if (value.includes("обработ")) return "processing"; + if (value.includes("событ")) return "event"; + if (value.includes("обмен") || value.includes("обмена")) return "exchange-plan"; + if (value.includes("регистр")) return "register"; + if (value.includes("план")) return "plan"; + if (value.includes("бизнес")) return "business-process"; + if (value.includes("задач")) return "task"; + if (value.includes("источник")) return "external-source"; + if (value.includes("реквизит") || value.includes("измерен") || value.includes("ресурс")) return "attribute"; + if (value.includes("таблич")) return "tabular"; + if (value.includes("форм")) return "form"; + if (value.includes("команд")) return "command"; + if (value.includes("макет")) return "layout"; + if (value.includes("модул")) return "module"; + if (value.includes("прав") || value.includes("рол")) return "role"; + if (value.includes("http") || value.includes("web") || value.includes("ws-")) return "web"; + if (value.includes("интеграц")) return "integration"; + if (value.includes("регламент")) return "scheduled-job"; + if (value.includes("констант")) return "constant"; + if (value.includes("язык")) return "language"; + if (value.includes("стил") || value.includes("палитр")) return "palette"; + if (value.includes("настрой") || value.includes("параметр") || value.includes("индекс")) return "settings"; + return "common"; +} + +function kindForSirNode(kind: string): OneCIconKind { + const value = kind.toUpperCase(); + if (value.includes("EXCHANGE")) return "exchange-plan"; + if (value.includes("DOCUMENT")) return "document"; + if (value.includes("CATALOG")) return "catalog"; + if (value.includes("REGISTER")) return "register"; + if (value.includes("REPORT")) return "report"; + if (value.includes("PROCESSING")) return "processing"; + if (value.includes("FORM")) return "form"; + if (value.includes("COMMAND")) return "command"; + if (value.includes("ATTRIBUTE")) return "attribute"; + if (value.includes("TABULAR")) return "tabular"; + if (value.includes("EVENT")) return "event"; + if (value.includes("SCHEDULED_JOB")) return "scheduled-job"; + if (value.includes("MODULE") || value.includes("PROCEDURE") || value.includes("FUNCTION")) return "module"; + return "common"; +} + +function EditorTreeGroup({ title, children }: Readonly<{ title: string; children: React.ReactNode }>) { + return ( +
+
{title}
+
{children}
+
+ ); +} + +function EditorTreeBranch({ + children, + defaultOpen = false, + icon: Icon = ListTree, + iconKind, + storageScope, + title +}: Readonly<{ + children: React.ReactNode; + defaultOpen?: boolean; + icon?: React.ComponentType<{ className?: string }>; + iconKind?: OneCIconKind; + storageScope?: string; + title: string; +}>) { + const storageKey = `sfera.editor-tree.branch.${storageScope ? `${storageScope}.` : ""}${title}`; + const [open, setOpen] = useState(() => { + if (typeof window === "undefined") { + return defaultOpen; + } + const saved = window.localStorage.getItem(storageKey); + return saved ? saved === "true" : defaultOpen; + }); + + useEffect(() => { + const saved = window.localStorage.getItem(storageKey); + setOpen(saved ? saved === "true" : defaultOpen); + }, [defaultOpen, storageKey]); + + useEffect(() => { + window.localStorage.setItem(storageKey, String(open)); + }, [open, storageKey]); + + return ( +
setOpen(event.currentTarget.open)} open={open}> + + +
{children}
+
+ ); +} + +function OneCTreeIcon({ kind }: Readonly<{ kind: OneCIconKind }>) { + const icon = oneCIconFiles[kind] ?? oneCIconFiles.common; + return ( + + ); +} + +function EditorTreeLeaf({ href = "#", iconKind = "attribute", label }: Readonly<{ href?: string; iconKind?: OneCIconKind; label: string }>) { + return ( + + + {label} + + ); +} + +function EditorTreeLink({ + active, + href, + iconKind, + label, + meta +}: Readonly<{ + active: boolean; + href: string; + iconKind: OneCIconKind; + label: string; + meta: string; +}>) { + return ( + + + + {label} + {meta} + + + ); +} + +function WorkspaceModePanel({ + activeMode, + data, + language, + onAuthoringChangeApplied, + selectedObject, + selectedMetadataNode, + setActiveMode +}: Readonly<{ + activeMode: WorkspaceMode; + data: ProjectWorkspaceData; + language: UiLanguage; + onAuthoringChangeApplied: (change: AuthoringChange, version?: ProjectVersion) => void; + selectedObject?: SirNode; + selectedMetadataNode?: MetadataTreeNode; + setActiveMode: (mode: WorkspaceMode) => void; +}>) { + return ( +
+ + +
+ ); +} + +function WorkspaceModeBody({ + activeMode, + data, + language, + onAuthoringChangeApplied, + selectedObject, + selectedMetadataNode, + setActiveMode +}: Readonly<{ + activeMode: WorkspaceMode; + data: ProjectWorkspaceData; + language: UiLanguage; + onAuthoringChangeApplied: (change: AuthoringChange, version?: ProjectVersion) => void; + selectedObject?: SirNode; + selectedMetadataNode?: MetadataTreeNode; + setActiveMode: (mode: WorkspaceMode) => void; +}>) { + if (activeMode === "overview") { + return ; + } + if (activeMode === "form") { + return ; + } + if (activeMode === "properties" || activeMode === "events") { + return ( + + ); + } + if (activeMode === "versions") { + return ; + } + if (activeMode === "flowchart") { + return ; + } + if (activeMode === "documentation" || activeMode === "knowledge" || activeMode === "learning") { + return ; + } + + return ( + + ); +} + +function ObjectInternalTabs({ + activeMode, + language, + setActiveMode +}: Readonly<{ + activeMode: WorkspaceMode; + language: UiLanguage; + setActiveMode: (mode: WorkspaceMode) => void; +}>) { + const t = messages[language]; + const tabs: Array<{ label: string; mode: WorkspaceMode }> = [ + { label: t.objectOverview, mode: "overview" }, + { label: t.objectAttributes, mode: "properties" }, + { label: t.forms, mode: "form" }, + { label: t.moduleMode, mode: "module" }, + { label: language === "ru" ? "Блок-схема" : "Flowchart", mode: "flowchart" }, + { label: t.permissionState, mode: "properties" }, + { label: t.versionsMode, mode: "versions" }, + { label: t.authoringHistory, mode: "versions" } + ]; + + return ( +
+ {tabs.map((tab) => ( + + ))} +
+ ); +} + +function ObjectOverviewPanel({ + data, + language, + selectedMetadataNode, + selectedObject +}: Readonly<{ + data: ProjectWorkspaceData; + language: UiLanguage; + selectedMetadataNode?: MetadataTreeNode; + selectedObject?: SirNode; +}>) { + const t = messages[language]; + const context = data.authoringPreview?.context; + const selectedName = context?.object?.qualified_name ?? selectedObject?.qualified_name ?? selectedMetadataNode?.qualified_name ?? selectedMetadataNode?.label ?? t.none; + const selectedForms = data.selectedObjectUi?.forms ?? []; + const formRows = selectedForms.length > 0 ? selectedForms.map((item) => item.form.name) : childLabelsByName(selectedMetadataNode, "Формы"); + const formCount = childGroupCountByName(selectedMetadataNode, "Формы"); + const visibleFormRows = formRows.length > 0 ? formRows : formCount > 0 ? [`${formCount} ${language === "ru" ? "форм, загружаются при раскрытии" : "forms, load on expand"}`] : []; + const schema = data.selectedObjectSchema; + const impact = data.selectedObjectImpact; + const commandRows = impact?.commands.map((node) => node.name) ?? context?.commands.map((node) => node.name) ?? childLabelsByName(selectedMetadataNode, "Команды"); + const formElementCount = selectedForms.reduce((total, item) => total + item.elements.length, 0); + + return ( + + +
+
+
+
{t.selectedObject}
+

{selectedName}

+

{t.objectOverviewDescription}

+
+
+ + + +
+
+ node.name)} /> + `${section.tabular_section.name}${section.columns.length ? ` (${section.columns.length})` : ""}`)} /> + + + node.qualified_name) ?? context?.available_methods.slice(0, 5) ?? []} /> + node.qualified_name) ?? context?.writes.map((node) => node.qualified_name) ?? []} /> +
+
+
+ +
+ +
+
+ +
+
+
+
+ ); +} + +function OverviewMetric({ label, value }: Readonly<{ label: string; value: string }>) { + return ( +
+
{label}
+
{value}
+
+ ); +} + +function FlowchartPanel({ + data, + language, + selectedMetadataNode, + selectedObject +}: Readonly<{ + data: ProjectWorkspaceData; + language: UiLanguage; + selectedMetadataNode?: MetadataTreeNode; + selectedObject?: SirNode; +}>) { + const [chart, setChart] = useState(data.flowchart); + const [selectedKind, setSelectedKind] = useState(null); + const [loadingFocus, setLoadingFocus] = useState(null); + const [error, setError] = useState(null); + const selectedQualifiedName = selectedMetadataNode?.qualified_name ?? selectedObject?.qualified_name ?? null; + const nodesById = useMemo(() => new Map((chart?.nodes ?? []).map((node) => [node.id, node])), [chart?.nodes]); + const kindObjects = useMemo(() => { + if (!selectedKind) { + return []; + } + return (data.exportSnapshot?.nodes ?? []) + .filter((node) => node.kind === selectedKind) + .sort((left, right) => left.qualified_name.localeCompare(right.qualified_name, "ru")) + .slice(0, 80); + }, [data.exportSnapshot?.nodes, selectedKind]); + + useEffect(() => { + setChart(data.flowchart); + setSelectedKind(null); + setError(null); + }, [data.flowchart, data.projectId]); + + async function loadFocus(focus: string | null) { + setError(null); + setLoadingFocus(focus ?? "overview"); + try { + const next = await getProjectFlowchart(data.projectId, { + apiUrl: data.apiUrl, + focus, + depth: focus ? 2 : undefined, + limit: focus ? 120 : 80 + }); + setChart(next); + if (!focus) { + setSelectedKind(null); + } + } catch (loadError) { + setError(loadError instanceof Error ? loadError.message : "Не удалось загрузить блок-схему"); + } finally { + setLoadingFocus(null); + } + } + + function handleNodeClick(node: FlowchartNode) { + if (node.id.startsWith("kind:")) { + setSelectedKind(node.kind); + return; + } + void loadFocus(node.id); + } + + const selectedKindLabel = selectedKind ? flowchartKindLabel(selectedKind, language) : null; + const activeNode = chart?.focus ? nodesById.get(chart.focus) : null; + const positions = chart ? flowchartPositions(chart.nodes) : new Map(); + + return ( + + +
+ + +
+ {loadingFocus ? ( +
+ {language === "ru" ? "Загрузка схемы..." : "Loading chart..."} +
+ ) : null} + {error ? ( +
+ {error} +
+ ) : null} +
+ + + + + + + {(chart?.edges ?? []).map((edge) => { + const source = positions.get(edge.source); + const target = positions.get(edge.target); + if (!source || !target) { + return null; + } + const midX = (source.x + target.x) / 2; + const midY = (source.y + target.y) / 2; + return ( + + 1 ? 2 : 1.4} x1={source.x} x2={target.x} y1={source.y} y2={target.y} /> + + {edge.count > 1 ? `${edge.label} ${edge.count}` : edge.label} + + + ); + })} + + {(chart?.nodes ?? []).map((node) => { + const position = positions.get(node.id) ?? { x: 80, y: 80 }; + return ( + + ); + })} +
+
+ + +
+
+ ); +} + +function FlowchartActionButton({ active = false, disabled, label, onClick }: Readonly<{ active?: boolean; disabled?: boolean; label: string; onClick: () => void }>) { + return ( + + ); +} + +function flowchartPositions(nodes: ProjectFlowchart["nodes"]) { + const positions = new Map(); + if (nodes.length === 0) { + return positions; + } + const overview = nodes.some((node) => node.id.startsWith("kind:")); + const levels = new Map(); + nodes.forEach((node, index) => { + const level = overview ? Math.floor(index / 4) : node.level; + const current = levels.get(level) ?? []; + current.push(node); + levels.set(level, current); + }); + const sortedLevels = [...levels.entries()].sort(([left], [right]) => left - right); + sortedLevels.forEach(([level, levelNodes], levelIndex) => { + const columns = overview ? Math.min(4, Math.max(1, levelNodes.length)) : 1; + levelNodes.forEach((node, index) => { + positions.set(node.id, overview ? { + x: 150 + (index % columns) * 230, + y: 90 + level * 150 + } : { + x: 180 + levelIndex * 260, + y: 90 + index * Math.max(84, Math.min(150, 520 / Math.max(1, levelNodes.length - 1 || 1))) + }); + }); + }); + return positions; +} + +function flowchartKindLabel(kind: string, language: UiLanguage) { + const ru: Record = { + CATALOG: "Справочник", + DOCUMENT: "Документ", + COMMON_MODULE: "Общий модуль", + MODULE: "Модуль", + PROCEDURE: "Процедура", + FUNCTION: "Функция", + FORM: "Форма", + COMMAND: "Команда", + ROLE: "Роль", + ATTRIBUTE: "Реквизит", + TABULAR_SECTION: "Табличная часть", + QUERY: "Запрос", + TABLE: "Таблица", + REGISTER: "Регистр", + REPORT: "Отчет", + DATA_PROCESSOR: "Обработка", + HTTP_SERVICE: "HTTP-сервис", + INTEGRATION_ENDPOINT: "Интеграция", + SCHEDULED_JOB: "Регламентное задание", + EXTENSION: "Расширение" + }; + return language === "ru" ? ru[kind] ?? kind : kind.replaceAll("_", " ").toLowerCase(); +} + +function iconKindForFlowchart(kind: string): OneCIconKind { + if (kind.includes("DOCUMENT")) return "document"; + if (kind.includes("CATALOG")) return "catalog"; + if (kind.includes("MODULE") || kind === "PROCEDURE" || kind === "FUNCTION" || kind === "QUERY") return "module"; + if (kind.includes("FORM")) return "form"; + if (kind.includes("COMMAND")) return "command"; + if (kind.includes("ROLE")) return "role"; + if (kind.includes("REPORT")) return "report"; + if (kind.includes("REGISTER")) return "register"; + if (kind.includes("HTTP") || kind.includes("INTEGRATION")) return "web"; + if (kind.includes("TABULAR")) return "tabular"; + if (kind.includes("ATTRIBUTE")) return "attribute"; + return "tree"; +} + +function modeForFlowchartNode(node: { kind: string }): WorkspaceMode { + if (node.kind === "FORM") return "form"; + if (node.kind === "ROLE" || node.kind === "ATTRIBUTE" || node.kind === "TABULAR_SECTION") return "properties"; + return "module"; +} + +function OverviewList({ rows, title }: Readonly<{ rows: string[]; title: string }>) { + return ( +
+
{title}
+
+ {rows.length === 0 ? ( +
нет
+ ) : ( + rows.map((row) =>
{row}
) + )} +
+
+ ); +} + +function EditorPanel({ + data, + language, + onAuthoringChangeApplied, + selectedMetadataNode, + selectedObject, + setActiveMode +}: Readonly<{ + data: ProjectWorkspaceData; + language: UiLanguage; + onAuthoringChangeApplied: (change: AuthoringChange, version?: ProjectVersion) => void; + selectedMetadataNode?: MetadataTreeNode; + selectedObject?: SirNode; + setActiveMode: (mode: WorkspaceMode) => void; +}>) { + const t = messages[language]; + const initialProposedText = data.editorSourceText ?? data.editorProposedText ?? sampleCode.join("\n"); + const [proposedText, setProposedText] = useState(initialProposedText); + const [semanticDiffPreview, setSemanticDiffPreview] = useState(data.semanticDiffPreview); + const [isRefreshingPreview, setIsRefreshingPreview] = useState(false); + const sourceText = data.editorSourceText && data.editorSourceText.trim() ? data.editorSourceText : sampleCode.join("\n"); + const monacoValue = proposedText || sourceText; + const isRealSourceLoaded = Boolean(data.editorSourceText && !data.editorSourceText.startsWith("// Код модуля не загружен.")); + const hasEditorChanges = normalizeEditorText(proposedText) !== normalizeEditorText(sourceText); + const applyEnabled = semanticDiffPreview?.version_preview?.apply_available ?? false; + const canApplyPayload = Boolean(data.editorSelectedObject && data.editorSourceText && proposedText && hasEditorChanges); + const navigationTarget = data.authoringPreview?.context.routine ?? data.authoringPreview?.context.object ?? selectedObject ?? null; + const initialSymbolQuery = data.authoringPreview?.context.routine?.name ?? selectedMetadataNode?.label ?? selectedObject?.name ?? "Проведение"; + const [applyState, setApplyState] = useState<"idle" | "pending" | "applied" | "error">("idle"); + const [applyMessage, setApplyMessage] = useState(""); + const [symbolQuery, setSymbolQuery] = useState(initialSymbolQuery); + const [symbolResults, setSymbolResults] = useState([]); + const [symbolReferences, setSymbolReferences] = useState(null); + const [symbolDefinition, setSymbolDefinition] = useState(null); + const [symbolState, setSymbolState] = useState<"idle" | "loading" | "error">("idle"); + const [symbolMessage, setSymbolMessage] = useState(""); + const isApplying = applyState === "pending"; + const applyLabel = + applyState === "pending" + ? t.applying + : applyState === "applied" + ? t.savedToSfera + : t.applyToSfera; + const activeSymbol = symbolResults[0] ?? (navigationTarget ? { node: navigationTarget, source: sourceLocationFromNode(selectedObject) } : null); + const routineName = data.authoringPreview?.context.routine?.name ?? data.editorSelectedRoutine ?? "Procedure"; + const guardClauseSnippet = `Процедура ${routineName}\n Если ЗначениеЗаполнено(${routineName}) Тогда\n Возврат;\n КонецЕсли;\nКонецПроцедуры`; + const extractProcedureSnippet = `&НаКлиенте\nПроцедура ExtractedProcedure()\n // TODO: перенести логику в новую процедуру\nКонецПроцедуры`; + const knowledgeLinkSnippet = `// TODO [Knowledge]: ссылку на профильный шаблон/регламент добавить здесь`; + + useEffect(() => { + setProposedText(data.editorSourceText ?? data.editorProposedText ?? sampleCode.join("\n")); + }, [data.editorProposedText, data.editorSourceText, data.editorSelectedObject, data.editorSelectedRoutine]); + + useEffect(() => { + setSemanticDiffPreview(data.semanticDiffPreview); + }, [data.semanticDiffPreview]); + + useEffect(() => { + if (!hasEditorChanges || !isRealSourceLoaded) { + return; + } + const timeout = window.setTimeout(() => { + void refreshSemanticDiff(proposedText); + }, 700); + return () => window.clearTimeout(timeout); + }, [hasEditorChanges, isRealSourceLoaded, proposedText]); + + async function refreshSemanticDiff(nextProposedText: string) { + const objectName = data.editorSelectedObject ?? data.authoringPreview?.context.object?.name ?? selectedMetadataNode?.label ?? null; + if (!objectName || !data.editorSourceText || !nextProposedText) { + setSemanticDiffPreview(null); + return; + } + + setIsRefreshingPreview(true); + try { + const response = await getAuthoringSemanticDiffPreview( + data.projectId, + { + object_name: objectName, + routine_name: data.editorSelectedRoutine ?? data.authoringPreview?.context.routine?.name ?? null, + original_text: data.editorSourceText, + proposed_text: nextProposedText, + task_id: "task.preview", + session_id: "session.preview" + }, + data.apiUrl + ); + setSemanticDiffPreview(response); + } catch { + setSemanticDiffPreview(null); + } finally { + setIsRefreshingPreview(false); + } + } + + function setSuggestedText(next: string) { + setProposedText((current) => { + const nextProposedText = `${current.trimEnd()}\n\n${next}`; + void refreshSemanticDiff(nextProposedText); + return nextProposedText; + }); + } + + function applyInsertGuardClause() { + setSuggestedText(guardClauseSnippet); + } + + function applyExtractProcedure() { + setSuggestedText(extractProcedureSnippet); + } + + function applyAddKnowledgeLink() { + setSuggestedText(knowledgeLinkSnippet); + } + + function openSemanticDiff() { + setActiveMode("versions"); + } + + function openKnowledgePanel() { + setActiveMode("knowledge"); + } + + function openDocumentationPanel() { + setActiveMode("documentation"); + } + + async function handleSymbolSearch() { + const query = symbolQuery.trim(); + if (!query) { + setSymbolResults([]); + setSymbolReferences(null); + setSymbolDefinition(null); + setSymbolMessage(language === "ru" ? "Введите имя символа." : "Enter a symbol name."); + return; + } + + setSymbolState("loading"); + setSymbolMessage(""); + try { + const results = await searchProjectSymbols(data.projectId, query, { apiUrl: data.apiUrl, limit: 12 }); + setSymbolResults(results); + setSymbolReferences(null); + setSymbolDefinition(null); + setSymbolState("idle"); + setSymbolMessage(results.length === 0 ? t.emptyList : `${t.search}: ${results.length}`); + } catch (error) { + setSymbolState("error"); + setSymbolMessage(error instanceof Error ? error.message : language === "ru" ? "Не удалось выполнить поиск символов." : "Symbol search failed."); + } + } + + async function handleDefinition(lineageId = activeSymbol?.node.lineage_id) { + if (!lineageId) { + setSymbolMessage(language === "ru" ? "Нет выбранного символа." : "No selected symbol."); + return; + } + + setSymbolState("loading"); + setSymbolMessage(""); + try { + const definition = await getProjectSymbolDefinition(data.projectId, lineageId, data.apiUrl); + setSymbolDefinition(definition); + setSymbolState("idle"); + setSymbolMessage(`${language === "ru" ? "Определение" : "Definition"}: ${formatSourceLocation(definition.source, language)}`); + } catch (error) { + setSymbolState("error"); + setSymbolMessage(error instanceof Error ? error.message : language === "ru" ? "Не удалось открыть определение." : "Definition lookup failed."); + } + } + + async function handleReferences(lineageId = activeSymbol?.node.lineage_id) { + if (!lineageId) { + setSymbolMessage(language === "ru" ? "Нет выбранного символа." : "No selected symbol."); + return; + } + + setSymbolState("loading"); + setSymbolMessage(""); + try { + const references = await getProjectSymbolReferences(data.projectId, lineageId, { apiUrl: data.apiUrl, direction: "incoming" }); + setSymbolReferences(references); + setSymbolState("idle"); + setSymbolMessage(`${t.referencesPanel}: ${references.references.length}`); + } catch (error) { + setSymbolState("error"); + setSymbolMessage(error instanceof Error ? error.message : language === "ru" ? "Не удалось найти использования." : "References lookup failed."); + } + } + + async function handleApplyToSfera() { + const versionPreview = semanticDiffPreview?.version_preview; + if (!versionPreview?.apply_available || !canApplyPayload) { + setApplyState("error"); + setApplyMessage(t.previewRequired); + return; + } + + setApplyState("pending"); + setApplyMessage(""); + try { + const apiUrl = + data.apiUrl ?? + (typeof window === "undefined" ? resolveApiUrl() : resolveApiUrl(window.location.host)); + const response = await applyAuthoringChangeSet( + data.projectId, + { + object_name: data.editorSelectedObject ?? data.authoringPreview?.context.object?.name ?? selectedMetadataNode?.label ?? null, + routine_name: data.editorSelectedRoutine ?? data.authoringPreview?.context.routine?.name ?? null, + original_text: data.editorSourceText ?? sourceText, + proposed_text: proposedText ?? sourceText, + task_id: null, + session_id: "session.ide", + user_id: "current-user", + estimated_tokens: 2550, + expected_next_version_id: versionPreview.next_version_id, + approved_by: "current-user", + approval_note: t.guardedApplyNote, + apply_to_production: false + }, + apiUrl + ); + onAuthoringChangeApplied( + { + change_id: response.change_id, + project_id: response.project_id, + status: response.status, + target: response.preview.target, + version_id: response.version.version_id, + approved_by: "current-user", + approval_note: t.guardedApplyNote, + task_id: response.version.task_id, + session_id: response.version.session_id, + added_lines: response.preview.added_lines, + removed_lines: response.preview.removed_lines, + production_applied: response.production_applied + }, + versionToSummary(response.version) + ); + setApplyState("applied"); + setApplyMessage(`${formatChangeStatus(response.status, language)}: ${response.version.version_id}`); + } catch (error) { + setApplyState("error"); + setApplyMessage(error instanceof Error ? error.message : language === "ru" ? "Ошибка применения." : "Apply failed."); + } + } + + return ( +
+
+
+
+
+ + handleDefinition()} /> + handleReferences()} /> + + + + + + {canApplyPayload ? t.workspaceApplyReady : t.previewRequired} +
+
+
+ +
+
+ ); +} + +function SymbolNavigationPanel({ + definition, + language, + onDefinition, + onReferences, + references, + results +}: Readonly<{ + definition: SymbolResult | null; + language: UiLanguage; + onDefinition: (lineageId?: string) => void; + onReferences: (lineageId?: string) => void; + references: SymbolReferences | null; + results: SymbolResult[]; +}>) { + const t = messages[language]; + const referenceRows = references?.references.slice(0, 8) ?? []; + + return ( +
+
+
{t.referencesPanel}
+ {referenceRows.length} +
+
+ {results.length === 0 ? ( +
{language === "ru" ? "Выполните поиск символа или откройте использования выбранного объекта." : "Search a symbol or open references for the selected object."}
+ ) : ( + results.map((result) => ( +
+
{result.node.qualified_name}
+
{result.node.kind} · {formatSourceLocation(result.source, language)}
+
+ + +
+
+ )) + )} +
+ {definition ? ( +
+
{definition.node.qualified_name}
+
{formatSourceLocation(definition.source, language)}
+
+ ) : null} + {referenceRows.length > 0 ? ( +
+ {referenceRows.map((reference) => ( +
+
{reference.source?.qualified_name ?? reference.target?.qualified_name ?? reference.kind}
+
{reference.kind} · {reference.direction} · {formatSourceLocation(reference.location, language)}
+
+ ))} +
+ ) : null} +
+ ); +} + +function EditorToolbarButton({ + actionId, + disabled = false, + icon: Icon, + label, + onClick +}: Readonly<{ + actionId?: string; + disabled?: boolean; + icon: React.ComponentType<{ className?: string }>; + label: string; + onClick?: () => void; +}>) { + return ( + + ); +} + +function FastBslEditor({ + data, + onChange, + readOnly, + value +}: Readonly<{ + data: ProjectWorkspaceData; + onChange: (value: string) => void; + readOnly: boolean; + value: string; +}>) { + const textareaRef = useRef(null); + const highlightRef = useRef(null); + const [completionState, setCompletionState] = useState<{ + items: BslCompletionItem[]; + left: number; + prefix: string; + receiver: string | null; + replaceStart: number; + replaceEnd: number; + selectedIndex: number; + top: number; + } | null>(null); + const localCompletionItems = useMemo(() => buildLocalBslCompletionItems(data), [data]); + const highlightedLines = useMemo(() => value.split("\n"), [value]); + + function syncScroll() { + const textarea = textareaRef.current; + const highlight = highlightRef.current; + if (!textarea || !highlight) { + return; + } + highlight.scrollTop = textarea.scrollTop; + highlight.scrollLeft = textarea.scrollLeft; + } + + async function refreshCompletions(nextValue = value, caret = textareaRef.current?.selectionStart ?? 0, force = false) { + const context = getBslCompletionContext(nextValue, caret); + if (!context && !force) { + setCompletionState(null); + return; + } + const normalizedContext = context ?? { + prefix: "", + receiver: null, + replaceStart: caret, + replaceEnd: caret + }; + let items = filterCompletionItems(localCompletionItems, normalizedContext.prefix, normalizedContext.receiver); + if (normalizedContext.receiver) { + try { + const remoteItems = await getBslCompletions(data.projectId, { + apiUrl: data.apiUrl, + receiver: normalizedContext.receiver, + q: normalizedContext.prefix, + qualifiedName: data.editorSelectedObject, + limit: 80 + }); + items = mergeCompletionItems(remoteItems, items); + } catch { + items = filterCompletionItems(localCompletionItems, normalizedContext.prefix, normalizedContext.receiver); + } + } + setCompletionState( + items.length + ? { + ...normalizedContext, + items, + ...completionPopupPosition(nextValue, caret, textareaRef.current), + selectedIndex: 0 + } + : null + ); + } + + function updateValue(nextValue: string) { + onChange(nextValue); + window.requestAnimationFrame(() => { + const caret = textareaRef.current?.selectionStart ?? nextValue.length; + void refreshCompletions(nextValue, caret); + }); + } + + function insertCompletion(item: BslCompletionItem) { + const textarea = textareaRef.current; + if (!textarea || !completionState) { + return; + } + const insertText = item.insert_text ?? item.label; + const nextValue = `${value.slice(0, completionState.replaceStart)}${insertText}${value.slice(completionState.replaceEnd)}`; + const nextCaret = completionState.replaceStart + insertText.length; + onChange(nextValue); + setCompletionState(null); + window.requestAnimationFrame(() => { + textarea.focus(); + textarea.selectionStart = nextCaret; + textarea.selectionEnd = nextCaret; + syncScroll(); + }); + } + + function handleKeyDown(event: React.KeyboardEvent) { + if (event.ctrlKey && event.code === "Space") { + event.preventDefault(); + void refreshCompletions(value, event.currentTarget.selectionStart, true); + return; + } + if (!completionState) { + return; + } + if (event.key === "ArrowDown") { + event.preventDefault(); + setCompletionState((current) => current ? { ...current, selectedIndex: (current.selectedIndex + 1) % current.items.length } : current); + } else if (event.key === "ArrowUp") { + event.preventDefault(); + setCompletionState((current) => current ? { ...current, selectedIndex: (current.selectedIndex - 1 + current.items.length) % current.items.length } : current); + } else if (event.key === "Enter" || event.key === "Tab") { + event.preventDefault(); + insertCompletion(completionState.items[completionState.selectedIndex]); + } else if (event.key === "Escape") { + event.preventDefault(); + setCompletionState(null); + } + } + + return ( +
+ +