Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2530,6 +2530,11 @@ APP_LOG_TO_FILE=true
# should leave this unset; the sidecar is auto-managed.
# OMNIROUTE_TLS_PROXY_URL=

# Optional read-only seed directory for the pinned tls-client-node native binary.
# The file name and SHA-256 must match the bundled manifest; symlinks are rejected.
# Used by: open-sse/services/tlsClientDownloadDir.ts
# OMNIROUTE_TLS_CLIENT_SEED_DIR=

# ── Skills sandbox (experimental) ──
# Used by: src/lib/skills/builtins.ts. All values support comma lists where
# noted in the source.
Expand Down Expand Up @@ -2637,6 +2642,13 @@ APP_LOG_TO_FILE=true
# Default (when unset): 1 (tarballs emitted). Set to 0 to disable.
# OMNIROUTE_OPTIONAL_PACK_TAR=1

# Electron packaging target passed to prepare-electron-standalone.mjs. The root
# electron:build:* scripts and release workflow set these automatically; leave
# them unset for host-native local preparation. Platform accepts win32, darwin,
# or linux. Arches is a comma-separated list such as x64 or x64,arm64.
# OMNIROUTE_ELECTRON_TARGET_PLATFORM=
# OMNIROUTE_ELECTRON_TARGET_ARCHES=

# Electron smoke harness (used by scripts/dev/smoke-electron-packaged.mjs).
# ELECTRON_SMOKE_URL=http://127.0.0.1:20128/login
# ELECTRON_SMOKE_TIMEOUT_MS=45000
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/electron-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ jobs:
OMNIROUTE_USE_TURBOPACK: "0"
run: npm run build

- name: Verify TLS client runtime seed
run: node scripts/build/fixTlsClientNodeBinary.mjs --strict --standalone-dir .build/next/standalone

- name: Pack standalone bundle
# Deterministic tar.gz + byte-level manifest; the manifest embeds the
# archive's own sha256 so artifact-transfer corruption is caught before
Expand Down Expand Up @@ -258,6 +261,8 @@ jobs:
working-directory: electron
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OMNIROUTE_ELECTRON_TARGET_PLATFORM: ${{ matrix.os }}
OMNIROUTE_ELECTRON_TARGET_ARCHES: ${{ matrix.arch }}
run: npm run build:${{ matrix.target }}

- name: Smoke packaged Electron app
Expand Down
26 changes: 11 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ COPY open-sse/package.json ./open-sse/package.json
COPY scripts/build/postinstall.mjs ./scripts/build/postinstall.mjs
COPY scripts/build/postinstallSupport.mjs ./scripts/build/postinstallSupport.mjs
COPY scripts/build/native-binary-compat.mjs ./scripts/build/native-binary-compat.mjs
COPY scripts/build/fixTlsClientNodeBinary.mjs ./scripts/build/fixTlsClientNodeBinary.mjs
COPY open-sse/config/tlsClientNativeManifest.json ./open-sse/config/tlsClientNativeManifest.json
ENV NPM_CONFIG_LEGACY_PEER_DEPS=true
# --ignore-scripts blocks broad dependency install/postinstall hooks, closing
# the supply-chain attack surface where a transitive dep can run arbitrary code
Expand All @@ -104,24 +106,18 @@ RUN test -f package-lock.json \
# instead of `npx --yes`, which would install an arbitrary registry version
# on-demand and run its lifecycle scripts (Sonar docker:S6505).
#
# tls-client-node (chatgpt-web/claude-web/grok-web/lmarena/perplexity-web TLS
# impersonation) hits the same --ignore-scripts wall: its own postinstall.js
# fetches a platform .so/.dylib/.dll from the bogdanfinn/tls-client GitHub
# Releases API and is never invoked when npm ci skips lifecycle scripts. Unlike
# better-sqlite3 above, that script never throws on failure — it only
# `console.warn`s and exits 0 — so a rate-limited or offline build would
# otherwise succeed silently with an empty bin/ and only fail at first request
# in production (TlsClientUnavailableError, #7802). Run it explicitly here so
# a broken/rate-limited fetch fails the BUILD loudly instead of shipping a
# broken image.
# tls-client-node (shared by six web-provider transports) hits the same
# --ignore-scripts wall. Its upstream postinstall downloads the latest native
# release without verifying a checksum and exits 0 on failure. Our repair helper
# pins bogdanfinn/tls-client v1.15.1, checks GitHub's official SHA-256 for this
# platform, and runs in strict mode so Docker cannot ship an absent or tampered
# library.
RUN --mount=type=cache,id=s/92ca8a61-c1ba-421f-a389-d48ac7258c2d-npm-cache,target=/root/.npm \
npm ci --include=optional --no-audit --no-fund --legacy-peer-deps --ignore-scripts \
&& (cd node_modules/better-sqlite3 \
&& node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js rebuild) \
&& node -e "require('better-sqlite3')(':memory:').close()" \
&& node node_modules/tls-client-node/scripts/postinstall.js \
&& (test -n "$(find node_modules/tls-client-node/bin -mindepth 1 -print -quit 2>/dev/null)" \
|| (echo "tls-client-node native binary missing after postinstall — GitHub API fetch likely rate-limited or failed (#7802)" >&2 && exit 1))
&& node scripts/build/fixTlsClientNodeBinary.mjs --strict

# Build with Turbopack (stable in Next 16, the repo default). The v3.8.27-era
# TurbopackInternalError panic ("entered unreachable code: there must be a path to a
Expand Down Expand Up @@ -203,6 +199,7 @@ COPY . ./
RUN --mount=type=cache,id=s/92ca8a61-c1ba-421f-a389-d48ac7258c2d-next-cache,target=/app/.build/next/cache \
mkdir -p /app/data \
&& npm run build \
&& node scripts/build/fixTlsClientNodeBinary.mjs --strict --standalone-dir .build/next/standalone \
&& node --input-type=module -e "import { createRequire } from 'node:module'; import { pathToFileURL } from 'node:url'; const standaloneRoot = '/app/.build/next/standalone/node_modules/'; const require = createRequire('/app/.build/next/standalone/package.json'); for (const pkg of ['@atjsh/llmlingua-2', '@huggingface/transformers', 'js-tiktoken']) { const resolved = require.resolve(pkg); if (!resolved.startsWith(standaloneRoot)) throw new Error(pkg + ' resolved outside standalone: ' + resolved); await import(pathToFileURL(resolved).href); } const onnxRuntime = require.resolve('onnxruntime-node'); if (!onnxRuntime.startsWith(standaloneRoot)) throw new Error('onnxruntime-node resolved outside standalone: ' + onnxRuntime); await import(pathToFileURL(onnxRuntime).href);"

# ── Runner base ────────────────────────────────────────────────────────────
Expand All @@ -211,8 +208,7 @@ FROM base AS runner-base
LABEL org.opencontainers.image.title="omniroute" \
org.opencontainers.image.description="Unified AI proxy — route any LLM through one endpoint" \
org.opencontainers.image.url="https://omniroute.online" \
org.opencontainers.image.source="https://github.com/diegosouzapw/OmniRoute" \
org.opencontainers.image.licenses="MIT"
org.opencontainers.image.source="https://github.com/diegosouzapw/OmniRoute"

ENV NODE_ENV=production
ENV PORT=20128
Expand Down
20 changes: 11 additions & 9 deletions Dockerfile.bun
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ RUN if [ -d "node_modules/better-sqlite3" ]; then \
(cd node_modules/better-sqlite3 && bunx node-gyp rebuild); \
fi

# Fetch tls-client-node native binary if script exists
RUN if [ -f "node_modules/tls-client-node/scripts/postinstall.js" ]; then \
bun node_modules/tls-client-node/scripts/postinstall.js || true; \
fi
# Pin and checksum-verify the tls-client-node native binary; fail closed if unavailable.
RUN bun scripts/build/fixTlsClientNodeBinary.mjs --strict

# Disable Turbopack for Bun builder stage (Turbopack V8 internal worker bindings require Node)
ENV OMNIROUTE_USE_TURBOPACK=0
Expand All @@ -47,16 +45,17 @@ ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production

# Bun native Next.js build execution
RUN bun run --quiet build
RUN bun run --quiet build \
&& bun scripts/build/fixTlsClientNodeBinary.mjs --strict \
--standalone-dir .build/next/standalone

# ── Runner Base stage (100% Bun Native Production Runtime) ──────────────────
FROM oven/bun:1.3.14-slim AS runner-base

LABEL org.opencontainers.image.title="omniroute" \
org.opencontainers.image.description="Unified AI proxy — route any LLM through one endpoint (Bun Native)" \
org.opencontainers.image.url="https://omniroute.online" \
org.opencontainers.image.source="https://github.com/diegosouzapw/OmniRoute" \
org.opencontainers.image.licenses="MIT"
org.opencontainers.image.source="https://github.com/diegosouzapw/OmniRoute"

WORKDIR /app

Expand All @@ -73,14 +72,17 @@ ENV HOSTNAME=0.0.0.0
ENV OMNIROUTE_MEMORY_MB=1024

ENV DATA_DIR=/app/data
RUN mkdir -p /app/data
RUN mkdir -p /app/data \
&& chown -R bun:bun /app/data

COPY --from=builder /app/.build/next/standalone ./
COPY --from=builder --chown=bun:bun /app/.build/next/standalone ./
COPY --from=builder /app/node_modules/better-sqlite3 ./node_modules/better-sqlite3
ENV OMNIROUTE_MIGRATIONS_DIR=/app/migrations

COPY --from=builder /app/scripts/dev/healthcheck.mjs ./healthcheck.mjs

USER bun

EXPOSE 20128

HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,15 +461,15 @@ All **19** strategies — mix & match per combo step:

</div>

<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 352 providers, 90+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 43 i18n UI locales. OmniRoute is MIT-licensed and self-hostable. Competitor capabilities and counts may change; see the linked methodology."/>
<img src="./docs/diagrams/comparison-table.svg" width="100%" alt="What sets OmniRoute apart — a dated feature snapshot vs 9router, OpenRouter, CLIProxyAPI and LiteLLM across 13 capabilities. OmniRoute: 352 providers, 90+ free tiers built in, 19 routing strategies, 12-engine token compression, built-in MCP server with 110 tools, A2A agent protocol, persistent memory, guardrails, cloud agents, TLS fingerprint stealth, Desktop/Termux/PWA and 43 i18n UI locales. OmniRoute's own code is MIT-licensed and self-hostable; optional third-party dependencies retain their own licenses. Competitor capabilities and counts may change; see the linked methodology."/>

<sub>📊 Full methodology &amp; per-feature detail vs 9router, OpenRouter, CLIProxyAPI &amp; LiteLLM → [`docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md`](docs/comparison/OMNIROUTE_VS_ALTERNATIVES.md)</sub>

<br/>

## 💚 Support OmniRoute

OmniRoute is MIT-licensed and maintained in the open. If it saves you time or money, here's how to keep it independent — pick whatever fits you. Sponsorship never affects routing priority; it buys visibility, not ranking.
OmniRoute's own code is MIT-licensed and maintained in the open; bundled and optional third-party components retain their own licenses. If it saves you time or money, here's how to keep it independent — pick whatever fits you. Sponsorship never affects routing priority; it buys visibility, not ranking.

<table>
<tr><td nowrap>⭐ <b>Star the repo</b></td><td>Free — genuinely helps visibility</td><td><a href="https://github.com/diegosouzapw/OmniRoute">Star OmniRoute</a></td></tr>
Expand Down Expand Up @@ -769,7 +769,7 @@ From inside the editor: open the **Extensions** view, search **"OmniRoute"**, cl

</div>

<img src="./docs/diagrams/privacy-local.svg" width="100%" alt="Private and local-first — OmniRoute's gateway and control plane run on your machine. Prompts are sent to the upstream provider selected for each request; OmniRoute adds no hosted prompt-processing hop and telemetry is disabled by default. Credentials are encrypted at rest with AES-256-GCM; controls include API-key scoping, IP filtering, rate limits, prompt-injection guards, upstream-header scrubbing, opt-in PII redaction, sanitized errors and a local SQLite audit trail. OmniRoute is MIT-licensed and self-hostable."/>
<img src="./docs/diagrams/privacy-local.svg" width="100%" alt="Private and local-first — OmniRoute's gateway and control plane run on your machine. Prompts are sent to the upstream provider selected for each request; OmniRoute adds no hosted prompt-processing hop and telemetry is disabled by default. Credentials are encrypted at rest with AES-256-GCM; controls include API-key scoping, IP filtering, rate limits, prompt-injection guards, upstream-header scrubbing, opt-in PII redaction, sanitized errors and a local SQLite audit trail. OmniRoute's own code is MIT-licensed and self-hostable; bundled and optional third-party components retain their own licenses."/>

<sub>📖 [Authorization](docs/architecture/AUTHZ_GUIDE.md) · [Guardrails](docs/security/GUARDRAILS.md) · [Compliance](docs/security/COMPLIANCE.md)</sub>

Expand Down
Loading
Loading