Skip to content

Latest commit

 

History

History
417 lines (308 loc) · 31.5 KB

CONTRIBUTING.md

File metadata and controls

417 lines (308 loc) · 31.5 KB

Contributing to OmniRoute (Українська)

🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇧🇦 bs · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW


Thank you for your interest in contributing! This guide covers everything you need to get started.


Налаштування середовища розробки

Передумови

  • Node.js >=22.22.3 <23 або >=24.0.0 <27 (рекомендовано: 24 LTS)
  • npm 10+

Користувачам npm v11+ (Node 24+): після npm install перевірте, чи встановлено нативні модулі: node -e "require('better-sqlite3')". Якщо команда завершується помилкою MODULE_NOT_FOUND, виконайте npm approve-scripts better-sqlite3 && npm install. Див. Усунення несправностей.

  • Git

Клонування та встановлення

git clone https://github.com/diegosouzapw/OmniRoute.git
cd OmniRoute
npm install

Змінні середовища

# Створіть файл .env із шаблону
cp .env.example .env

# Згенеруйте необхідні секрети
echo "JWT_SECRET=$(openssl rand -base64 48)" >> .env
echo "API_KEY_SECRET=$(openssl rand -hex 32)" >> .env

Основні змінні для розробки:

Змінна Значення за замовчуванням для розробки Опис
PORT 20128 Порт сервера
NEXT_PUBLIC_BASE_URL http://localhost:20128 Базова URL-адреса для фронтенду
JWT_SECRET (згенеруйте вище) Секрет для підписування JWT
INITIAL_PASSWORD CHANGEME Пароль для першого входу
APP_LOG_LEVEL info Рівень деталізації журналювання

Налаштування панелі керування

Панель керування надає перемикачі інтерфейсу для функцій, які також можна налаштувати за допомогою змінних середовища:

Розташування налаштування Перемикач Опис
Налаштування → Розширені Режим налагодження Увімкнути журнали запитів налагодження (UI)
Налаштування → Загальні Видимість бічної панелі Показати/приховати розділи бічної панелі

Ці налаштування зберігаються в базі даних і не втрачаються після перезапусків, замінюючи встановлені значення змінних середовища за замовчуванням.

Локальний запуск

# Режим розробки (гаряче перезавантаження)
npm run dev

# Виробнича збірка
npm run build    # next build → .build/next/, потім assembleStandalone → dist/
npm run start

# Швидка компіляція лише бекенду/API для перевірки змін від учасників
npm run build:contributor

# Релізна збірка (чиста повторна збірка + контрольний файл HEAD — обов’язково для розгортання)
npm run build:release   # rm -rf .build dist, потім збірка + запис dist/BUILD_SHA

# Типова конфігурація порту
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev

Збірка для учасників виконує лише перевірку компіляції: вона не формує автономний дистрибутив і не збирає необов’язкові ресурси нативного пакування. Використовуйте звичайну виробничу збірку, коли потрібно перевірити готовий до розповсюдження пакет.

Структура результатів збірки

Каталог Вміст Відстежується
src/ Вихідний код застосунку (TypeScript / TSX) Так
.build/ Проміжні файли — результат next build (ігнорується Git, distDir = .build/next) Ні
dist/ Готовий до розповсюдження пакет — сформований assembleStandalone (ігнорується Git) Ні

Конвеєр збірки виконується за один прохід:

npm run build
  └─ next build → .build/next/standalone  (результат Next.js)
  └─ assembleStandalone()                 (копіює автономну збірку + статичні + публічні + нативні ресурси)
       └─ результат: dist/                (server.js, .next/static/, public/, node_modules/)

npm run build:release додатково спочатку очищає обидва каталоги та записує dist/BUILD_SHA (= git rev-parse --short HEAD) як контрольний маркер цілісності розгортання.

npm run build:contributor використовує профіль збірки лише для бекенду. Під час збірки він тимчасово замінює файли інтерфейсу панелі керування заглушками, зберігає обробники маршрутів API та відновлює початкові файли після збірки. Використовуйте npm run build для змін, які впливають на інтерфейс панелі керування, або для повної перевірки релізу; профіль для учасників не замінює релізну збірку.

Примітка щодо розгортання на VPS: віддалений каталог образу /usr/lib/node_modules/omniroute/app/ не змінився. Засоби розгортання синхронізують вміст dist/ із ним за допомогою rsync. Змінився лише шлях до результату збірки в репозиторії (app/ → dist/).

URL-адреси за замовчуванням:

  • Панель керування: http://localhost:20128/dashboard
  • API: http://localhost:20128/v1

Робочий процес Git

⚠️ НІКОЛИ не виконуйте коміти безпосередньо в main. Завжди використовуйте гілки функціональності.

Базова гілка PR: вибирайте активну гілку release/vX.Y.Z (а не main). Див. docs/ops/BRANCHING_MODEL.md, щоб дізнатися про модель з окремою гілкою для кожного випуску та створенням тегу під час випуску.

# Створіть гілку від останнього коміту активної гілки випуску (приклад: release/v3.8.49)
git fetch origin
git checkout -b feat/your-feature-name origin/release/v3.8.49
# ... внесіть зміни ...
git commit -m "feat: describe your change"
git push -u origin feat/your-feature-name
# Відкрийте Pull Request із базовою гілкою release/v3.8.49

Іменування гілок

Префікс Призначення
feat/ Нові функції
fix/ Виправлення помилок
refactor/ Реструктуризація коду
docs/ Зміни в документації
test/ Додавання/виправлення тестів
chore/ Інструменти, CI, залежності

Повідомлення комітів

Дотримуйтеся специфікації Conventional Commits:

feat: add circuit breaker for provider calls
fix: resolve JWT secret validation edge case
docs: update SECURITY.md with PII protection
test: add observability unit tests
refactor(db): consolidate rate limit tables

Області (v3.8): db, sse, oauth, dashboard, api, cli, docker, ci, mcp, a2a, memory, skills, cloud-agent, guardrails, compression, auto-combo, resilience, providers, executors, translator, domain, authz.


Запуск тестів

# Усі тести (модульні + vitest + екосистемні + e2e)
npm run test:all

# Окремий файл тестів (вбудований засіб запуску тестів Node.js — використовується для більшості тестів)
node --import tsx/esm --test tests/unit/your-file.test.ts

# Лише модульні тести, на які впливають ваші зміни (той самий селектор TIA, що й у шлюзі CI, #8084)
npm run test:scoped            # зміни в останньому коміті (або в робочому дереві)
npm run test:scoped:staged     # лише індексовані зміни — добре поєднується із запуском перед комітом
npm run test:scoped:full       # спочатку перебудувати мапу графа імпортів (після додавання/переміщення файлів)
# Код завершення 1 + "run the full suite" означає, що змінився центральний файл (tsconfig, package.json, …) або
# невідображене джерело — селектор безпечно завершується помилкою й ніколи не пропускає тести без повідомлення.

# Vitest (сервер MCP, autoCombo, кеш)
npm run test:vitest

# Тести E2E (потребують Playwright)
npm run test:e2e

# E2E для клієнтів протоколів (транспортні механізми MCP, A2A)
npm run test:protocols:e2e

# Тести сумісності з екосистемою
npm run test:ecosystem

# Поріг покриття: 60% інструкцій/рядків/функцій/гілок
npm run test:coverage
npm run coverage:report

# Перевірка лінтингу та форматування
npm run lint
npm run check

# Контрольний тест комбінацій із реальними зовнішніми сервісами (потребує доступу до VPS і коштів у реальних провайдерів)
# Звертається до РЕАЛЬНИХ провайдерів — це трохи коштує. НІКОЛИ не запускається в CI. Коректно пропускається без прапорця.
# Потрібно: доступ ssh root@192.168.0.15 (завантажує з VPS доступний лише для читання знімок БД).
RUN_COMBO_LIVE=1 npm run test:combo:live

# Оперативний тест фази 3 на VPS — звичайні скрипти Node ESM, які безпосередньо звертаються до активного сервера .15.
# Потрібно: доступ ssh root@192.168.0.15 (комбінації створюються/видаляються через SSH sqlite).
# Звертається до РЕАЛЬНИХ провайдерів (невелика вартість). Створює/видаляє лише комбінації __live_test__*. НІКОЛИ не запускається в CI.
# На .15 встановлено REQUIRE_API_KEY=false, тому ключ API не потрібен, але враховуються COMBO_LIVE_BASE_URL / COMBO_LIVE_API_KEY, якщо їх задано.
npm run test:combo:live:vps              # 7 сценаріїв HTTP (пріоритет/циклічний розподіл/зважений розподіл/вартість/об'єднання/автоматичний режим + працездатність)
npm run test:combo:live:vps:failover     # додає реальний сценарій перемикання між провайдерами (загалом 8)

Примітки щодо покриття:

  • npm run test:coverage вимірює покриття вихідного коду основним набором модульних тестів, виключає tests/** і включає open-sse/**
  • Запити на злиття мають зберігати поріг покриття на рівні 60%+ інструкцій/рядків/функцій/гілок
  • Якщо PR змінює робочий код у src/, open-sse/, electron/ або bin/, у тому самому PR потрібно додати або оновити автоматизовані тести
  • npm run coverage:report виводить докладний звіт за кожним файлом з останнього запуску перевірки покриття
  • npm run test:coverage:legacy зберігає старішу метрику для історичного порівняння
  • Поетапний план покращення покриття див. у docs/ops/COVERAGE_PLAN.md

Вимоги до запиту на злиття

Перш ніж відкривати PR, скористайтеся рекомендованим процесом внесення змін, щоб виконати цільовий цикл перевірок для внесених змін. Повний набір модульних тестів (4 сегменти CI), Vitest, поріг покриття 60%+ і робоча збірка належать до відповідальності CI — їх локальний запуск не надає жодної додаткової інформації, якої ще не нададуть перевірки PR, а на менш потужних машинах він може перевантажити систему (#8084):

  • Запустіть файли тестів, які охоплюють ваші зміни: node --import tsx/esm --test tests/unit/<file>.test.ts
  • Запустіть npm run lint
  • Щоразу, коли змінюється робочий код, додайте або оновіть автоматизовані тести в тому самому PR
  • Якщо робочий код змінено, зазначте змінені або додані файли тестів в описі PR
  • Перевірте результат SonarQube для PR, якщо секрети проєкту налаштовано в CI

Поточний стан тестів: 122 файли модульних тестів, що охоплюють:

  • Транслятори провайдерів і перетворення форматів
  • Обмеження частоти запитів, автоматичний вимикач і відмовостійкість
  • Семантичний кеш, ідемпотентність, відстеження прогресу
  • Операції з базою даних і схему (21 модуль БД)
  • Потоки OAuth та автентифікацію
  • Валідацію кінцевих точок API (Zod v4)
  • Інструменти сервера MCP і контроль областей доступу
  • Системи пам'яті та навичок

Стиль коду

  • ESLint — запускайте npm run lint перед комітом
  • Prettier — автоматичне форматування через lint-staged під час коміту (2 пробіли, крапки з комою, подвійні лапки, ширина 100 символів, кінцеві коми в стилі es5)
  • TypeScript — увесь код у src/ використовує .ts/.tsx; open-sse/ використовує .ts/.js; документуйте за допомогою TSDoc (@param, @returns, @throws)
  • Без eval() — ESLint застосовує правила no-eval, no-implied-eval, no-new-func
  • Валідація Zod — використовуйте схеми Zod v4 для валідації всіх вхідних даних API
  • Іменування: файли = camelCase/kebab-case, компоненти = PascalCase, константи = UPPER_SNAKE

Обробка помилок / порожні блоки catch

Ніколи не залишайте catch без пояснення. Віднесіть його до однієї з двох категорій (це практичне втілення суворого правила «ніколи мовчки не ігнорувати помилки в потоках SSE»):

  • Навмисно (наше власне очищення/телеметрія за принципом best-effort) — помилка тут очікувана й нешкідлива; додайте однорядковий коментар із поясненням, без журналювання (ця домовленість дає змогу уникнути шуму від журналювання кожного запиту).

    } catch {} // закриття вже закритого контролера після від’єднання клієнта є очікуваним
  • Слід журналювати (зовнішній/наданий викликачем код або ігнорування змінює потік керування) — залиште catch (ніколи не дозволяйте йому перервати потік), але виведіть контекстне повідомлення через console.debug/warn, щоб помилку можна було виявити.

    } catch (e) {
      console.debug("[STREAM] помилка зворотного виклику onFailure:", e);
    }

Приклади застосування див. у open-sse/utils/stream.ts і open-sse/utils/streamHandler.ts.


Project Structure

src/                        # TypeScript (.ts / .tsx)
├── app/                    # Next.js 16 App Router
│   ├── (dashboard)/        # Dashboard pages (23 sections)
│   ├── api/                # API routes (51 directories)
│   └── login/              # Auth pages (.tsx)
├── domain/                 # Policy engine (policyEngine, comboResolver, costRules, etc.)
├── lib/                    # Core business logic (.ts)
│   ├── a2a/                # Agent-to-Agent v0.3 protocol server
│   ├── acp/                # Agent Communication Protocol registry
│   ├── compliance/         # Compliance policy engine
│   ├── db/                 # SQLite database layer (110 top-level modules + 130 migrations)
│   ├── memory/             # Persistent conversational memory
│   ├── oauth/              # OAuth providers, services, and utilities
│   ├── skills/             # Extensible skill framework
│   ├── usage/              # Usage tracking and cost calculation
│   └── localDb.ts          # Re-export layer only — never add logic here
├── middleware/              # Request middleware (promptInjectionGuard)
├── mitm/                   # MITM proxy (cert, DNS, target routing)
├── shared/
│   ├── components/         # React components (.tsx)
│   ├── constants/          # Provider definitions (329), MCP scopes, routing strategies
│   ├── utils/              # Circuit breaker, sanitizer, auth helpers
│   └── validation/         # Zod v4 schemas
└── sse/                    # SSE proxy pipeline

open-sse/                   # @omniroute/open-sse workspace
├── executors/              # 89 executor implementation modules
├── handlers/               # 11 request handlers (chat, responses, embeddings, images, etc.)
├── mcp-server/             # MCP server (107 tools, 3 transports, 32 scopes)
├── services/               # 178 top-level services (combo, autoCombo, rateLimitManager, etc.)
├── translator/             # Format translators (OpenAI ↔ Claude ↔ Gemini ↔ Responses ↔ Ollama)
├── transformer/            # Responses API transformer
└── utils/                  # 22 utility modules (stream, TLS, proxy, logging)

electron/                   # Electron desktop app (cross-platform)

tests/
├── unit/                   # Node.js test runner (122 test files)
├── integration/            # Integration tests
├── e2e/                    # Playwright tests
├── security/               # Security tests
├── translator/             # Translator-specific tests
└── load/                   # Load tests

docs/                       # Documentation
├── ARCHITECTURE.md         # System architecture
├── API_REFERENCE.md        # All endpoints
├── USER_GUIDE.md           # Provider setup, CLI integration
├── TROUBLESHOOTING.md      # Common issues
├── MCP-SERVER.md           # MCP server (107 tools)
├── A2A-SERVER.md           # A2A agent protocol
├── AUTO-COMBO.md           # Auto-combo engine
├── CLI-TOOLS.md            # CLI tools integration
├── COVERAGE_PLAN.md        # Test coverage improvement plan
├── openapi.yaml            # OpenAPI specification
└── adr/                    # Architecture Decision Records

Додавання нового провайдера

Крок 1: Зареєструйте константи провайдера

Додайте їх до src/shared/constants/providers.ts — валідація за допомогою Zod виконується під час завантаження модуля.

Крок 2: Додайте виконавець (якщо потрібна власна логіка)

Створіть виконавець у open-sse/executors/your-provider.ts, успадкувавши його від базового виконавця.

Крок 3: Додайте транслятор (якщо формат відрізняється від OpenAI)

Створіть транслятори запитів і відповідей у open-sse/translator/.

Крок 4: Додайте конфігурацію OAuth (якщо використовується OAuth)

Додайте облікові дані OAuth до src/lib/oauth/constants/oauth.ts, а сервіс — до src/lib/oauth/services/.

Якщо upstream-провайдер поширює публічний OAuth client_id/secret або ключ Firebase Web API у своєму публічному CLI / браузерному пакеті, не вбудовуйте його як рядковий літерал. Використовуйте resolvePublicCred() з open-sse/utils/publicCreds.ts і додайте запис із замаскованими байтами до EMBEDDED_DEFAULTS. Повний обов’язковий робочий процес задокументовано в docs/security/PUBLIC_CREDS.md.

Усередині обробників/виконавців повідомлення про помилки, що надходять клієнту, мають проходити через buildErrorBody() / sanitizeErrorMessage() з open-sse/utils/error.ts — ніколи не додавайте необроблені err.stack або err.message до тіла Response. Див. docs/security/ERROR_SANITIZATION.md.

Крок 5: Зареєструйте моделі

Додайте визначення моделей до open-sse/config/providerRegistry.ts.

Крок 6: Додайте тести

Напишіть модульні тести в tests/unit/, які щонайменше охоплюють:

  • Реєстрацію провайдера
  • Трансляцію запитів і відповідей
  • Обробку помилок

Контрольний список Pull Request

  • Тести проходять (npm test)
  • Перевірка лінтером проходить (npm run lint)
  • Збірка виконується успішно (npm run build)
  • Додано типи TypeScript для нових публічних функцій та інтерфейсів
  • Немає жорстко закодованих секретів або резервних значень
  • Публічні облікові дані вбудовано через resolvePublicCred() (див. docs/security/PUBLIC_CREDS.md), а не задано як літерали
  • Відповіді з помилками проходять через buildErrorBody() / sanitizeErrorMessage() — у тілах відповідей немає необроблених трасувань стека (див. docs/security/ERROR_SANITIZATION.md)
  • Команди оболонки (exec / spawn) передають значення середовища виконання через env, а не через інтерполяцію рядків
  • Усі вхідні дані перевіряються за допомогою схем Zod
  • Для змін, видимих користувачам, додано фрагмент журналу змін у changelog.d/{features|fixes|maintenance}/<PR>-<slug>.md (див. changelog.d/README.md) — не редагуйте CHANGELOG.md безпосередньо; фрагменти об’єднуються під час випуску й ніколи не спричиняють конфліктів між PR
  • Документацію оновлено (якщо застосовно)
  • Не створено нових сповіщень CodeQL / Secret-Scanning або кожне з них відхилено з технічним обґрунтуванням і посиланням на відповідний документ у docs/security/
  • Маршрути, які запускають дочірні процеси (/api/mcp/, /api/cli-tools/runtime/), класифіковано як isLocalOnlyPath() у src/server/authz/routeGuard.ts — див. жорстке правило №15
  • У повідомленнях комітів немає завершальних рядків Co-Authored-By — коміти мають відображатися виключно під Git-ідентичністю власника репозиторію (жорстке правило №16)

Releasing

Releases are managed via the /generate-release workflow. When a new GitHub Release is created, the package is automatically published to npm via GitHub Actions.


Отримання допомоги