From a9f69711c618621ecbdcf4e63ac14f65d7f10978 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 17 Mar 2026 04:24:46 -0300 Subject: [PATCH] fix(build): remove node: protocol prefix from all src/ imports (#turbopack-compat) Turbopack (Next.js 15) does not process node: URL prefixes correctly when bundling server-side files that get transitively included. Removed the node: prefix from 17 files: - src/lib/db/migrationRunner.ts (node:fs, node:path, node:url) - src/lib/db/core.ts (node:path, node:fs) - src/lib/db/backup.ts (node:path, node:fs) - src/lib/db/prompts.ts (node:fs) - src/lib/dataPaths.ts (node:path, node:os) - src/app/api/settings/route.ts - src/app/api/storage/health/route.ts - src/app/api/oauth/[provider]/[action]/route.ts - src/app/api/db-backups/{exportAll,import,export}/route.ts - src/shared/middleware/correlationId.ts - src/shared/utils/requestId.ts - src/lib/apiBridgeServer.ts - src/lib/cacheLayer.ts - src/lib/semanticCache.ts - src/lib/oauth/providers/kimi-coding.ts Also updated generate-release.md: Docker Hub sync and dual-VPS deploy are now mandatory steps in every release. --- .agents/workflows/generate-release.md | 43 +++++++++++++++++-- .agents/workflows/resolve-issues.md | 4 +- .agents/workflows/review-prs.md | 6 ++- CHANGELOG.md | 11 +++++ docs/openapi.yaml | 2 +- package-lock.json | 5 ++- package.json | 2 +- .../dashboard/media/MediaPageClient.tsx | 26 +++++++---- src/app/api/db-backups/export/route.ts | 6 +-- src/app/api/db-backups/exportAll/route.ts | 6 +-- src/app/api/db-backups/import/route.ts | 6 +-- .../api/oauth/[provider]/[action]/route.ts | 2 +- src/app/api/settings/route.ts | 2 +- src/app/api/storage/health/route.ts | 4 +- src/lib/apiBridgeServer.ts | 4 +- src/lib/cacheLayer.ts | 2 +- src/lib/dataPaths.ts | 4 +- src/lib/db/backup.ts | 4 +- src/lib/db/core.ts | 4 +- src/lib/db/migrationRunner.ts | 6 +-- src/lib/db/prompts.ts | 2 +- src/lib/oauth/providers/kimi-coding.ts | 4 +- src/lib/semanticCache.ts | 2 +- src/shared/middleware/correlationId.ts | 2 +- src/shared/utils/requestId.ts | 8 +--- 25 files changed, 113 insertions(+), 54 deletions(-) diff --git a/.agents/workflows/generate-release.md b/.agents/workflows/generate-release.md index 374e6adbbc..0ce8912eb5 100644 --- a/.agents/workflows/generate-release.md +++ b/.agents/workflows/generate-release.md @@ -85,12 +85,49 @@ git push origin main --tags gh release create v2.x.y --title "v2.x.y — summary" --notes "..." ``` -### 8. Deploy to VPS (if requested) +### 8. 🐳 Trigger Docker Hub build (MANDATORY — keep npm and Docker in sync) -See `/deploy-vps` workflow for Akamai VPS or use npm for local VPS: +> **CRITICAL**: Docker Hub and npm MUST always publish the same version. +> The Docker image is built automatically via GitHub Actions when a new tag is pushed. +> After pushing the tag in step 5-6, **verify the workflow runs**: ```bash -ssh root@ "npm install -g omniroute@2.x.y && pm2 restart omniroute" +# Verify the Docker workflow triggered +gh run list --repo diegosouzapw/OmniRoute --workflow docker-publish.yml --limit 3 + +# Wait for the Docker build to complete (usually 5–10 min) +gh run watch --repo diegosouzapw/OmniRoute + +# After completion, verify on Docker Hub: +# https://hub.docker.com/r/diegosouzapw/omniroute/tags +``` + +If the Docker build was not triggered automatically, trigger it manually: + +```bash +gh workflow run docker-publish.yml --repo diegosouzapw/OmniRoute --ref v2.x.y +``` + +### 9. Deploy to BOTH VPS environments (MANDATORY) + +> Always deploy to **both** environments after every release. +> See `/deploy-vps` workflow for detailed steps. + +```bash +# Build and pack locally +cd /home/diegosouzapw/dev/proxys/9router && npm run build:cli && npm pack --ignore-scripts + +# Deploy to LOCAL VPS (192.168.0.15) +scp omniroute-*.tgz root@192.168.0.15:/tmp/ +ssh root@192.168.0.15 "npm install -g /tmp/omniroute-*.tgz --ignore-scripts && pm2 restart omniroute && pm2 save" + +# Deploy to AKAMAI VPS (69.164.221.35) +scp omniroute-*.tgz root@69.164.221.35:/tmp/ +ssh root@69.164.221.35 "npm install -g /tmp/omniroute-*.tgz --ignore-scripts && pm2 restart omniroute && pm2 save" + +# Verify both +curl -s -o /dev/null -w "LOCAL: HTTP %{http_code}\n" http://192.168.0.15:20128/ +curl -s -o /dev/null -w "AKAMAI: HTTP %{http_code}\n" http://69.164.221.35:20128/ ``` ## Notes diff --git a/.agents/workflows/resolve-issues.md b/.agents/workflows/resolve-issues.md index af9ff76513..b7b2cbfebd 100644 --- a/.agents/workflows/resolve-issues.md +++ b/.agents/workflows/resolve-issues.md @@ -21,8 +21,8 @@ This workflow fetches all open issues from the project's GitHub repository, clas // turbo -- Run: `gh issue list --repo / --state open --limit 100 --json number,title,labels,body,comments,createdAt,author` -- Parse the JSON output to get a list of all open issues +- Run: `gh issue list --repo / --state open --limit 500 --json number,title,labels,body,comments,createdAt,author` +- Parse the JSON output to get a list of **all** open issues - Sort by oldest first (FIFO) ### 3. Classify Each Issue diff --git a/.agents/workflows/review-prs.md b/.agents/workflows/review-prs.md index 6d2361fd82..ac2878a8b9 100644 --- a/.agents/workflows/review-prs.md +++ b/.agents/workflows/review-prs.md @@ -18,7 +18,11 @@ This workflow fetches all open PRs from the project's GitHub repository, perform ### 2. Fetch Open Pull Requests -- Navigate to `https://github.com///pulls` and scrape all open PRs +// turbo + +- Run: `gh pr list --repo / --state open --limit 500 --json number,title,author,headRefName,body,createdAt,additions,deletions,files` +- This fetches **all** open PRs without restriction. Get the diff for each with: + `gh pr diff --repo /` - For each open PR, collect: - PR number, title, author, branch, number of commits, date - PR description/body diff --git a/CHANGELOG.md b/CHANGELOG.md index 242c4e6ab9..62aa69ca82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ --- +## [2.6.6] — 2026-03-17 + +> Hotfix: Turbopack/Docker compatibility — remove `node:` protocol from all `src/` imports. + +### 🐛 Bug Fixes + +- **fix(build)**: Removed `node:` protocol prefix from `import` statements in 17 files under `src/`. The `node:fs`, `node:path`, `node:url`, `node:os` etc. imports caused `Ecmascript file had an error` on Turbopack builds (Next.js 15 Docker) and on upgrades from older npm global installs. Affected files: `migrationRunner.ts`, `core.ts`, `backup.ts`, `prompts.ts`, `dataPaths.ts`, and 12 others in `src/app/api/` and `src/lib/`. +- **chore(workflow)**: Updated `generate-release.md` to make Docker Hub sync and dual-VPS deploy **mandatory** steps in every release. + +--- + ## [2.6.5] — 2026-03-17 > Sprint: reasoning model param filtering, local provider 404 fix, Kilo Gateway provider, dependency bumps. diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 6283ded5b2..53e7b2137f 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: OmniRoute API - version: 2.6.5 + version: 2.6.6 description: | OmniRoute is a local-first AI API proxy router. It provides an OpenAI-compatible endpoint that routes requests to multiple AI providers with load balancing, diff --git a/package-lock.json b/package-lock.json index 1989d2f376..9c64cf5743 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute", - "version": "2.6.5", + "version": "2.6.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute", - "version": "2.6.5", + "version": "2.6.6", "hasInstallScript": true, "license": "MIT", "workspaces": [ @@ -6866,6 +6866,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, diff --git a/package.json b/package.json index 0319b1c93b..de486f9a89 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omniroute", - "version": "2.6.5", + "version": "2.6.6", "description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.", "type": "module", "bin": { diff --git a/src/app/(dashboard)/dashboard/media/MediaPageClient.tsx b/src/app/(dashboard)/dashboard/media/MediaPageClient.tsx index d3aa8e0a11..4229d85a75 100644 --- a/src/app/(dashboard)/dashboard/media/MediaPageClient.tsx +++ b/src/app/(dashboard)/dashboard/media/MediaPageClient.tsx @@ -81,29 +81,36 @@ const PROVIDER_MODELS: Record< { id: "openai/dall-e-2", name: "DALL-E 2" }, ], }, - { id: "xai", name: "xAI (Grok)", models: [{ id: "xai/grok-2-image", name: "Grok 2 Image" }] }, + { + id: "xai", + name: "xAI (Grok)", + models: [{ id: "xai/grok-2-image-1212", name: "Grok 2 Image" }], + }, { id: "together", name: "Together AI", models: [ - { id: "together/stable-diffusion-xl", name: "SDXL" }, - { id: "together/FLUX.1-schnell-Free", name: "FLUX.1 Schnell" }, + { id: "together/stabilityai/stable-diffusion-xl-base-1.0", name: "SDXL" }, + { id: "together/black-forest-labs/FLUX.1-schnell-Free", name: "FLUX.1 Schnell" }, ], }, { id: "fireworks", name: "Fireworks AI", models: [ - { id: "fireworks/stable-diffusion-xl-1024-v1-0", name: "SDXL 1024" }, - { id: "fireworks/flux-1-dev-fp8", name: "FLUX.1 Dev" }, + { + id: "fireworks/accounts/fireworks/models/stable-diffusion-xl-1024-v1-0", + name: "SDXL 1024", + }, + { id: "fireworks/accounts/fireworks/models/flux-1-dev-fp8", name: "FLUX.1 Dev" }, ], }, { id: "nebius", name: "Nebius AI", models: [ - { id: "nebius/flux-dev", name: "FLUX Dev" }, - { id: "nebius/sdxl", name: "SDXL" }, + { id: "nebius/black-forest-labs/flux-dev", name: "FLUX Dev" }, + { id: "nebius/black-forest-labs/flux-schnell", name: "FLUX Schnell" }, ], }, { @@ -117,7 +124,10 @@ const PROVIDER_MODELS: Record< { id: "nanobanana", name: "NanoBanana", - models: [{ id: "nanobanana/flux-schnell", name: "FLUX Schnell" }], + models: [ + { id: "nanobanana/nanobanana-flash", name: "NanoBanana Flash" }, + { id: "nanobanana/nanobanana-pro", name: "NanoBanana Pro" }, + ], }, { id: "sdwebui", diff --git a/src/app/api/db-backups/export/route.ts b/src/app/api/db-backups/export/route.ts index e18e2a8970..7a61310d8f 100644 --- a/src/app/api/db-backups/export/route.ts +++ b/src/app/api/db-backups/export/route.ts @@ -1,7 +1,7 @@ import { NextResponse } from "next/server"; -import path from "node:path"; -import fs from "node:fs"; -import os from "node:os"; +import path from "path"; +import fs from "fs"; +import os from "os"; import { getDbInstance, SQLITE_FILE } from "@/lib/db/core"; import { isAuthRequired, isAuthenticated } from "@/shared/utils/apiAuth"; diff --git a/src/app/api/db-backups/exportAll/route.ts b/src/app/api/db-backups/exportAll/route.ts index 7404938cbf..64fd705a82 100644 --- a/src/app/api/db-backups/exportAll/route.ts +++ b/src/app/api/db-backups/exportAll/route.ts @@ -1,8 +1,8 @@ import { NextResponse } from "next/server"; import { getDbInstance, SQLITE_FILE } from "@/lib/db/core"; -import fs from "node:fs"; -import path from "node:path"; -import os from "node:os"; +import fs from "fs"; +import path from "path"; +import os from "os"; /** * GET /api/db-backups/exportAll diff --git a/src/app/api/db-backups/import/route.ts b/src/app/api/db-backups/import/route.ts index 80c47035cb..a988b30f38 100644 --- a/src/app/api/db-backups/import/route.ts +++ b/src/app/api/db-backups/import/route.ts @@ -1,8 +1,8 @@ import { NextResponse } from "next/server"; import Database from "better-sqlite3"; -import path from "node:path"; -import fs from "node:fs"; -import os from "node:os"; +import path from "path"; +import fs from "fs"; +import os from "os"; import { getDbInstance, resetDbInstance, SQLITE_FILE } from "@/lib/db/core"; import { backupDbFile } from "@/lib/db/backup"; import { isAuthRequired, isAuthenticated } from "@/shared/utils/apiAuth"; diff --git a/src/app/api/oauth/[provider]/[action]/route.ts b/src/app/api/oauth/[provider]/[action]/route.ts index a1c140dd85..1d212e8983 100644 --- a/src/app/api/oauth/[provider]/[action]/route.ts +++ b/src/app/api/oauth/[provider]/[action]/route.ts @@ -1,5 +1,5 @@ import { NextResponse } from "next/server"; -import { timingSafeEqual } from "node:crypto"; +import { timingSafeEqual } from "crypto"; import { getProvider, generateAuthData, diff --git a/src/app/api/settings/route.ts b/src/app/api/settings/route.ts index 28dcdc66f0..1373d233bc 100644 --- a/src/app/api/settings/route.ts +++ b/src/app/api/settings/route.ts @@ -2,7 +2,7 @@ import { NextResponse } from "next/server"; import { getSettings, updateSettings } from "@/lib/localDb"; import { clearHealthCheckLogCache } from "@/lib/tokenHealthCheck"; import bcrypt from "bcryptjs"; -import { timingSafeEqual } from "node:crypto"; +import { timingSafeEqual } from "crypto"; import { getRuntimePorts } from "@/lib/runtime/ports"; import { updateSettingsSchema } from "@/shared/validation/settingsSchemas"; import { isValidationFailure, validateBody } from "@/shared/validation/helpers"; diff --git a/src/app/api/storage/health/route.ts b/src/app/api/storage/health/route.ts index f4848e60e3..ad8aaa56fd 100644 --- a/src/app/api/storage/health/route.ts +++ b/src/app/api/storage/health/route.ts @@ -1,6 +1,6 @@ import { NextResponse } from "next/server"; -import path from "node:path"; -import fs from "node:fs"; +import path from "path"; +import fs from "fs"; import { resolveDataDir } from "@/lib/dataPaths"; /** diff --git a/src/lib/apiBridgeServer.ts b/src/lib/apiBridgeServer.ts index 44e40591bb..e8b7782ff4 100644 --- a/src/lib/apiBridgeServer.ts +++ b/src/lib/apiBridgeServer.ts @@ -1,5 +1,5 @@ -import http from "node:http"; -import type { IncomingMessage, ServerResponse } from "node:http"; +import http from "http"; +import type { IncomingMessage, ServerResponse } from "http"; import { getRuntimePorts } from "@/lib/runtime/ports"; const DEFAULT_PROXY_TIMEOUT_MS = 30_000; diff --git a/src/lib/cacheLayer.ts b/src/lib/cacheLayer.ts index d56215052d..164a9d646c 100644 --- a/src/lib/cacheLayer.ts +++ b/src/lib/cacheLayer.ts @@ -8,7 +8,7 @@ * @module lib/cacheLayer */ -import crypto from "node:crypto"; +import crypto from "crypto"; /** * @typedef {Object} CacheEntry diff --git a/src/lib/dataPaths.ts b/src/lib/dataPaths.ts index 233caf77d7..60a6dc2835 100644 --- a/src/lib/dataPaths.ts +++ b/src/lib/dataPaths.ts @@ -1,5 +1,5 @@ -import path from "node:path"; -import os from "node:os"; +import path from "path"; +import os from "os"; export const APP_NAME = "omniroute"; diff --git a/src/lib/db/backup.ts b/src/lib/db/backup.ts index e699acdf0e..916b5acad1 100644 --- a/src/lib/db/backup.ts +++ b/src/lib/db/backup.ts @@ -3,8 +3,8 @@ */ import Database from "better-sqlite3"; -import path from "node:path"; -import fs from "node:fs"; +import path from "path"; +import fs from "fs"; import { getDbInstance, resetDbInstance, diff --git a/src/lib/db/core.ts b/src/lib/db/core.ts index 178ceade45..96b8ee10bc 100644 --- a/src/lib/db/core.ts +++ b/src/lib/db/core.ts @@ -5,8 +5,8 @@ */ import Database from "better-sqlite3"; -import path from "node:path"; -import fs from "node:fs"; +import path from "path"; +import fs from "fs"; import { resolveDataDir, getLegacyDotDataDir } from "../dataPaths"; import { runMigrations } from "./migrationRunner"; diff --git a/src/lib/db/migrationRunner.ts b/src/lib/db/migrationRunner.ts index b18a8e7047..473f28ea50 100644 --- a/src/lib/db/migrationRunner.ts +++ b/src/lib/db/migrationRunner.ts @@ -9,9 +9,9 @@ * All migrations run within a single transaction — all-or-nothing per file. */ -import fs from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; import type Database from "better-sqlite3"; /** diff --git a/src/lib/db/prompts.ts b/src/lib/db/prompts.ts index e62c56ad30..1b0e720e0c 100644 --- a/src/lib/db/prompts.ts +++ b/src/lib/db/prompts.ts @@ -9,7 +9,7 @@ * @module lib/db/prompts */ -import crypto from "node:crypto"; +import crypto from "crypto"; import { getDbInstance } from "./core"; interface StatementLike { diff --git a/src/lib/oauth/providers/kimi-coding.ts b/src/lib/oauth/providers/kimi-coding.ts index 6dd59aca0c..2d48abdbca 100644 --- a/src/lib/oauth/providers/kimi-coding.ts +++ b/src/lib/oauth/providers/kimi-coding.ts @@ -1,6 +1,6 @@ import { KIMI_CODING_CONFIG } from "../constants/oauth"; -import { randomUUID } from "node:crypto"; -import { hostname } from "node:os"; +import { randomUUID } from "crypto"; +import { hostname } from "os"; // Generate device ID (persistent per installation) const DEVICE_ID = randomUUID(); diff --git a/src/lib/semanticCache.ts b/src/lib/semanticCache.ts index 2eed057064..c8674e0caa 100644 --- a/src/lib/semanticCache.ts +++ b/src/lib/semanticCache.ts @@ -10,7 +10,7 @@ * @module lib/semanticCache */ -import crypto from "node:crypto"; +import crypto from "crypto"; import { LRUCache } from "./cacheLayer"; import { getDbInstance } from "./db/core"; diff --git a/src/shared/middleware/correlationId.ts b/src/shared/middleware/correlationId.ts index c5e8363e2c..9f30e0a2f8 100644 --- a/src/shared/middleware/correlationId.ts +++ b/src/shared/middleware/correlationId.ts @@ -9,7 +9,7 @@ */ import { AsyncLocalStorage } from "node:async_hooks"; -import crypto from "node:crypto"; +import crypto from "crypto"; const correlationStore = new AsyncLocalStorage(); diff --git a/src/shared/utils/requestId.ts b/src/shared/utils/requestId.ts index db99bbb619..3a30e401f7 100644 --- a/src/shared/utils/requestId.ts +++ b/src/shared/utils/requestId.ts @@ -10,9 +10,8 @@ * @module shared/utils/requestId */ - import { AsyncLocalStorage } from "node:async_hooks"; -import { randomUUID } from "node:crypto"; +import { randomUUID } from "crypto"; const requestIdStore = new AsyncLocalStorage(); @@ -66,10 +65,7 @@ export function addRequestIdHeader(headers = {}) { * @returns {Response} Response with request ID header */ export function attachRequestIdToResponse(request, response) { - const requestId = - getRequestId() || - request?.headers?.get?.("x-request-id") || - randomUUID(); + const requestId = getRequestId() || request?.headers?.get?.("x-request-id") || randomUUID(); const headers = new Headers(response.headers); headers.set("x-request-id", requestId);