File size: 16,387 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
# Contributing to OmniRoute

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

---

## Development Setup

### Prerequisites

- **Node.js** `>=22.22.3 <23`, or `>=24.0.0 <27` (recommended: 24 LTS)
- **npm** 10+
- **Git**

### Clone & Install

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

### Environment Variables

```bash
# Create your .env from the template
cp .env.example .env

# Generate required secrets
echo "JWT_SECRET=$(openssl rand -base64 48)" >> .env
echo "API_KEY_SECRET=$(openssl rand -hex 32)" >> .env
```

Key variables for development:

| Variable               | Development Default      | Description           |
| ---------------------- | ------------------------ | --------------------- |
| `PORT`                 | `20128`                  | Server port           |
| `NEXT_PUBLIC_BASE_URL` | `http://localhost:20128` | Base URL for frontend |
| `JWT_SECRET`           | (generate above)         | JWT signing secret    |
| `INITIAL_PASSWORD`     | `CHANGEME`               | First login password  |
| `APP_LOG_LEVEL`        | `info`                   | Log verbosity level   |

### Dashboard Settings

The dashboard provides UI toggles for features that can also be configured via environment variables:

| Setting Location    | Toggle             | Description                    |
| ------------------- | ------------------ | ------------------------------ |
| Settings β†’ Advanced | Debug Mode         | Enable debug request logs (UI) |
| Settings β†’ General  | Sidebar Visibility | Show/hide sidebar sections     |

These settings are stored in the database and persist across restarts, overriding env var defaults when set.

### Running Locally

```bash
# Development mode (hot reload)
npm run dev

# Production build
npm run build    # next build β†’ .build/next/ then assembleStandalone β†’ dist/
npm run start

# Release build (clean rebuild + HEAD sentinel β€” required for deploy)
npm run build:release   # rm -rf .build dist && build + writes dist/BUILD_SHA

# Common port configuration
PORT=20128 NEXT_PUBLIC_BASE_URL=http://localhost:20128 npm run dev
```

### Build Output Layout

| Directory | Contents                                                                  | Tracked |
| --------- | ------------------------------------------------------------------------- | ------- |
| `src/`    | Application source (TypeScript / TSX)                                     | Yes     |
| `.build/` | Intermediates β€” `next build` output (gitignored, `distDir = .build/next`) | No      |
| `dist/`   | Shippable bundle β€” assembled by `assembleStandalone` (gitignored)         | No      |

The build pipeline is a single pass:

```
npm run build
  └─ next build β†’ .build/next/standalone  (Next.js output)
  └─ assembleStandalone()                 (copies standalone + static + public + native assets)
       └─ output: dist/                   (server.js, .next/static/, public/, node_modules/)
```

`npm run build:release` additionally cleans both directories first and writes
`dist/BUILD_SHA` (= `git rev-parse --short HEAD`) as a deploy integrity sentinel.

> **VPS deploy note:** the remote image directory `/usr/lib/node_modules/omniroute/app/`
> is unchanged. The deploy skills rsync the contents of `dist/` into it.
> Only the in-repo build output path moved (`app/` β†’ `dist/`).

Default URLs:

- **Dashboard**: `http://localhost:20128/dashboard`
- **API**: `http://localhost:20128/v1`

---

## Git Workflow

> ⚠️ **NEVER commit directly to `main`.** Always use feature branches.

```bash
git checkout -b feat/your-feature-name
# ... make changes ...
git commit -m "feat: describe your change"
git push -u origin feat/your-feature-name
# Open a Pull Request on GitHub
```

### Branch Naming

| Prefix      | Purpose                   |
| ----------- | ------------------------- |
| `feat/`     | New features              |
| `fix/`      | Bug fixes                 |
| `refactor/` | Code restructuring        |
| `docs/`     | Documentation changes     |
| `test/`     | Test additions/fixes      |
| `chore/`    | Tooling, CI, dependencies |

### Commit Messages

Follow [Conventional Commits](https://www.conventionalcommits.org/):

```
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
```

Scopes (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`.

---

## Running Tests

```bash
# All tests (unit + vitest + ecosystem + e2e)
npm run test:all

# Single test file (Node.js native test runner β€” most tests use this)
node --import tsx/esm --test tests/unit/your-file.test.ts

# Vitest (MCP server, autoCombo, cache)
npm run test:vitest

# E2E tests (requires Playwright)
npm run test:e2e

# Protocol clients E2E (MCP transports, A2A)
npm run test:protocols:e2e

# Ecosystem compatibility tests
npm run test:ecosystem

# Coverage gate: 75% statements/lines/functions, 70% branches
npm run test:coverage
npm run coverage:report

# Lint + format check
npm run lint
npm run check

# Gated real-upstream combo smoke (requires VPS access + real provider credits)
# Hits REAL providers β€” costs a little. NEVER runs in CI. Skips cleanly without the gate.
# Needs: ssh root@192.168.0.15 access (sources a read-only DB snapshot from the VPS).
RUN_COMBO_LIVE=1 npm run test:combo:live

# Phase-3 VPS live smoke β€” plain Node ESM scripts, hit the live .15 server directly.
# Requires: ssh root@192.168.0.15 access (combos created/torn down via SSH sqlite).
# Hits REAL providers (small cost). Creates/deletes only __live_test__* combos. NEVER runs in CI.
# REQUIRE_API_KEY=false on .15 so no API key needed, but honors COMBO_LIVE_BASE_URL / COMBO_LIVE_API_KEY if set.
npm run test:combo:live:vps              # 7 HTTP scenarios (priority/round-robin/weighted/cost/fusion/auto + health)
npm run test:combo:live:vps:failover     # adds a real cross-provider failover scenario (8 total)
```

Coverage notes:

- `npm run test:coverage` measures source coverage for the main unit test suite, excludes `tests/**`, and includes `open-sse/**`
- Pull requests must keep the coverage gate at **75%+** statements/lines/functions and **70%+** branches
- If a PR changes production code in `src/`, `open-sse/`, `electron/`, or `bin/`, it must add or update automated tests in the same PR
- `npm run coverage:report` prints the detailed file-by-file report from the latest coverage run
- `npm run test:coverage:legacy` preserves the older metric for historical comparison
- See `docs/ops/COVERAGE_PLAN.md` for the phased coverage improvement roadmap

### Pull Request Requirements

Before opening or merging a PR:

- Run `npm run test:unit`
- Run `npm run test:coverage`
- Ensure the coverage gate stays at **75%+** statements/lines/functions, **70%+** branches
- Include the changed or added test files in the PR description when production code changed
- Check the SonarQube result on the PR when the project secrets are configured in CI

Current test status: **122 unit test files** covering:

- Provider translators and format conversion
- Rate limiting, circuit breaker, and resilience
- Semantic cache, idempotency, progress tracking
- Database operations and schema (21 DB modules)
- OAuth flows and authentication
- API endpoint validation (Zod v4)
- MCP server tools and scope enforcement
- Memory and Skills systems

---

## Code Style

- **ESLint** β€” Run `npm run lint` before committing
- **Prettier** β€” Auto-formatted via `lint-staged` on commit (2 spaces, semicolons, double quotes, 100 char width, es5 trailing commas)
- **TypeScript** β€” All `src/` code uses `.ts`/`.tsx`; `open-sse/` uses `.ts`/`.js`; document with TSDoc (`@param`, `@returns`, `@throws`)
- **No `eval()`** β€” ESLint enforces `no-eval`, `no-implied-eval`, `no-new-func`
- **Zod validation** β€” Use Zod v4 schemas for all API input validation
- **Naming**: Files = camelCase/kebab-case, components = PascalCase, constants = UPPER_SNAKE

---

## 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 (21 modules + 16 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 (177), MCP scopes, 14 routing strategies
β”‚   β”œβ”€β”€ utils/              # Circuit breaker, sanitizer, auth helpers
β”‚   └── validation/         # Zod v4 schemas
└── sse/                    # SSE proxy pipeline

open-sse/                   # @omniroute/open-sse workspace
β”œβ”€β”€ executors/              # 14 provider-specific request executors
β”œβ”€β”€ handlers/               # 11 request handlers (chat, responses, embeddings, images, etc.)
β”œβ”€β”€ mcp-server/             # MCP server (25 tools, 3 transports, 10 scopes)
β”œβ”€β”€ services/               # 36+ 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 (1,574 test files)
β”œβ”€β”€ integration/            # Integration tests
β”œβ”€β”€ e2e/                    # Playwright tests
β”œβ”€β”€ security/               # Security tests
β”œβ”€β”€ translator/             # Translator-specific tests
└── load/                   # Load tests

docs/
β”œβ”€β”€ adr/                     # Architecture Decision Records
β”œβ”€β”€ architecture/            # System architecture & resilience
β”œβ”€β”€ comparison/              # OmniRoute vs alternatives
β”œβ”€β”€ compression/             # Compression guides & rules
β”œβ”€β”€ dev/                     # Development guides
β”œβ”€β”€ diagrams/                # Architecture diagrams
β”œβ”€β”€ frameworks/              # MCP, A2A, OpenCode, Memory, Skills
β”œβ”€β”€ guides/                  # User guide, Docker, setup, troubleshooting
β”œβ”€β”€ i18n/                    # Internationalized README translations
β”œβ”€β”€ marketing/               # Marketing materials
β”œβ”€β”€ ops/                     # Deployment, proxy, coverage, releases
β”œβ”€β”€ providers/               # Provider-specific docs
β”œβ”€β”€ reference/               # API reference, env vars, CLI tools, free tiers
β”œβ”€β”€ releases/                # Release notes
β”œβ”€β”€ routing/                 # Auto-combo engine, reasoning replay
β”œβ”€β”€ screenshots/             # Dashboard screenshots
β”œβ”€β”€ security/                # Guardrails, compliance, stealth, tokens
└── specs/                   # Design specs
```

---

## Adding a New Provider

### Step 1: Register Provider Constants

Add to `src/shared/constants/providers.ts` β€” Zod-validated at module load.

### Step 2: Add Executor (if custom logic needed)

Create executor in `open-sse/executors/your-provider.ts` extending the base executor.

### Step 3: Add Translator (if non-OpenAI format)

Create request/response translators in `open-sse/translator/`.

### Step 4: Add OAuth Config (if OAuth-based)

Add OAuth credentials in `src/lib/oauth/constants/oauth.ts` and service in `src/lib/oauth/services/`.

If the upstream provider distributes a public OAuth client_id/secret or Firebase Web API key inside its public CLI / browser bundle, **do not** embed it as a string literal. Use `resolvePublicCred()` from `open-sse/utils/publicCreds.ts` and add a masked byte entry to `EMBEDDED_DEFAULTS`. The full mandatory workflow is documented in [`docs/security/PUBLIC_CREDS.md`](./docs/security/PUBLIC_CREDS.md).

Inside handlers/executors, error messages reaching the client must go through `buildErrorBody()` / `sanitizeErrorMessage()` from `open-sse/utils/error.ts` β€” never put raw `err.stack` or `err.message` in a Response body. See [`docs/security/ERROR_SANITIZATION.md`](./docs/security/ERROR_SANITIZATION.md).

### Step 5: Register Models

Add model definitions in `open-sse/config/providerRegistry.ts`.

### Step 6: Add Tests

Write unit tests in `tests/unit/` covering at minimum:

- Provider registration
- Request/response translation
- Error handling

---

## Pull Request Checklist

- [ ] Tests pass (`npm test`)
- [ ] Linting passes (`npm run lint`)
- [ ] Build succeeds (`npm run build`)
- [ ] TypeScript types added for new public functions and interfaces
- [ ] No hardcoded secrets or fallback values
- [ ] Public upstream credentials embedded via `resolvePublicCred()` (see [`docs/security/PUBLIC_CREDS.md`](./docs/security/PUBLIC_CREDS.md)), never as literals
- [ ] Error responses route through `buildErrorBody()` / `sanitizeErrorMessage()` β€” no raw stack traces in response bodies (see [`docs/security/ERROR_SANITIZATION.md`](./docs/security/ERROR_SANITIZATION.md))
- [ ] Shell commands (`exec` / `spawn`) pass runtime values via `env`, not via string interpolation
- [ ] All inputs validated with Zod schemas
- [ ] CHANGELOG updated (if user-facing change)
- [ ] Documentation updated (if applicable)
- [ ] No new CodeQL / Secret-Scanning alerts opened, or each one dismissed with technical justification referencing the relevant `docs/security/` doc
- [ ] Routes that spawn child processes (`/api/mcp/`, `/api/cli-tools/runtime/`) classified as `isLocalOnlyPath()` in `src/server/authz/routeGuard.ts` β€” see [Hard Rule #15](docs/security/ROUTE_GUARD_TIERS.md)
- [ ] No `Co-Authored-By` trailers in commit messages β€” commits must appear solely under the repository owner's Git identity (Hard Rule #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.

For VPS deploys, use `npm run build:release` (not `npm run build`) β€” it performs a clean
rebuild, assembles the bundle into `dist/`, and writes the `dist/BUILD_SHA` sentinel.
Then use the `/deploy-vps-*-cc` skills which rsync `dist/` to the remote `app/` directory.

---

## Getting Help

- **Architecture**: See [`docs/architecture/ARCHITECTURE.md`](docs/architecture/ARCHITECTURE.md)
- **API Reference**: See [`docs/reference/API_REFERENCE.md`](docs/reference/API_REFERENCE.md)
- **Security docs**: [`docs/security/CLI_TOKEN.md`](docs/security/CLI_TOKEN.md), [`docs/security/ROUTE_GUARD_TIERS.md`](docs/security/ROUTE_GUARD_TIERS.md), [`docs/security/ERROR_SANITIZATION.md`](docs/security/ERROR_SANITIZATION.md), [`docs/security/PUBLIC_CREDS.md`](docs/security/PUBLIC_CREDS.md)
- **Ops docs**: [`docs/ops/SQLITE_RUNTIME.md`](docs/ops/SQLITE_RUNTIME.md)
- **Issues**: [github.com/diegosouzapw/OmniRoute/issues](https://github.com/diegosouzapw/OmniRoute/issues)
- **ADRs**: See `docs/adr/` for architectural decision records