Merge remote-tracking branch 'origin/release/v3.8.51' into fix/trivy-cve-2025-68121-tls-client

This commit is contained in:
diegosouzapw
2026-08-30 03:39:26 -03:00
306 changed files with 1479 additions and 3370 deletions

View File

@@ -289,8 +289,7 @@ When creating _any_ validation tests or one-off logic scripts, default to `scrip
### Database
- **Always** go through `src/lib/db/` domain modules — **never** write raw SQL in routes or handlers
- **Never** add logic to `src/lib/localDb.ts` (re-export layer only)
- **Never** barrel-import from `localDb.ts` — import specific `db/` modules instead
- **Never** barrel-import from `localDb.ts` — import specific `src/lib/db/*` modules
- DB singleton: `getDbInstance()` from `src/lib/db/core.ts` (WAL journaling)
- Migrations: `src/lib/db/migrations/` — versioned SQL files, idempotent, run in transactions
@@ -355,8 +354,7 @@ Documentation must describe verified behavior, not plausible behavior.
1. Create `src/lib/db/yourModule.ts` — import `getDbInstance` from `./core.ts`
2. Export CRUD functions for your domain table(s)
3. Add migration in `src/lib/db/migrations/` if new tables needed
4. Re-export from `src/lib/localDb.ts` (add to the re-export list only)
5. Write tests
4. Write tests
### Adding a New MCP Tool
@@ -668,7 +666,7 @@ the stale-enforcement added in Fase 6A.3.
## Hard Rules
1. Never commit secrets or credentials
2. Never add logic to `localDb.ts`
2. Never barrel-import from `localDb.ts` — import specific `src/lib/db/*` modules
3. Never use `eval()` / `new Function()` / implied eval
4. Never commit directly to `main`
5. Never write raw SQL in routes — use `src/lib/db/` modules

View File

@@ -0,0 +1 @@
- **fix(build):** `prepublish.ts` bundles the ChatGPT Web (Codex) MCP bridge through `runBuildTool()` instead of spawning `npx.cmd` raw, fixing the build crash on Node ≥ 20/Windows where `.cmd` shims cannot be spawned without a shell (EINVAL) ([#11704](https://github.com/diegosouzapw/OmniRoute/issues/11704))

File diff suppressed because it is too large Load Diff

View File

@@ -514,7 +514,7 @@ For the full stealth playbook and operational guidance, see
Primary state DB (SQLite):
- Core infra: `src/lib/db/core.ts` (better-sqlite3, migrations, WAL)
- Re-export facade: `src/lib/localDb.ts` (thin compatibility layer for callers)
- DB access: import specific `src/lib/db/*` modules directly (the old `localDb.ts` barrel was removed)
- file: `${DATA_DIR}/storage.sqlite` (or `$XDG_CONFIG_HOME/omniroute/storage.sqlite` when set, else `~/.omniroute/storage.sqlite`)
- entities (tables + KV namespaces): providerConnections, providerNodes, modelAliases, combos, apiKeys, settings, pricing, **customModels**, **proxyConfig**, **ipFilter**, **thinkingBudget**, **systemPrompt**
@@ -888,7 +888,7 @@ flowchart LR
### Persistence
- `src/lib/db/*`: persistent config/state and domain persistence on SQLite
- `src/lib/localDb.ts`: compatibility re-export for DB modules
- `src/lib/db/*`: import specific modules directly — no barrel (the old `localDb.ts` re-export layer was removed)
- `src/lib/usageDb.ts`: usage history/call logs facade on top of SQLite tables
## Provider Executor Coverage (Strategy Pattern)

View File

@@ -313,7 +313,7 @@ table groups the actual directories and notable top-level files.
Top-level files in `src/lib/`:
- `localDb.ts` — re-export layer only. **Never** add logic here.
- The old `localDb.ts` barrel was removed — consumers import specific `src/lib/db/*` modules directly.
- `proxyHealth.ts`, `proxyLogger.ts`, `tokenHealthCheck.ts`, `localHealthCheck.ts`
- `oneproxyRotator.ts`, `oneproxySync.ts`
- `apiBridgeServer.ts`, `cacheLayer.ts`, `semanticCache.ts`, `settingsCache.ts`
@@ -759,7 +759,7 @@ See [RESILIENCE_GUIDE.md](./RESILIENCE_GUIDE.md) and the dedicated section in
2. Export CRUD functions for your domain.
3. If new tables: add a migration under `src/lib/db/migrations/`, numbered
sequentially, idempotent, transactional.
4. Re-export from `src/lib/localDb.ts` (re-export only — **no logic**).
4. Importers use direct imports from `@/lib/db/yourModule` (no barrel — the old `localDb.ts` re-export layer was removed).
5. Add tests under `tests/unit/`.
### Add a new MCP tool
@@ -790,7 +790,7 @@ See [A2A-SERVER.md § Adding a New Skill](../frameworks/A2A-SERVER.md). Skills l
- **TypeScript**: `strict: false` (legacy posture). Prefer explicit types over
inference for cross-module boundaries.
- **Database**: never write raw SQL in routes or handlers — always go through
`src/lib/db/` modules. Never add logic to `src/lib/localDb.ts`.
`src/lib/db/` modules. Never barrel-import — use specific `src/lib/db/*` modules directly.
- **DB-entity typing (#3512)**: a function that writes or reads a DB table's
row shape should take/return a named TS interface mirroring that table's
columns 1:1, not `any` or an inline anonymous type at the call site. Land
@@ -824,7 +824,7 @@ See [A2A-SERVER.md § Adding a New Skill](../frameworks/A2A-SERVER.md). Skills l
## 12. Hard Rules (from CLAUDE.md)
1. Never commit secrets or credentials.
2. Never add logic to `src/lib/localDb.ts`.
2. Never barrel-import — use specific `src/lib/db/*` modules directly.
3. Never use `eval()` / `new Function()` / implied eval.
4. Never commit directly to `main`.
5. Never write raw SQL in routes — always go through `src/lib/db/` modules.

View File

@@ -158,7 +158,7 @@ status. CI performs the broader package artifact and ecosystem checks.
**Contracts**
- Domain modules under `src/lib/db/`; `src/lib/localDb.ts` remains a re-export layer only.
- Domain modules under `src/lib/db/`; import specific modules directly (the old `localDb.ts` re-export layer was removed).
- Numbered, idempotent SQL migrations under `src/lib/db/migrations/`, transaction safety, upgrade
behavior, indexes, and every caller affected by the schema.
- Routes and handlers never issue raw SQL directly.

View File

@@ -329,11 +329,12 @@ const nextConfig = {
// TODO: Re-enable after fixing all sub-component useTranslations scope issues
ignoreBuildErrors: true,
},
webpack(config, { webpack }) {
webpack(config, { dev, webpack }) {
config.ignoreWarnings = [
...(config.ignoreWarnings || []),
isNextIntlExtractorDynamicImportWarning,
];
const nextDefaultSplitChunks = config.optimization?.splitChunks;
config.optimization = config.optimization || {};
config.optimization.splitChunks = {
...config.optimization.splitChunks,
@@ -392,6 +393,9 @@ const nextConfig = {
},
},
};
// Next's development defaults are tuned for incremental route compilation.
// Retain the custom vendor topology for production without imposing it on dev.
if (dev) config.optimization.splitChunks = nextDefaultSplitChunks;
if (isMinimalBuild) {
// Mirror the turbopack.resolveAlias entries for webpack-built artifacts.

View File

@@ -1427,7 +1427,7 @@ export async function handleChatCore({
};
if ((isCombo && comboName) || routingComboId) {
try {
const { getComboByName } = await import("../../src/lib/localDb");
const { getComboByName } = await import("@/lib/db/combos");
let comboConfig = await getComboByName(comboName);
if (!comboConfig && comboName?.startsWith("combo/")) {
comboConfig = await getComboByName(comboName.substring(6));
@@ -1918,7 +1918,7 @@ export async function handleChatCore({
if (isCombo && comboName) {
log?.info?.("CONTEXT", `Attempting to resolve combo limits for comboName=${comboName}`);
try {
const { getComboByName } = await import("../../src/lib/localDb");
const { getComboByName } = await import("@/lib/db/combos");
const { resolveComboTargets } = await import("../services/combo.ts");
let comboConfig = await getComboByName(comboName);
if (!comboConfig && comboName.startsWith("combo/")) {
@@ -4292,13 +4292,14 @@ export async function handleChatCore({
let quotaCooldownMs = kimiRateLimitResetAt
? Math.max(new Date(kimiRateLimitResetAt).getTime() - Date.now(), 0)
: retryAfterMs || COOLDOWN_MS.rateLimit;
const deferAntigravityQuotaStateToCaller =
shouldDeferAntigravityQuotaStateToCaller(
provider,
typeof onStreamFailure === "function"
);
const isAntigravityQuotaFamily =
shouldDeferAntigravityQuotaStateToCaller(provider, true);
const deferAntigravityQuotaStateToCaller = shouldDeferAntigravityQuotaStateToCaller(
provider,
typeof onStreamFailure === "function"
);
const isAntigravityQuotaFamily = shouldDeferAntigravityQuotaStateToCaller(
provider,
true
);
let coreOwnedAntigravityLockout: {
cooldownMs: number;
failureCount: number;

View File

@@ -1,5 +1,4 @@
import { getUpstreamProxyConfig } from "@/lib/localDb";
import type { FallbackBackend } from "@/lib/db/upstreamProxy";
import { FallbackBackend, getUpstreamProxyConfig } from "@/lib/db/upstreamProxy";
/**
* Module-level cache for upstream proxy config (shared across all requests).
@@ -29,7 +28,8 @@ const COMBOS_CACHE_TTL = 10_000;
export async function getCombosCached(): Promise<unknown[]> {
const now = Date.now();
const { getCombos, getCombosCacheVersion } = await import("@/lib/localDb");
const { getCombos } = await import("@/lib/db/combos");
const { getCombosCacheVersion } = await import("@/lib/db/readCache");
const version = getCombosCacheVersion();
// A combo write (create/update/delete/reorder) bumps the shared version via
// invalidateDbCache("combos"); when it no longer matches our snapshot we drop

View File

@@ -265,7 +265,15 @@ export function translateNonStreamingResponse(
if (toolCalls.length > 0) {
message.tool_calls = toolCalls;
}
if (message.content === undefined) {
if (
(!message.content ||
(typeof message.content === "string" && message.content.trim().length === 0)) &&
toolCalls.length === 0 &&
replayableReasoningContent &&
replayableReasoningContent.trim().length > 0
) {
message.content = replayableReasoningContent;
} else if (message.content === undefined) {
message.content = "";
}

View File

@@ -90,7 +90,7 @@ import {
clampMcpAccessibilityConfig,
type McpAccessibilityConfig,
} from "../services/compression/engines/mcpAccessibility/constants.ts";
import { getDbInstance } from "../../src/lib/db/core.ts";
import { getDbInstance, ensureDbInitialized } from "../../src/lib/db/core.ts";
import { normalizeQuotaResponse } from "../../src/shared/contracts/quota.ts";
import { resolveOmniRouteBaseUrl } from "../../src/shared/utils/resolveOmniRouteBaseUrl.ts";
import { sanitizeErrorMessage } from "../utils/error.ts";
@@ -1527,10 +1527,10 @@ export function createMcpServer(options?: CreateMcpServerOptions): McpServer {
* Called when `omniroute --mcp` is used.
*/
export async function startMcpStdio(): Promise<void> {
await ensureDbInitialized();
// Stdout is reserved for JSON-RPC — bin/mcpStdioConsoleGuard.mjs is preloaded via
// `node --import` (see bin/mcp-server.mjs) so console.log/warn already redirect to
// stderr before this module's own imports evaluate (DB init happens as a side effect of
// createMcpServer()'s tool registration, earlier than any code placed here could catch).
// stderr before this module's own imports evaluate.
const server = createMcpServer();
const transport = new StdioServerTransport();
const version = process.env.npm_package_version || "1.8.1";

View File

@@ -3,7 +3,7 @@ import { describe, it, expect, vi } from "vitest";
// Mock the DB so recommendStrategyOverride sees adaptiveVolumeRouting = true.
// Without this the real getSettings() throws (no SQLite in test env), the
// catch block fires, and the function returns noOverride before any rule runs.
vi.mock("@/lib/localDb", () => ({
vi.mock("@/lib/db/settings", () => ({
getSettings: vi.fn().mockResolvedValue({ adaptiveVolumeRouting: true }),
}));

View File

@@ -1,22 +1,20 @@
import { v4 as uuidv4 } from "uuid";
import type { BatchItemCheckpoint, BatchRecord } from "@/lib/localDb";
import {
type BatchItemCheckpoint,
type BatchRecord,
countBatchItemCheckpoints,
createFile,
deleteFile,
ensureBatchItemCheckpoints,
getApiKeyById,
getBatch,
getFileContent,
getPendingBatches,
getTerminalBatches,
listBatchItemCheckpoints,
listFiles,
markBatchItemError,
markBatchItemProcessing,
markBatchItemResult,
updateBatch,
} from "@/lib/localDb";
} from "@/lib/db/batches";
import { createFile, deleteFile, getFileContent, listFiles } from "@/lib/db/files";
import { getApiKeyById } from "@/lib/db/apiKeys";
import { dispatch } from "@/lib/batches/dispatch";
import type { SupportedBatchEndpoint } from "@/shared/constants/batchEndpoints";
import { DEFAULT_BATCH_EXPIRATION_SECONDS } from "@/shared/constants/batch";

View File

@@ -370,7 +370,7 @@ export function clearStaleLKGP(
): void {
void (async () => {
try {
const { clearLKGP } = await import("@/lib/localDb");
const { clearLKGP } = await import("@/lib/db/settings");
const promises: Promise<void>[] = [clearLKGP(comboName, comboId || comboName)];
if (executionKey) {
promises.push(clearLKGP(comboName, executionKey));
@@ -427,7 +427,7 @@ export async function buildAutoCandidates(
// apply, so auto-routing behavior is unchanged.
const quotaCutoffEnabled =
(resilienceSettings ?? resolveResilienceSettings(null))?.quotaPreflight?.enabled === true;
const { getPricingForModel } = await import("../../src/lib/localDb");
const { getPricingForModel } = await import("@/lib/db/settings");
const quotaPromises = new Map<string, Promise<unknown>>();
let historicalLatencyStats: Record<string, HistoricalLatencyStatsEntry> = {};
try {
@@ -1640,7 +1640,8 @@ async function handleComboChatInner({
lastModel,
modelStr,
`Model routing: ${lastModel}${modelStr}`,
existingHandoff
existingHandoff,
universalHandoffConfig.relayMode
);
}
}
@@ -1969,7 +1970,7 @@ async function handleComboChatInner({
const connId = effectiveConnectionId || undefined;
void (async () => {
try {
const { setLKGP } = await import("../../src/lib/localDb");
const { setLKGP } = await import("@/lib/db/settings");
await Promise.all([
setLKGP(combo.name, target.executionKey, provider, connId),
setLKGP(combo.name, combo.id || combo.name, provider, connId),
@@ -3566,7 +3567,7 @@ async function handleRoundRobinCombo({
const connId = effectiveConnectionId || undefined;
void (async () => {
try {
const { setLKGP } = await import("../../src/lib/localDb");
const { setLKGP } = await import("@/lib/db/settings");
await Promise.all([
setLKGP(combo.name, target.executionKey, provider, connId),
setLKGP(combo.name, combo.id || combo.name, provider, connId),

View File

@@ -67,7 +67,7 @@ export async function applyStrategyOrdering(
if (strategy === "lkgp") {
try {
const { getLKGP } = await import("../../../src/lib/localDb");
const { getLKGP } = await import("@/lib/db/settings");
const lkgpProvider = await getLKGP(combo.name, combo.id || combo.name);
if (lkgpProvider) {

View File

@@ -19,7 +19,7 @@
* shrinking (Quality Gate / #3501).
*/
import { getCachedProviderConnectionById } from "@/lib/localDb";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import { effectiveMaxConcurrency } from "./comboPredicates.ts";
import type { ResolvedComboTarget } from "./types.ts";

View File

@@ -19,7 +19,7 @@ import {
type PreflightQuotaThresholds,
type QuotaInfo,
} from "../quotaPreflight.ts";
import { getCachedProviderConnectionById } from "@/lib/localDb";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import {
resolveResilienceSettings,
type ResilienceSettings,
@@ -109,8 +109,7 @@ export async function resolveQuotaExhaustionCutoffForTarget(
let connection: Record<string, unknown> | undefined;
try {
connection = (await getCachedProviderConnectionById(connectionId)) as
| Record<string, unknown>
| undefined;
Record<string, unknown> | undefined;
} catch {
connection = undefined;
}

View File

@@ -245,7 +245,7 @@ export async function resolveAutoStrategyOrder(
let lastKnownGoodProvider: string | undefined;
try {
const { getLKGP } = await import("../../../src/lib/localDb");
const { getLKGP } = await import("@/lib/db/settings");
const lkgp = await getLKGP(combo.name, combo.id || combo.name);
if (lkgp) lastKnownGoodProvider = lkgp.provider;
} catch (err) {

View File

@@ -65,7 +65,7 @@ export function orderTargetsForWeightedFallback<T extends { executionKey: string
*/
export async function sortModelsByCost(models: string[]): Promise<string[]> {
try {
const { getPricingForModel } = await import("../../../src/lib/localDb");
const { getPricingForModel } = await import("@/lib/db/settings");
const withCost = await Promise.all(
models.map(async (modelStr) => {
const parsed = parseModel(modelStr);

View File

@@ -48,6 +48,7 @@ export interface ContextRelayConfig {
handoffThreshold?: number;
handoffProviders?: string[];
maxMessagesForSummary?: number;
relayMode?: "schema-locked" | "standard";
}
export interface UniversalHandoffConfig {
@@ -65,6 +66,7 @@ export interface UniversalHandoffConfig {
ttlMinutes: number;
/** Preserve existing system prompt when injecting handoff */
preserveSystemPrompt: boolean;
relayMode?: "schema-locked" | "standard";
}
export const DEFAULT_UNIVERSAL_HANDOFF_CONFIG: UniversalHandoffConfig = {
@@ -155,6 +157,8 @@ export function resolveUniversalHandoffConfig(
"preserveSystemPrompt",
DEFAULT_UNIVERSAL_HANDOFF_CONFIG.preserveSystemPrompt
),
relayMode:
getString("relayMode", "standard") === "schema-locked" ? "schema-locked" : "standard",
};
}
export interface ParsedHandoffContent {
@@ -192,6 +196,7 @@ export function resolveContextRelayConfig(
Number.isFinite(rawMaxMessages) && rawMaxMessages >= 5 && rawMaxMessages <= 100
? Math.round(rawMaxMessages)
: DEFAULT_MAX_MESSAGES_FOR_SUMMARY,
relayMode: config?.relayMode === "schema-locked" ? "schema-locked" : "standard",
};
}
@@ -232,7 +237,8 @@ function formatMessagesForPrompt(messages: MessageLike[]): string {
export function selectMessagesForSummary(
messages: MessageLike[],
maxMessages: number
maxMessages: number,
relayMode?: "schema-locked" | "standard"
): MessageLike[] {
const validMessages = messages.filter((m) => m && typeof m === "object");
const system = validMessages.filter(
@@ -242,15 +248,23 @@ export function selectMessagesForSummary(
(m) => typeof m.role !== "string" || (m.role !== "system" && m.role !== "developer")
);
const recentMessages = [...system, ...nonSystem.slice(-maxMessages)];
const recentMessages =
relayMode === "schema-locked"
? [...nonSystem.slice(-maxMessages)]
: [...system, ...nonSystem.slice(-maxMessages)];
let working = [...recentMessages];
while (working.length > system.length + 1) {
const minWorkingLength = relayMode === "schema-locked" ? 1 : system.length + 1;
while (working.length > minWorkingLength) {
const history = formatMessagesForPrompt(working);
if (estimateTokens(history) <= MAX_HISTORY_TOKENS_FOR_SUMMARY) {
return working;
}
working = [...system, ...working.slice(system.length + 1)];
working =
relayMode === "schema-locked"
? working.slice(1)
: [...system, ...working.slice(system.length + 1)];
}
const fallbackHistory = formatMessagesForPrompt(working);
@@ -258,7 +272,7 @@ export function selectMessagesForSummary(
// If there are system messages, return them so the caller can still produce context.
// If there are no system messages (system=[]), fall back to the single most-recent
// non-system message rather than returning [] which would silently drop the handoff.
if (system.length > 0) {
if (relayMode !== "schema-locked" && system.length > 0) {
return system;
}
const lastNonSystem = nonSystem[nonSystem.length - 1];
@@ -386,7 +400,8 @@ async function generateHandoffAsync(options: {
const summaryModel = relayConfig.handoffModel || options.model;
const selectedMessages = selectMessagesForSummary(
Array.isArray(options.messages) ? options.messages : [],
relayConfig.maxMessagesForSummary
relayConfig.maxMessagesForSummary,
relayConfig.relayMode
);
const historyText = formatMessagesForPrompt(selectedMessages);
if (!historyText) return;
@@ -499,7 +514,8 @@ The context above contains a concise summary of the prior work. Continue seamles
export function injectHandoffIntoBody(
body: Record<string, unknown>,
payload: HandoffPayload
payload: HandoffPayload,
_relayMode?: "schema-locked" | "standard"
): Record<string, unknown> {
const handoffContent = buildHandoffSystemMessage(payload);
const isResponsesRequest =
@@ -680,12 +696,14 @@ async function generateUniversalHandoffAsync(options: {
handoffModel: string;
ttlMs: number;
maxMessages: number;
relayMode?: "schema-locked" | "standard";
providerAllowlist: string[];
handleSingleModel: (body: Record<string, unknown>, modelStr: string) => Promise<Response>;
}): Promise<UniversalHandoffOutcome> {
const selectedMessages = selectMessagesForSummary(
Array.isArray(options.messages) ? options.messages : [],
options.maxMessages
options.maxMessages,
options.relayMode
);
const historyText = formatMessagesForPrompt(selectedMessages);
if (!historyText) return "unavailable";
@@ -789,6 +807,7 @@ export function maybeGenerateUniversalHandoff(options: {
handoffModel: options.universalConfig.handoffModel || options.currModel,
ttlMs,
maxMessages: options.universalConfig.maxMessagesForSummary,
relayMode: options.universalConfig.relayMode,
providerAllowlist: options.universalConfig.providerAllowlist,
handleSingleModel: options.handleSingleModel,
})
@@ -812,7 +831,8 @@ export function injectUniversalHandoffBody(
prevModel: string,
currModel: string,
reason: string,
existingPayload?: HandoffPayload | null
existingPayload?: HandoffPayload | null,
_relayMode?: "schema-locked" | "standard"
): Record<string, unknown> {
const handoffContent = buildUniversalHandoffSystemMessage(
prevModel,

View File

@@ -12,7 +12,7 @@
* - Provider-specific rules: "openai/gpt-4"
*/
import { checkKeyModelAccess, getKeyGroupsForApiKey } from "@/lib/localDb";
import { checkKeyModelAccess, getKeyGroupsForApiKey } from "@/lib/db/apiKeyGroups";
export interface KeyGroupAuthResult {
/** Whether the request is authorized */

View File

@@ -332,7 +332,7 @@ function getProviderIdFromConnection(connection: unknown) {
async function getActiveProviderSet() {
try {
const { getCachedProviderConnections } = await import("@/lib/localDb");
const { getCachedProviderConnections } = await import("@/lib/db/readCache");
const conns = (await getCachedProviderConnections()) as unknown[];
const providers = conns
.map(getProviderIdFromConnection)
@@ -345,7 +345,7 @@ async function getActiveProviderSet() {
async function getActiveSyncedProvidersForModel(modelId: string) {
try {
const { getActiveProvidersWithSyncedModel } = await import("@/lib/localDb");
const { getActiveProvidersWithSyncedModel } = await import("@/lib/db/models");
const providers = await getActiveProvidersWithSyncedModel(modelId);
return providers
.map(resolveProviderAlias)
@@ -403,7 +403,7 @@ function isTruthyEnv(value: string | undefined) {
async function getPreferClaudeCodeForUnprefixedClaudeModels() {
try {
const { getCachedSettings } = await import("@/lib/localDb");
const { getCachedSettings } = await import("@/lib/db/readCache");
const settings = (await getCachedSettings()) as Record<string, unknown>;
if (typeof settings.preferClaudeCodeForUnprefixedClaudeModels === "boolean") {
return settings.preferClaudeCodeForUnprefixedClaudeModels;

View File

@@ -223,7 +223,7 @@ export function clearPayloadRulesConfigOverride() {
// silently reverting to the (usually empty) file config.
async function loadPayloadRulesFromSettings(): Promise<PayloadRulesConfig | null> {
try {
const { getCachedSettings } = await import("@/lib/localDb");
const { getCachedSettings } = await import("@/lib/db/readCache");
const settings = (await getCachedSettings()) as { payloadRules?: unknown };
const raw = settings?.payloadRules;
if (raw === null || raw === undefined) return null;

View File

@@ -338,7 +338,8 @@ export async function initializeRateLimits() {
applyBottleneckHeartbeatPatch();
try {
const { getCachedProviderConnections, getSettings } = await import("@/lib/localDb");
const { getCachedProviderConnections } = await import("@/lib/db/readCache");
const { getSettings } = await import("@/lib/db/settings");
const [connections, settings] = await Promise.all([
getCachedProviderConnections(),
getSettings(),
@@ -385,7 +386,7 @@ export async function applyRequestQueueSettings(nextSettings: RequestQueueSettin
currentRequestQueueSettings = { ...nextSettings };
// Global policy changes invalidate snapshots from the previous generation.
preservedReplacementSettings.clear();
const { getCachedProviderConnections } = await import("@/lib/localDb");
const { getCachedProviderConnections } = await import("@/lib/db/readCache");
const connections = await getCachedProviderConnections();
// Also discard any snapshot created while the asynchronous DB read yielded.
preservedReplacementSettings.clear();

View File

@@ -20,7 +20,7 @@ import {
getTokenLimitsForRequest,
logTokenLimitReset,
type TokenLimit,
} from "@/lib/localDb";
} from "@/lib/db/tokenLimits";
interface CacheEntry {
windowStart: string;
@@ -295,8 +295,7 @@ export function recordTokenUsage(
ORDER BY window_start DESC LIMIT 1`
)
.get(limit.id, windowStart) as
| { window_start?: string; tokens_used?: number }
| undefined;
{ window_start?: string; tokens_used?: number } | undefined;
const prevTokens =
priorRow && typeof priorRow.tokens_used === "number" ? priorRow.tokens_used : 0;
if (prevTokens > 0) {

View File

@@ -155,7 +155,7 @@ export async function recommendStrategyOverride(
// Check if adaptive routing is enabled globally
try {
const { getSettings } = await import("@/lib/localDb");
const { getSettings } = await import("@/lib/db/settings");
const settings = await getSettings();
if (!settings.adaptiveVolumeRouting) {
return noOverride;

View File

@@ -20,7 +20,7 @@ async function getConfig() {
if (_cachedConfig && now < _cacheExpiry) return _cachedConfig;
try {
const { getProxyConfig } = await import("../../src/lib/localDb");
const { getProxyConfig } = await import("@/lib/db/settings");
_cachedConfig = await getProxyConfig();
_cacheExpiry = now + 30_000; // Cache for 30s
return _cachedConfig;

View File

@@ -10,7 +10,8 @@
import { fetch as undiciFetch } from "undici";
import { createProxyDispatcher, normalizeProxyUrl } from "./proxyDispatcher.ts";
import { resolveProxyForScopeFromRegistry, listProxies, listOneproxyProxies } from "@/lib/localDb";
import { resolveProxyForScopeFromRegistry, listProxies } from "@/lib/db/proxies";
import { listOneproxyProxies } from "@/lib/db/oneproxy";
import { isFeatureFlagEnabled } from "@/shared/utils/featureFlags";
// ---------------------------------------------------------------------------

View File

@@ -328,10 +328,10 @@ const chatGptWebCodexMcpDestFile = join(
if (existsSync(chatGptWebCodexMcpSrcFile)) {
console.log(" 🔨 Bundling ChatGPT Web (Codex) MCP bridge...");
mkdirSync(dirname(chatGptWebCodexMcpDestFile), { recursive: true });
execFileSync(
NPX_BIN,
runBuildTool(
"esbuild",
"esbuild",
[
"esbuild",
"open-sse/vendor/codex-chatgpt-web/adapters/chatgpt-web/mcp-server.ts",
"--bundle",
"--platform=node",

View File

@@ -1,89 +1,24 @@
#!/usr/bin/env node
// scripts/check/check-db-rules.mjs
// Gate de convenções de banco (CLAUDE.md Hard Rules #2 e #5). Três verificações:
// (a) Todo módulo de domínio em src/lib/db/*.ts deve ser re-exportado por
// src/lib/localDb.ts (camada de compat). Um módulo db NOVO que não é
// re-exportado (e não está congelado) falha — força a decisão consciente
// de expor ou justificar (Hard Rule #2).
// (b) src/lib/localDb.ts é APENAS camada de re-export: nada de lógica
// (function/class/arrow de negócio). Mata o anti-padrão de "só uma
// funçãozinha aqui" que vira regra de negócio fora dos módulos db/.
// Gate de convenções de banco (CLAUDE.md Hard Rules #2 e #5). Uma verificação:
// (c) Nenhum SQL cru em src/app/api/**/route.ts ou open-sse/handlers/*.ts.
// SQL deve viver em src/lib/db/ (Hard Rule #5). Ofensores pré-existentes
// são congelados; QUALQUER novo SQL cru em rota/handler falha.
// Stale-enforcement (6A.3): entradas em INTENTIONALLY_INTERNAL / EXTERNAL_DB_ALLOWED
// que não suprimem nenhuma violação real → gate falha com instrução de remoção.
// As antigas verificações (a) re-export completo via src/lib/localDb.ts e
// (b) localDb.ts sem lógica foram REMOVIDAS: o barrel src/lib/localDb.ts foi
// deletado (#11795) — consumidores importam módulos src/lib/db/* diretamente
// (regra "never barrel-import", aplicada por eslint no-restricted-imports).
// Stale-enforcement (6A.3): entradas em EXTERNAL_DB_ALLOWED que não suprimem
// nenhuma violação real → gate falha com instrução de remoção.
import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { assertNoStale } from "./lib/allowlist.mjs";
const cwd = process.cwd();
const DB_DIR = path.join(cwd, "src/lib/db");
const LOCAL_DB = path.join(cwd, "src/lib/localDb.ts");
const API_DIR = path.join(cwd, "src/app/api");
const HANDLERS_DIR = path.join(cwd, "open-sse/handlers");
// (a) Módulos db/ que NÃO são re-exportados por localDb.ts por DESIGN (Hard Rule #2:
// "Never barrel-import from localDb.ts — import specific db/ modules instead").
// Cada entrada aqui foi auditada e é consumida via import direto de "@/lib/db/X"
// (estático ou dinâmico) pelos seus consumidores — exatamente o padrão correto.
// Re-exportar esses módulos via localDb.ts INCENTIVARIA o anti-padrão proibido.
// O gate ainda bloqueia QUALQUER módulo db/ NOVO que não seja re-exportado E não
// esteja nessa lista — mantendo a decisão consciente obrigatória (Hard Rule #2).
// Legenda de classificação:
// type-only = exporta apenas tipos (sem runtime API), não há o que re-exportar
// db-internal = importado apenas dentro de src/lib/db/ (coordenação interna)
// intentionally-internal = consumido por import direto fora de db/ (correto per Rule #2)
// DEAD? = zero importers encontrados na auditoria de 2026-06-11; não deletar
// sem investigação — pode ser reserva de schema ou F2 pendente
export const INTENTIONALLY_INTERNAL = new Set([
"_rowTypes", // type-only: 5 importers internos em db/ (AgentBridge/Inspector row types)
"accessTokens", // intentionally-internal: 4 rotas /api/cli/* (connect, whoami, tokens, tokens/[id]) + server/authz/accessTokenAuth.ts via import direto "@/lib/db/accessTokens" (Rule #2)
"apiKeyColumnFallbacks", // db-internal: importado só por db/apiKeys.ts (API_KEY_COLUMN_FALLBACKS — fallbacks de coluna split do apiKeys.ts)
"apiKeyUsageLimitFields", // db-internal: importado só por db/apiKeys.ts (helpers de campo de limite de uso split do apiKeys.ts; mig 101)
"backupRetention", // db-internal: importado só por db/backup.ts e db/migrationRunner.ts (política de retenção compartilhada; mora fora de backup.ts porque core.ts importa migrationRunner.ts — importar backup.ts de lá fecharia um ciclo, #10421)
"caseMapping", // db-internal: importado só por db/core.ts (toSnakeCase/toCamelCase/objToSnake — column-mapping snake↔camel split do core.ts, #4947)
"cleanup", // intentionally-internal: 3 API routes (purge-quota-snapshots, purge-call-logs, purge-detailed-logs)
"cliToolState", // intentionally-internal: 14+ API routes em /api/cli-tools/*-settings
"comboForecast", // intentionally-internal: src/lib/usage/comboForecast.ts
"commandCodeAuth", // intentionally-internal: 5 API routes em /api/providers/command-code/auth/*
"compression", // intentionally-internal: 2 API routes (settings/compression, context/rtk/config)
"compressionDetailNormalizers", // db-internal: importado só por db/compression.ts (normalizeSessionDedupConfig/normalizeCcrConfig/buildDetailConfigDefaults/applyDetailConfigUpdate — normalizadores do detail-config split do compression.ts, #8404)
"connectionRuntimeState", // intentionally-internal: warmupScheduler sqlite/redis stores importam diretamente de @/lib/db/connectionRuntimeState (Rule #2)
"vacuumScheduler", // intentionally-internal: src/instrumentation-node.ts (dynamic import, lifecycle wiring per Rule #2)
"detailedLogs", // intentionally-internal: 3 callers (callLogs.ts, logs/detail route, embeddings handler)
"discovery", // DEAD?: 0 importers na auditoria de 2026-06-11; lib/discovery/index.ts não usa db/discovery
"domainState", // intentionally-internal: 5 callers (batchWriter, circuitBreaker, costRules, fallbackPolicy, lockoutPolicy)
"encryption", // intentionally-internal: 8+ callers (container, webhookDispatcher, cloudAgent/credentials, services/apiKey, 4+ routes, open-sse)
"healthCheck", // db-internal: importado por db/core.ts (runDbHealthCheck)
"jsonMigration", // intentionally-internal: src/app/api/settings/import-json/route.ts
"migrationRunner", // db-internal: importado por db/core.ts (runMigrations ao inicializar o DB)
"modelCapabilityOverrides", // intentionally-internal: src/app/api/model-capability-overrides/route.ts via import direto "@/lib/db/modelCapabilityOverrides" (#6727 — evita empurrar localDb.ts para o cap de 800 linhas)
"notion", // intentionally-internal: settings/notion API route + open-sse/mcp-server/tools/notionTools.ts
"obsidian", // intentionally-internal: src/lib/obsidianSync.ts + settings/obsidian route + MCP obsidianTools.ts
"optimizationSettings", // db-internal: imported by db/core.ts for SQLite PRAGMA application helpers that require the live adapter
"pluginMetrics", // DEAD? (production): write path não foi conectado ainda (documentado no cabeçalho do módulo); testado por tests/unit/plugins-metrics.test.ts
"prompts", // DEAD? (production): zero callers de produção encontrados; domínio domain/prompts.ts é independente; testado por tests/integration/proxy-pipeline.test.ts
"probeUtils", // db-internal: importado so por db/core.ts (retryProbeIfTransient no caminho da corruption-probe, #9541); testado por tests/unit/probe-9541-repro.test.ts
"providerNodeSelect", // db-internal: importado só por db/providers.ts (selectProviderNodeForConnection — lógica pura de seleção de provider node split do providers.ts, #4421)
"providerStats", // intentionally-internal: src/app/api/provider-stats/route.ts
"proxyLatency", // intentionally-internal: imported directly by src/lib/db/proxies.ts (anti-barrel, #6798)
"proxySubscriptions", // db-internal: importado só por db/proxies.ts (addProxiesToScopePool — split do proxies.ts para ficar sob o cap de tamanho congelado, #7299); a função já é re-exportada por proxies.ts (que localDb.ts re-exporta)
"recovery", // intentionally-internal: bin/cli/runtime.mjs (import() dinâmico) + tests
"schemaColumns", // db-internal: importado só por db/core.ts (ensureProviderConnections/UsageHistory/CallLogsColumns + hasColumn/hasTable/getTableColumns — schema-column reconciliation split do core.ts, #4948)
"secrets", // intentionally-internal: src/instrumentation-node.ts (import() dinâmico na inicialização)
"serviceModels", // intentionally-internal: 3 callers (services/modelSync, services/bootstrap, /api/services/9router/models)
"stateReset", // db-internal: 3 callers dentro de src/lib/db/ (core, backup, apiKeys) para coordenação de reset
"stats", // intentionally-internal: src/app/api/settings/database/refresh-stats/route.ts
"tierConfig", // intentionally-internal: open-sse/services/tierResolver.ts (require() dinâmico)
"webSessionDedup", // db-internal: importado só por db/providers.ts (webSessionCredentialKey/parseProviderSpecificData — helpers puros de dedup de credencial web-session split do providers.ts, #3368 PR6)
]);
// Alias para retrocompatibilidade com os testes existentes que importam KNOWN_UNEXPORTED.
// O comportamento do gate é idêntico — só o nome e os comentários mudaram (#3499).
export const KNOWN_UNEXPORTED = INTENTIONALLY_INTERNAL;
// (c) Leituras de SQL contra bancos EXTERNOS, permitidas por design (#3500).
// Esta rota NÃO consulta o DB do OmniRoute (getDbInstance) — ela abre o
// SQLite de OUTRO aplicativo (Kiro) para auto-importar credenciais.
@@ -97,16 +32,13 @@ export const KNOWN_UNEXPORTED = INTENTIONALLY_INTERNAL;
// precisa de entrada aqui: o SQL contra o state.vscdb externo do Cursor vive
// em src/lib/cursor/tokenExtractor.ts, fora do escopo desta checagem (que só
// varre src/app/api/**/route.ts e open-sse/handlers/*.ts).
const EXTERNAL_DB_ALLOWED = new Set([
export const EXTERNAL_DB_ALLOWED = new Set([
"src/app/api/oauth/kiro/auto-import/route.ts", // read-only no SQLite do Kiro (DB externo)
]);
// Alias de retrocompatibilidade (testes/consumidores que importam KNOWN_RAW_SQL).
// Comportamento do gate idêntico — só o nome e o enquadramento mudaram (#3500).
const KNOWN_RAW_SQL = EXTERNAL_DB_ALLOWED;
// Módulos sempre excluídos da checagem (a): não são domínio re-exportável.
const DB_MODULE_EXCLUDE = new Set(["core", "localDb", "index"]);
export const KNOWN_RAW_SQL = EXTERNAL_DB_ALLOWED;
function walk(dir, acc = []) {
if (!fs.existsSync(dir)) return acc;
@@ -118,59 +50,6 @@ function walk(dir, acc = []) {
return acc;
}
// Lista os módulos de domínio em src/lib/db (top-level *.ts), excluindo
// core/localDb/index, *.d.ts e qualquer subdiretório (migrations/, adapters/, __tests__/).
export function collectDbModules(dbDir = DB_DIR) {
if (!fs.existsSync(dbDir)) return [];
return fs
.readdirSync(dbDir, { withFileTypes: true })
.filter((e) => e.isFile() && /\.ts$/.test(e.name) && !/\.d\.ts$/.test(e.name))
.map((e) => e.name.replace(/\.ts$/, ""))
.filter((name) => !DB_MODULE_EXCLUDE.has(name))
.sort();
}
// Extrai os nomes de módulo re-exportados de localDb.ts a partir de
// `... from "./db/X"` (cobre export {…}, export * e export type {…}).
export function extractReexportedModules(localDbSource) {
const re = /from\s+["']\.\/db\/([A-Za-z0-9_]+)["']/g;
const out = new Set();
let m;
while ((m = re.exec(localDbSource))) out.add(m[1]);
return out;
}
// (a) Módulos db/ que não são re-exportados e não estão na lista de
// intencionalmente-internos (INTENTIONALLY_INTERNAL). O gate falha para
// qualquer módulo NOVO que não seja re-exportado nem justificado.
export function findMissingReexports(dbModules, reexported, allowlist = INTENTIONALLY_INTERNAL) {
return dbModules.filter((mod) => !reexported.has(mod) && !allowlist.has(mod));
}
// (b) localDb.ts deve conter SOMENTE import/export + comentários (sem lógica).
// Remove comentários e strings, depois procura declarações de runtime.
export function hasLogic(localDbSource) {
const stripped = localDbSource
// comentários de bloco
.replace(/\/\*[\s\S]*?\*\//g, "")
// comentários de linha
.replace(/\/\/[^\n]*/g, "")
// template strings
.replace(/`(?:\\[\s\S]|[^\\`])*`/g, '""')
// strings simples/duplas (paths de import etc.)
.replace(/"(?:\\.|[^"\\])*"/g, '""')
.replace(/'(?:\\.|[^'\\])*'/g, '""');
// function/class declaradas, ou atribuição a função (const X = (…) =>, const X = function).
const logicPatterns = [
/(^|[^.\w])function\s+[A-Za-z_$]/, // function decl (não method .foo())
/(^|[^.\w])class\s+[A-Za-z_$]/, // class decl
/(?:const|let|var)\s+[A-Za-z_$][\w$]*\s*=\s*(?:async\s*)?\(/, // const X = (…) ... (arrow/call)
/(?:const|let|var)\s+[A-Za-z_$][\w$]*\s*=\s*(?:async\s+)?function\b/, // const X = function
];
return logicPatterns.some((rx) => rx.test(stripped));
}
// SQL cru é sempre uma STRING passada a db.prepare()/exec(): casamos os padrões
// SÓ dentro de literais de string (não em código JS — `import … from`, `.set(`,
// `new Set(`, `delete x` etc. são falsos positivos se varrermos o código todo).
@@ -198,7 +77,7 @@ export function extractStringLiterals(code) {
// tira as aspas/crases delimitadoras
out.push(m[0].slice(1, -1));
}
return out.join("\n\n"); // separador que nenhum padrão SQL atravessa
return out.join("\n\u0000\n"); // separador que nenhum padrão SQL atravessa
}
// (c) Arquivos com SQL cru dentro de literais de string (linhas não-comentário),
@@ -217,7 +96,7 @@ export function findRawSql(files, allowlist = KNOWN_RAW_SQL) {
// Match each literal independently. Joining literals before scanning would
// turn harmless code such as `update(...)` plus a later `"set"` string into
// a false UPDATE ... SET SQL match.
const literals = extractStringLiterals(stripComments(src)).split("\n\0\n");
const literals = extractStringLiterals(stripComments(src)).split("\n\u0000\n");
if (literals.some((literal) => SQL_PATTERNS.some((rx) => rx.test(literal)))) {
offenders.push(rel);
}
@@ -239,33 +118,6 @@ export function collectSqlScanFiles(apiDir = API_DIR, handlersDir = HANDLERS_DIR
function main() {
const failures = [];
const localDbSource = fs.readFileSync(LOCAL_DB, "utf8");
// (a) re-export completeness
const dbModules = collectDbModules();
const reexported = extractReexportedModules(localDbSource);
// Live unexported modules BEFORE allowlist filtering (needed for stale-enforcement).
const liveUnexported = dbModules.filter((mod) => !reexported.has(mod));
assertNoStale(INTENTIONALLY_INTERNAL, liveUnexported, "check-db-rules:unexported");
const missing = findMissingReexports(dbModules, reexported);
if (missing.length) {
failures.push(
`[#2 re-export] ${missing.length} módulo(s) db/ não re-exportado(s) por src/lib/localDb.ts:\n` +
missing.map((m) => ` ✗ src/lib/db/${m}.ts`).join("\n") +
`\n → re-exporte de src/lib/localDb.ts (apenas a lista de re-export, nada de lógica)` +
` ou adicione a INTENTIONALLY_INTERNAL com justificativa (import direto de "@/lib/db/${missing[0]}").`
);
}
// (b) localDb sem lógica
if (hasLogic(localDbSource)) {
failures.push(
`[#2 sem-lógica] src/lib/localDb.ts contém lógica (function/class/arrow). É camada de` +
` re-export apenas — mova a lógica para um módulo src/lib/db/.`
);
}
// (c) SQL cru fora de db/
// Live raw-SQL offenders BEFORE allowlist filtering (needed for stale-enforcement).
@@ -289,8 +141,8 @@ function main() {
}
if (!process.exitCode) {
console.log(
`[check-db-rules] OK (${dbModules.length} módulos db/, ${reexported.size} re-exportados, ` +
`${INTENTIONALLY_INTERNAL.size} intencionalmente-internos (Rule #2); ${EXTERNAL_DB_ALLOWED.size} leituras de DB externo permitidas (#3500))`
`[check-db-rules] OK (${scanFiles.length} arquivos varridos; ` +
`${EXTERNAL_DB_ALLOWED.size} leituras de DB externo permitidas (#3500))`
);
}
}

View File

@@ -1,5 +1,5 @@
import { getMachineId } from "@/shared/utils/machine";
import { getSettings } from "@/lib/localDb";
import { getSettings } from "@/lib/db/settings";
import HomePageClient from "../dashboard/HomePageClient";
import BootstrapBanner from "../dashboard/BootstrapBanner";
import KimiSponsorBanner from "../dashboard/KimiSponsorBanner";

View File

@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { getCachedSettings, updateSettings } from "@/lib/localDb";
import { getCachedSettings } from "@/lib/db/readCache";
import { updateSettings } from "@/lib/db/settings";
import { SignJWT, jwtVerify, createRemoteJWKSet } from "jose";
import { cookies } from "next/headers";
import { timingSafeCompare } from "@/shared/utils/timingSafeCompare";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getCachedSettings } from "@/lib/localDb";
import { getCachedSettings } from "@/lib/db/readCache";
/**
* GET /api/auth/oidc/login

View File

@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
export const dynamic = "force-dynamic";
import { getBatch } from "@/lib/localDb";
import { getBatch } from "@/lib/db/batches";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
export async function GET(request: Request, { params }: { params: { id: string } }) {

View File

@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
export const dynamic = "force-dynamic";
import { listBatches } from "@/lib/localDb";
import { listBatches } from "@/lib/db/batches";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
export async function GET(request: Request) {

View File

@@ -9,7 +9,7 @@ import {
} from "@/lib/semanticCache";
import { getIdempotencyStats } from "@/lib/idempotencyLayer";
import { getCacheMetrics, getCacheTrend } from "@/lib/db/settings";
import { getCachedSettings } from "@/lib/localDb";
import { getCachedSettings } from "@/lib/db/readCache";
import { isAuthenticated } from "@/shared/utils/apiAuth";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";

View File

@@ -14,7 +14,7 @@ import { normalizeClaudeBaseUrl } from "@/shared/services/claudeCliConfig";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import { cliSettingsEnvSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { getApiKeyById } from "@/lib/localDb";
import { getApiKeyById } from "@/lib/db/apiKeys";
import { readJsoncConfig } from "../_lib/jsoncConfig";
// Get claude settings path based on OS

View File

@@ -13,7 +13,7 @@ import { createMultiBackup } from "@/shared/services/backupService";
import { saveCliToolLastConfigured, deleteCliToolLastConfigured } from "@/lib/db/cliToolState";
import { cliModelConfigSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { getApiKeyById } from "@/lib/localDb";
import { getApiKeyById } from "@/lib/db/apiKeys";
import { normalizeCodexBaseUrl } from "@/shared/utils/codexBaseUrl";
import { migrateCodexFeatureFlags } from "@/shared/utils/codexConfig";

View File

@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { requireCliToolsAuth } from "@/lib/api/requireCliToolsAuth";
import { getApiKeys } from "@/lib/localDb";
import { getApiKeys } from "@/lib/db/apiKeys";
import { maskStoredApiKey } from "@/lib/apiKeyExposure";
// GET /api/cli-tools/keys - List API keys with raw values for authenticated CLI tools UI only

View File

@@ -1,7 +1,7 @@
import { NextResponse } from "next/server";
import { z } from "zod";
import { getAuditRequestContext, logAuditEvent } from "@/lib/compliance/index";
import { getCachedSettings } from "@/lib/localDb";
import { getCachedSettings } from "@/lib/db/readCache";
import {
ensurePersistentManagementPasswordHash,
getStoredManagementPassword,

View File

@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { reorderCombos, isCloudEnabled } from "@/lib/localDb";
import { reorderCombos } from "@/lib/db/combos";
import { isCloudEnabled } from "@/lib/db/settings";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { reorderCombosSchema } from "@/shared/validation/schemas";

View File

@@ -1,11 +1,6 @@
import { NextResponse } from "next/server";
import {
getCombos,
getCombosCount,
createCombo,
getComboByName,
isCloudEnabled,
} from "@/lib/localDb";
import { getCombos, getCombosCount, createCombo, getComboByName } from "@/lib/db/combos";
import { isCloudEnabled } from "@/lib/db/settings";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { validateCompositeTiersConfig } from "@/lib/combos/compositeTiers";

View File

@@ -1,7 +1,8 @@
import { randomUUID } from "node:crypto";
import { NextResponse } from "next/server";
import { buildComboTestRequestBody, extractComboTestResponseText } from "@/lib/combos/testHealth";
import { getComboByName, getCombos, pickApiKeyForInternalUse } from "@/lib/localDb";
import { getComboByName, getCombos } from "@/lib/db/combos";
import { pickApiKeyForInternalUse } from "@/lib/db/apiKeys";
import { getRuntimePorts } from "@/lib/runtime/ports";
import { resolveNestedComboTargets } from "@omniroute/open-sse/services/combo.ts";
import { testComboSchema } from "@/shared/validation/schemas";

View File

@@ -8,7 +8,7 @@ import {
setDbBackupMaxFiles,
getDbBackupRetentionDays,
setDbBackupRetentionDays,
} from "@/lib/localDb";
} from "@/lib/db/backup";
import { dbBackupCleanupSchema, dbBackupRestoreSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { isAuthenticated } from "@/shared/utils/apiAuth";

View File

@@ -1,6 +1,7 @@
import { randomUUID } from "node:crypto";
import { NextResponse } from "next/server";
import { getEvalScorecard, listEvalRuns, getApiKeys } from "@/lib/localDb";
import { getEvalScorecard, listEvalRuns } from "@/lib/db/evals";
import { getApiKeys } from "@/lib/db/apiKeys";
import { listSuites, runSuite, createScorecard } from "@/lib/evals/evalRunner";
import { buildEvalTargetOptions, runEvalSuiteAgainstTarget } from "@/lib/evals/runtime";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { deleteCustomEvalSuite, getCustomEvalSuite, saveCustomEvalSuite } from "@/lib/localDb";
import { deleteCustomEvalSuite, getCustomEvalSuite, saveCustomEvalSuite } from "@/lib/db/evals";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { evalSuiteSaveSchema } from "@/shared/validation/schemas";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { saveCustomEvalSuite } from "@/lib/localDb";
import { saveCustomEvalSuite } from "@/lib/db/evals";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { evalSuiteSaveSchema } from "@/shared/validation/schemas";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getFile, getFileContent } from "@/lib/localDb";
import { getFile, getFileContent } from "@/lib/db/files";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { listFiles } from "@/lib/localDb";
import { listFiles } from "@/lib/db/files";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
export async function GET(request: Request) {

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { regenerateApiKey } from "@/lib/localDb";
import { regenerateApiKey } from "@/lib/db/apiKeys";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import * as log from "@/sse/utils/logger";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getApiKeyById } from "@/lib/localDb";
import { getApiKeyById } from "@/lib/db/apiKeys";
import { isApiKeyRevealEnabled } from "@/lib/apiKeyExposure";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import * as log from "@/sse/utils/logger";

View File

@@ -3,9 +3,9 @@ import {
deleteApiKey,
getApiKeyById,
updateApiKeyPermissions,
isCloudEnabled,
ApiKeyPolicyInvariantError,
} from "@/lib/localDb";
} from "@/lib/db/apiKeys";
import { isCloudEnabled } from "@/lib/db/settings";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { updateKeyPermissionsSchema } from "@/shared/validation/schemas";
@@ -162,10 +162,13 @@ export async function PATCH(request, { params }) {
});
} catch (error) {
if (error instanceof ApiKeyPolicyInvariantError) {
return NextResponse.json(buildErrorBody(400, error.message, null, {
type: "lease_error",
code: error.code,
}), { status: 400 });
return NextResponse.json(
buildErrorBody(400, error.message, null, {
type: "lease_error",
code: error.code,
}),
{ status: 400 }
);
}
log.error("keys", "Error updating key permissions", error);
return NextResponse.json({ error: "Failed to update permissions" }, { status: 500 });

View File

@@ -1,6 +1,11 @@
import { NextResponse } from "next/server";
import { z } from "zod";
import { addKeyToGroup, removeKeyFromGroup, getGroupMembers, getKeyGroup } from "@/lib/localDb";
import {
addKeyToGroup,
removeKeyFromGroup,
getGroupMembers,
getKeyGroup,
} from "@/lib/db/apiKeyGroups";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
type RouteParams = { params: Promise<{ id: string }> };

View File

@@ -5,7 +5,7 @@ import {
removeGroupPermission,
getGroupPermissions,
getKeyGroup,
} from "@/lib/localDb";
} from "@/lib/db/apiKeyGroups";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
type RouteParams = { params: Promise<{ id: string }> };

View File

@@ -9,7 +9,7 @@ import {
removeGroupPermission,
addKeyToGroup,
removeKeyFromGroup,
} from "@/lib/localDb";
} from "@/lib/db/apiKeyGroups";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
type RouteParams = { params: Promise<{ id: string }> };

View File

@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { z } from "zod";
import { getAllKeyGroups, createKeyGroup, getKeyGroup } from "@/lib/localDb";
import { getAllKeyGroups, createKeyGroup, getKeyGroup } from "@/lib/db/apiKeyGroups";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
const createKeyGroupSchema = z.object({

View File

@@ -3,9 +3,9 @@ import {
getApiKeys,
getApiKeysCount,
createApiKey,
isCloudEnabled,
updateApiKeyPermissions,
} from "@/lib/localDb";
} from "@/lib/db/apiKeys";
import { isCloudEnabled } from "@/lib/db/settings";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { createKeySchema } from "@/shared/validation/schemas";

View File

@@ -3,7 +3,7 @@ import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { validateBody, isValidationFailure } from "@/shared/validation/helpers";
import { MemoryReindexSchema } from "@/shared/schemas/memory";
import { runReindexBatch, getReindexPending } from "@/lib/memory/reindex";
import { markAllMemoriesNeedReindex } from "@/lib/localDb";
import { markAllMemoriesNeedReindex } from "@/lib/db/memoryVec";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error.ts";
import { logger } from "@omniroute/open-sse/utils/logger.ts";
@@ -19,7 +19,7 @@ export async function POST(request: Request) {
} catch {
return NextResponse.json(
{ error: { message: "Invalid JSON body", details: [] } },
{ status: 400 },
{ status: 400 }
);
}

View File

@@ -5,7 +5,7 @@ import {
updateMiddlewareHook,
deleteMiddlewareHook,
getHookLogs,
} from "@/lib/localDb";
} from "@/lib/db/middleware";
import { registerHook, unregisterHook, updateHook } from "@/lib/middleware/registry";
import type { HookConfig } from "@/lib/middleware/types";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
@@ -106,7 +106,10 @@ export async function PUT(request: Request, { params }: RouteParams) {
return NextResponse.json({ hook: saved });
} catch (error: any) {
console.error("[API] PUT /api/middleware/hooks/[name] error:", error);
return NextResponse.json({ error: sanitizeErrorMessage(error) || "Failed to update hook" }, { status: 500 });
return NextResponse.json(
{ error: sanitizeErrorMessage(error) || "Failed to update hook" },
{ status: 500 }
);
}
}

View File

@@ -5,7 +5,7 @@ import {
createMiddlewareHook,
getMiddlewareHook,
getHookLogs,
} from "@/lib/localDb";
} from "@/lib/db/middleware";
import { registerHook, getAllHooks } from "@/lib/middleware/registry";
import type { HookConfig, CreateHookRequest } from "@/lib/middleware/types";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
@@ -115,6 +115,9 @@ export async function POST(request: Request) {
return NextResponse.json({ hook: saved }, { status: 201 });
} catch (error: any) {
console.error("[API] POST /api/middleware/hooks error:", error);
return NextResponse.json({ error: sanitizeErrorMessage(error) || "Failed to create hook" }, { status: 500 });
return NextResponse.json(
{ error: sanitizeErrorMessage(error) || "Failed to create hook" },
{ status: 500 }
);
}
}

View File

@@ -11,7 +11,7 @@ import {
updateModelComboMapping,
deleteModelComboMapping,
getModelComboMappingById,
} from "@/lib/localDb";
} from "@/lib/db/modelComboMappings";
import { validateBody, isValidationFailure } from "@/shared/validation/helpers";
const updateMappingSchema = z.object({

View File

@@ -7,7 +7,7 @@
import { z } from "zod";
import { NextResponse } from "next/server";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { createModelComboMapping, getModelComboMappings } from "@/lib/localDb";
import { createModelComboMapping, getModelComboMappings } from "@/lib/db/modelComboMappings";
import { paginationSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { validatedJsonBody } from "@/shared/validation/helpers";

View File

@@ -14,7 +14,7 @@ import { NextResponse } from "next/server";
import { z } from "zod";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { DEFAULT_MODEL_TEST_TIMEOUT_MS, runSingleModelTest } from "@/lib/api/modelTestRunner";
import { setModelIsHidden } from "@/lib/localDb";
import { setModelIsHidden } from "@/lib/db/models";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
import { getSettings } from "@/lib/db/settings";
import { isFreeModel, providerHasFreeModels } from "@/shared/utils/freeModels";

View File

@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { getProviderConnections, getCachedSettings } from "@/lib/localDb";
import { getProviderConnections } from "@/lib/db/providers";
import { getCachedSettings } from "@/lib/db/readCache";
import { buildHealthPayload } from "@/lib/monitoring/observability";
import { readRunningBuildSha } from "@/lib/monitoring/buildSha";
import { APP_CONFIG } from "@/shared/constants/config";

View File

@@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry.ts";
import { getAllCustomModels, getAllSyncedAvailableModels, getPricing } from "@/lib/localDb";
import { getAllCustomModels, getAllSyncedAvailableModels } from "@/lib/db/models";
import { getPricing } from "@/lib/db/settings";
import { getProviderPrefixIndex } from "@/lib/providerNodePrefixes";
function asRecord(value: unknown): Record<string, unknown> {

View File

@@ -6,7 +6,7 @@ import {
updatePricing,
resetPricing,
resetAllPricing,
} from "@/lib/localDb";
} from "@/lib/db/settings";
import { updatePricingSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";

View File

@@ -11,7 +11,7 @@ import {
mergeModelCompatOverride,
getHiddenModelsByProvider,
type ModelCompatPatch,
} from "@/lib/localDb";
} from "@/lib/db/models";
import {
getModelContextOverrideRecord,
setModelContextOverride,

View File

@@ -7,7 +7,8 @@
*/
import { NextRequest, NextResponse } from "next/server";
import { getCachedProviderConnectionById, updateProviderConnection } from "@/lib/localDb";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import { updateProviderConnection } from "@/lib/db/providers";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { clampLoginTimeoutMs } from "@/lib/api/loginTimeout";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error.ts";

View File

@@ -11,11 +11,8 @@ import { resolveAlibabaProviderModelsUrl } from "@/shared/constants/alibabaProvi
import { getStaticModelsForProvider } from "@/lib/providers/staticModels";
import { providerUsesCuratedModelsOnly } from "@/lib/providers/modelListingCapability";
import { mergeModelsWithCustomPrecedence } from "@/lib/providers/modelMetadataPrecedence";
import {
getCachedProviderConnectionById,
getModelIsHidden,
resolveProxyForProvider,
} from "@/lib/localDb";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import { resolveProxyForProvider } from "@/lib/db/proxies";
import {
SAFE_OUTBOUND_FETCH_PRESETS,
SafeOutboundFetchError,
@@ -86,7 +83,7 @@ import {
import { buildProviderModelsUrl, getDiscoveryClientVersionOptions } from "./discoveryClientVersion";
import { getAdobeModels } from "./adobeFireflyDiscovery";
import { parseGeminiModelsList } from "@/lib/providerModels/geminiModelsParser";
import { getSyncedAvailableModels, getCustomModels } from "@/lib/db/models";
import { getSyncedAvailableModels, getCustomModels, getModelIsHidden } from "@/lib/db/models";
import { isConnectionUnavailableToAuxiliaryActivity } from "@/lib/exclusiveLeaseIsolation";
import { fetchCursorAgentModels } from "@/lib/providerModels/cursorAgent";
import { fetchCursorAvailableModels } from "@/lib/providerModels/cursorAvailableModels";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getCachedProviderConnectionById } from "@/lib/localDb";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import { updateProviderConnection } from "@/lib/db/providers";
import {
getAccessToken,

View File

@@ -4,12 +4,9 @@ import {
getProviderAuditTarget,
summarizeProviderConnectionForAudit,
} from "@/lib/compliance/providerAudit";
import {
getCachedProviderConnectionById,
updateProviderConnection,
deleteProviderConnection,
isCloudEnabled,
} from "@/lib/localDb";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import { updateProviderConnection, deleteProviderConnection } from "@/lib/db/providers";
import { isCloudEnabled } from "@/lib/db/settings";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { updateProviderConnectionSchema } from "@/shared/validation/schemas";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getCachedProviderConnectionById } from "@/lib/localDb";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import {
deleteImportedCustomModels,
deleteSyncedAvailableModelsForProvider,

View File

@@ -1,12 +1,9 @@
import { NextResponse } from "next/server";
import { z } from "zod";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import {
getCachedProviderConnectionById,
updateProviderConnection,
isCloudEnabled,
resolveProxyForConnection,
} from "@/lib/localDb";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import { updateProviderConnection } from "@/lib/db/providers";
import { isCloudEnabled, resolveProxyForConnection } from "@/lib/db/settings";
import { getConsistentMachineId } from "@/shared/utils/machineId";
import { syncToCloud } from "@/lib/cloudSync";
import { validateProviderApiKey } from "@/lib/providers/validation";

View File

@@ -28,7 +28,8 @@ import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { isManagedProviderConnectionId } from "@/lib/providers/catalog";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
import { validateProviderApiKey } from "@/lib/providers/validation";
import { getProxyForLevel, resolveProxyForProvider } from "@/lib/localDb";
import { getProxyForLevel } from "@/lib/db/settings";
import { resolveProxyForProvider } from "@/lib/db/proxies";
import { runWithProxyContext } from "@omniroute/open-sse/utils/proxyFetch.ts";
import { rejectRetiredCommonChatGptWebProvider } from "@/lib/providers/chatgptWebRetirementResponse";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getProviderConnections } from "@/lib/localDb";
import { getProviderConnections } from "@/lib/db/providers";
// GET /api/providers/client - List all connections for client (includes sensitive fields for sync)
export async function GET() {

View File

@@ -1,10 +1,7 @@
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { consumeCommandCodeAuthSecret } from "@/lib/db/commandCodeAuth";
import {
createProviderConnection,
updateProviderConnection,
} from "@/lib/db/providers";
import { getCachedProviderConnectionById } from "@/lib/localDb";
import { createProviderConnection, updateProviderConnection } from "@/lib/db/providers";
import { getCachedProviderConnectionById } from "@/lib/db/readCache";
import { sanitizeProviderSpecificDataForResponse } from "@/lib/providers/requestDefaults";
import { commandCodeApplySchema, noStoreJson, stateHashFromState } from "../shared";

View File

@@ -27,7 +27,8 @@ import {
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
import { validateProviderApiKey } from "@/lib/providers/validation";
import { getProxyForLevel, resolveProxyForProvider } from "@/lib/localDb";
import { getProxyForLevel } from "@/lib/db/settings";
import { resolveProxyForProvider } from "@/lib/db/proxies";
import { runWithProxyContext } from "@omniroute/open-sse/utils/proxyFetch.ts";
import { rejectRetiredCommonChatGptWebProvider } from "@/lib/providers/chatgptWebRetirementResponse";

View File

@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { getAllProviderQuotaWindows } from "@omniroute/open-sse/services/quotaPreflight.ts";
import { getCachedSettings } from "@/lib/localDb";
import { getCachedSettings } from "@/lib/db/readCache";
import { resolveResilienceSettings } from "@/lib/resilience/settings";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";

View File

@@ -8,7 +8,8 @@ import {
isAnthropicCompatibleProvider,
} from "@/shared/constants/providers";
import { validateProviderApiKey } from "@/lib/providers/validation";
import { getProxyForLevel, resolveProxyForProvider } from "@/lib/localDb";
import { getProxyForLevel } from "@/lib/db/settings";
import { resolveProxyForProvider } from "@/lib/db/proxies";
import { validateProviderApiKeySchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { runWithProxyContextOrDirect } from "@omniroute/open-sse/utils/proxyFetch.ts";

View File

@@ -22,7 +22,8 @@ import { NextResponse } from "next/server";
import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { GroupRenameSchema } from "@/shared/schemas/quota";
import { renameGroup, deleteGroup, getGroup, getPoolsByGroup } from "@/lib/localDb";
import { renameGroup, deleteGroup, getGroup } from "@/lib/db/quotaGroups";
import { getPoolsByGroup } from "@/lib/db/quotaPools";
export const dynamic = "force-dynamic";
@@ -55,10 +56,7 @@ export async function PATCH(request: Request, { params }: RouteParams): Promise<
await syncQuotaCombos(pool.id);
} catch (err) {
// Guard: combo-sync failure must never break group rename callers.
console.warn(
"[quota-groups] syncQuotaCombos failed (non-fatal):",
(err as Error)?.message,
);
console.warn("[quota-groups] syncQuotaCombos failed (non-fatal):", (err as Error)?.message);
}
}

View File

@@ -15,7 +15,7 @@ import { NextResponse } from "next/server";
import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { GroupCreateSchema } from "@/shared/schemas/quota";
import { listGroups, createGroup } from "@/lib/localDb";
import { listGroups, createGroup } from "@/lib/db/quotaGroups";
export const dynamic = "force-dynamic";

View File

@@ -19,7 +19,8 @@
import { NextResponse } from "next/server";
import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { getApiKeyById, getCombos } from "@/lib/localDb";
import { getApiKeyById } from "@/lib/db/apiKeys";
import { getCombos } from "@/lib/db/combos";
import { resolveQuotaKeyScope } from "@/lib/quota/quotaKey";
import { filterModelsToQuotaPools } from "@/lib/quota/quotaCombos";
@@ -39,9 +40,7 @@ export async function GET(request: Request, { params }: RouteParams): Promise<Re
return NextResponse.json(buildErrorBody(404, "API key not found"), { status: 404 });
}
const allowedQuotas: string[] = Array.isArray(
(key as Record<string, unknown>).allowedQuotas,
)
const allowedQuotas: string[] = Array.isArray((key as Record<string, unknown>).allowedQuotas)
? ((key as Record<string, unknown>).allowedQuotas as string[])
: [];

View File

@@ -20,10 +20,10 @@ import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { PlanUpsertSchema } from "@/shared/schemas/quota";
import {
getProviderPlan,
upsertProviderPlan,
deleteProviderPlan,
} from "@/lib/localDb";
getPlan as getProviderPlan,
upsertPlan as upsertProviderPlan,
deletePlan as deleteProviderPlan,
} from "@/lib/db/providerPlans";
import { resolvePlan } from "@/lib/quota/planResolver";
import { resolveConnectionProvider } from "@/lib/quota/connectionProvider";
import { logAuditEvent, getAuditRequestContext } from "@/lib/compliance/index";

View File

@@ -17,7 +17,7 @@
import { NextResponse } from "next/server";
import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { listProviderPlans } from "@/lib/localDb";
import { listPlans as listProviderPlans } from "@/lib/db/providerPlans";
import { knownProviders, getKnownPlan } from "@/lib/quota/planRegistry";
export const dynamic = "force-dynamic";

View File

@@ -15,7 +15,7 @@ import { NextResponse } from "next/server";
import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { PoolUpdateSchema } from "@/shared/schemas/quota";
import { getPool, updatePool, deletePool } from "@/lib/localDb";
import { getPool, updatePool, deletePool } from "@/lib/db/quotaPools";
import { logAuditEvent, getAuditRequestContext } from "@/lib/compliance/index";
import { reconcilePoolExclusivity } from "@/lib/quota/quotaKey";

View File

@@ -15,7 +15,7 @@
import { NextResponse } from "next/server";
import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { getPool } from "@/lib/localDb";
import { getPool } from "@/lib/db/quotaPools";
import { getQuotaStore } from "@/lib/quota/QuotaStore";
import { resolvePlan } from "@/lib/quota/planResolver";
import { resolveConnectionProvider } from "@/lib/quota/connectionProvider";

View File

@@ -16,7 +16,7 @@ import { NextResponse } from "next/server";
import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { PoolCreateSchema } from "@/shared/schemas/quota";
import { listPools, createPool, ensurePool } from "@/lib/localDb";
import { listPools, createPool, ensurePool } from "@/lib/db/quotaPools";
import { logAuditEvent, getAuditRequestContext } from "@/lib/compliance/index";
export const dynamic = "force-dynamic";
@@ -66,7 +66,10 @@ export async function POST(request: Request): Promise<Response> {
requestId: ctx.requestId,
});
return NextResponse.json({ pool, ...(ensured ? { created: ensured.created, updated: ensured.updated } : {}) }, { status: ensured?.created === false ? 200 : 201 });
return NextResponse.json(
{ pool, ...(ensured ? { created: ensured.created, updated: ensured.updated } : {}) },
{ status: ensured?.created === false ? 200 : 201 }
);
} catch (err) {
const message = err instanceof Error ? err.message : "Failed to create pool";
return NextResponse.json(buildErrorBody(500, message), { status: 500 });

View File

@@ -25,7 +25,7 @@ import { NextResponse } from "next/server";
import { buildErrorBody } from "@omniroute/open-sse/utils/error";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { QuotaPreviewQuerySchema } from "@/shared/schemas/quota";
import { getPool } from "@/lib/localDb";
import { getPool } from "@/lib/db/quotaPools";
import { enforceQuotaShare } from "@/lib/quota/enforce";
export const dynamic = "force-dynamic";

View File

@@ -1,7 +1,7 @@
import { NextResponse } from "next/server";
import { getAllModelLockouts } from "@omniroute/open-sse/services/accountFallback.ts";
import { getCacheStats } from "@omniroute/open-sse/services/signatureCache.ts";
import { getProviderConnections, updateProviderConnection } from "@/lib/localDb";
import { getProviderConnections, updateProviderConnection } from "@/lib/db/providers";
import {
enableRateLimitProtection,
disableRateLimitProtection,

View File

@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { getCachedSettings, getSettings, updateSettings } from "@/lib/localDb";
import { getCachedSettings } from "@/lib/db/readCache";
import { getSettings, updateSettings } from "@/lib/db/settings";
import {
buildLegacyResilienceCompat,
mergeResilienceSettings,

View File

@@ -4,7 +4,7 @@ vi.mock("../../../../shared/utils/apiAuth", () => ({
isAuthenticated: vi.fn(),
}));
vi.mock("../../../../lib/localDb", () => ({
vi.mock("@/lib/db/settings", () => ({
getSettings: vi.fn(),
updateSettings: vi.fn(),
}));
@@ -19,7 +19,7 @@ vi.mock("../../../../lib/memory/settings", async () => {
import { GET, PUT } from "../memory/route";
import { isAuthenticated } from "../../../../shared/utils/apiAuth";
import { getSettings, updateSettings } from "../../../../lib/localDb";
import { getSettings, updateSettings } from "@/lib/db/settings";
import { invalidateMemorySettingsCache } from "../../../../lib/memory/settings";
function createRequest(method: "GET" | "PUT", body?: unknown) {

View File

@@ -1,9 +1,9 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { PATCH } from "../route";
// Mock the localDb functions used in the route
vi.mock("../../../../lib/localDb", () => {
const original = vi.importActual("../../../../lib/localDb");
// Mock the settings db functions used in the route
vi.mock("@/lib/db/settings", () => {
const original = vi.importActual("@/lib/db/settings");
return {
...original,
getSettings: vi.fn(),
@@ -11,7 +11,7 @@ vi.mock("../../../../lib/localDb", () => {
};
});
import { getSettings, updateSettings } from "../../../../lib/localDb";
import { getSettings, updateSettings } from "@/lib/db/settings";
// Helper to create a Request with JSON body
function createPatchRequest(body: unknown) {

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getSettings } from "@/lib/localDb";
import { getSettings } from "@/lib/db/settings";
import { isAuthRequired, isDashboardSessionAuthenticated } from "@/shared/utils/apiAuth";
import { createErrorResponse } from "@/lib/api/errorResponse";
import { extractApiKey, isValidApiKey } from "@/sse/services/auth";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getSettings, updateSettings } from "@/lib/localDb";
import { getSettings, updateSettings } from "@/lib/db/settings";
import { updateAutoDisableAccountsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";

View File

@@ -1,5 +1,5 @@
import { NextResponse } from "next/server";
import { getSettings, updateSettings } from "@/lib/localDb";
import { getSettings, updateSettings } from "@/lib/db/settings";
import { updateComboDefaultsSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";

View File

@@ -1,11 +1,9 @@
import { NextResponse } from "next/server";
import {
getSettings,
getProviderConnections,
getCachedProviderNodes,
getCombos,
getApiKeys,
} from "@/lib/localDb";
import { getSettings } from "@/lib/db/settings";
import { getProviderConnections } from "@/lib/db/providers";
import { getCachedProviderNodes } from "@/lib/db/readCache";
import { getCombos } from "@/lib/db/combos";
import { getApiKeys } from "@/lib/db/apiKeys";
import { isAuthRequired, isAuthenticated } from "@/shared/utils/apiAuth";
import {
getAllUsageHistory,
@@ -75,9 +73,10 @@ export async function GET(request: Request) {
// #6328: honor hidePaidModels at the export boundary so backup files
// cannot silently smuggle paid model ids back in on import.
const combos = rawSettings.hidePaidModels === true
? filterPaidComboSteps(combosRaw as Array<{ models?: unknown }>)
: combosRaw;
const combos =
rawSettings.hidePaidModels === true
? filterPaidComboSteps(combosRaw as Array<{ models?: unknown }>)
: combosRaw;
const exportData: Record<string, unknown> = {
settings: safeSettings,

View File

@@ -1,7 +1,7 @@
import { request as undiciRequest } from "undici";
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { createErrorResponse, createErrorResponseFromUnknown } from "@/lib/api/errorResponse";
import { getFreeProxyById, promoteFreeProxyToPool } from "@/lib/localDb";
import { getFreeProxyById, promoteFreeProxyToPool } from "@/lib/db/freeProxies";
import {
createProxyDispatcher,
proxyConfigToUrl,

View File

@@ -3,7 +3,7 @@ import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { createErrorResponse, createErrorResponseFromUnknown } from "@/lib/api/errorResponse";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { freeProxyBulkAddSchema } from "@/shared/validation/freeProxySchemas";
import { getFreeProxyById, promoteFreeProxyToPool } from "@/lib/localDb";
import { getFreeProxyById, promoteFreeProxyToPool } from "@/lib/db/freeProxies";
import {
createProxyDispatcher,
proxyConfigToUrl,

View File

@@ -9,7 +9,7 @@ import {
clearFreeProxiesBySource,
getFreeProxyStats,
getFreeProxySyncErrors,
} from "@/lib/localDb";
} from "@/lib/db/freeProxies";
import type { FreeProxySourceId } from "@/lib/freeProxyProviders/types";
export async function GET(request: Request) {

View File

@@ -1,6 +1,6 @@
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
import { createErrorResponseFromUnknown } from "@/lib/api/errorResponse";
import { getFreeProxyStats } from "@/lib/localDb";
import { getFreeProxyStats } from "@/lib/db/freeProxies";
import { getAllProviders } from "@/lib/freeProxyProviders";
import {
isFreeProxyAutoSyncEnabled,

Some files were not shown because too many files have changed in this diff Show More