mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-29 03:12:10 +03:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f96ee44213 | ||
|
|
bc53fe0cd9 | ||
|
|
97a67b5d3e |
19
CHANGELOG.md
19
CHANGELOG.md
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
---
|
||||
|
||||
## [2.0.4] — 2026-03-06
|
||||
|
||||
> ### 🐛 Bug Fixes — Round-Robin Persistence & Docker Compatibility
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **#218 — Round-robin sticks to one account** — Added `last_used_at` column to `provider_connections` schema. Round-robin routing relied on `lastUsedAt` to rotate between accounts, but the column was missing from the database — the value was always `null`, causing selection to fall back to the same account. Includes auto-migration for existing databases
|
||||
- **#217 — `Cannot find module 'zod'` in Docker/standalone builds** — Added `zod` to `serverExternalPackages` in `next.config.mjs`. Next.js standalone builds weren't tracing `zod` through dynamic imports, causing crashes on Docker startup. Data is **not lost** — the crash prevented the server from reading the existing database
|
||||
|
||||
### 📁 Files Changed
|
||||
|
||||
| File | Change |
|
||||
| ------------------------- | ------------------------------------------------------ |
|
||||
| `src/lib/db/core.ts` | Schema + migration + JSON migration for `last_used_at` |
|
||||
| `src/lib/db/providers.ts` | INSERT + UPDATE SQL for `last_used_at` |
|
||||
| `next.config.mjs` | `serverExternalPackages: ['better-sqlite3', 'zod']` |
|
||||
|
||||
---
|
||||
|
||||
## [2.0.3] — 2026-03-05
|
||||
|
||||
> ### 🐛 Bug Fixes & Quota System Hardening
|
||||
|
||||
@@ -6,7 +6,7 @@ const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
|
||||
const nextConfig = {
|
||||
turbopack: {},
|
||||
output: "standalone",
|
||||
serverExternalPackages: ["better-sqlite3"],
|
||||
serverExternalPackages: ["better-sqlite3", "zod"],
|
||||
transpilePackages: ["@omniroute/open-sse"],
|
||||
allowedDevOrigins: ["192.168.*"],
|
||||
typescript: {
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "2.0.1",
|
||||
"version": "2.0.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "omniroute",
|
||||
"version": "2.0.1",
|
||||
"version": "2.0.3",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"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": {
|
||||
|
||||
@@ -79,6 +79,7 @@ const SCHEMA_SQL = `
|
||||
token_type TEXT,
|
||||
consecutive_use_count INTEGER DEFAULT 0,
|
||||
rate_limit_protection INTEGER DEFAULT 0,
|
||||
last_used_at TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
@@ -311,6 +312,10 @@ function ensureProviderConnectionsColumns(db: SqliteDatabase) {
|
||||
);
|
||||
console.log("[DB] Added provider_connections.rate_limit_protection column");
|
||||
}
|
||||
if (!columnNames.has("last_used_at")) {
|
||||
db.exec("ALTER TABLE provider_connections ADD COLUMN last_used_at TEXT");
|
||||
console.log("[DB] Added provider_connections.last_used_at column");
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
console.warn("[DB] Failed to verify provider_connections schema:", message);
|
||||
@@ -483,7 +488,7 @@ function migrateFromJson(db: SqliteDatabase, jsonPath: string) {
|
||||
rate_limited_until, health_check_interval, last_health_check_at,
|
||||
last_tested, api_key, id_token, provider_specific_data,
|
||||
expires_in, display_name, global_priority, default_model,
|
||||
token_type, consecutive_use_count, rate_limit_protection, created_at, updated_at
|
||||
token_type, consecutive_use_count, rate_limit_protection, last_used_at, created_at, updated_at
|
||||
) VALUES (
|
||||
@id, @provider, @authType, @name, @email, @priority, @isActive,
|
||||
@accessToken, @refreshToken, @expiresAt, @tokenExpiresAt,
|
||||
@@ -492,7 +497,7 @@ function migrateFromJson(db: SqliteDatabase, jsonPath: string) {
|
||||
@rateLimitedUntil, @healthCheckInterval, @lastHealthCheckAt,
|
||||
@lastTested, @apiKey, @idToken, @providerSpecificData,
|
||||
@expiresIn, @displayName, @globalPriority, @defaultModel,
|
||||
@tokenType, @consecutiveUseCount, @rateLimitProtection, @createdAt, @updatedAt
|
||||
@tokenType, @consecutiveUseCount, @rateLimitProtection, @lastUsedAt, @createdAt, @updatedAt
|
||||
)
|
||||
`);
|
||||
|
||||
@@ -533,6 +538,7 @@ function migrateFromJson(db: SqliteDatabase, jsonPath: string) {
|
||||
defaultModel: conn.defaultModel || null,
|
||||
tokenType: conn.tokenType || null,
|
||||
consecutiveUseCount: conn.consecutiveUseCount || 0,
|
||||
lastUsedAt: conn.lastUsedAt || null,
|
||||
rateLimitProtection:
|
||||
conn.rateLimitProtection === true || conn.rateLimitProtection === 1 ? 1 : 0,
|
||||
createdAt: conn.createdAt || new Date().toISOString(),
|
||||
|
||||
@@ -217,7 +217,7 @@ function _insertConnectionRow(db: DbLike, conn: JsonRecord) {
|
||||
rate_limited_until, health_check_interval, last_health_check_at,
|
||||
last_tested, api_key, id_token, provider_specific_data,
|
||||
expires_in, display_name, global_priority, default_model,
|
||||
token_type, consecutive_use_count, rate_limit_protection, created_at, updated_at
|
||||
token_type, consecutive_use_count, rate_limit_protection, last_used_at, created_at, updated_at
|
||||
) VALUES (
|
||||
@id, @provider, @authType, @name, @email, @priority, @isActive,
|
||||
@accessToken, @refreshToken, @expiresAt, @tokenExpiresAt,
|
||||
@@ -226,7 +226,7 @@ function _insertConnectionRow(db: DbLike, conn: JsonRecord) {
|
||||
@rateLimitedUntil, @healthCheckInterval, @lastHealthCheckAt,
|
||||
@lastTested, @apiKey, @idToken, @providerSpecificData,
|
||||
@expiresIn, @displayName, @globalPriority, @defaultModel,
|
||||
@tokenType, @consecutiveUseCount, @rateLimitProtection, @createdAt, @updatedAt
|
||||
@tokenType, @consecutiveUseCount, @rateLimitProtection, @lastUsedAt, @createdAt, @updatedAt
|
||||
)
|
||||
`
|
||||
).run({
|
||||
@@ -267,6 +267,7 @@ function _insertConnectionRow(db: DbLike, conn: JsonRecord) {
|
||||
consecutiveUseCount: conn.consecutiveUseCount || 0,
|
||||
rateLimitProtection:
|
||||
conn.rateLimitProtection === true || conn.rateLimitProtection === 1 ? 1 : 0,
|
||||
lastUsedAt: conn.lastUsedAt || null,
|
||||
createdAt: conn.createdAt,
|
||||
updatedAt: conn.updatedAt,
|
||||
});
|
||||
@@ -290,6 +291,7 @@ function _updateConnectionRow(db: DbLike, id: string, data: JsonRecord) {
|
||||
default_model = @defaultModel, token_type = @tokenType,
|
||||
consecutive_use_count = @consecutiveUseCount,
|
||||
rate_limit_protection = @rateLimitProtection,
|
||||
last_used_at = @lastUsedAt,
|
||||
updated_at = @updatedAt
|
||||
WHERE id = @id
|
||||
`
|
||||
@@ -331,6 +333,7 @@ function _updateConnectionRow(db: DbLike, id: string, data: JsonRecord) {
|
||||
consecutiveUseCount: data.consecutiveUseCount || 0,
|
||||
rateLimitProtection:
|
||||
data.rateLimitProtection === true || data.rateLimitProtection === 1 ? 1 : 0,
|
||||
lastUsedAt: data.lastUsedAt || null,
|
||||
updatedAt: now,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user