Files
OmniRoute/src/lib/db/proxyLogs.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

70 lines
2.9 KiB
TypeScript

/**
* db/proxyLogs.ts — Read queries over the `proxy_logs` table.
* Extracted from the /api/logs/export route handler.
*
* Hard Rule #5: routes must not embed raw SQL — these queries live here so the
* /api/logs/export route can delegate.
*
* NOTE: The SELECT * intentionally returns the historical `public_ip` column,
* NOT `clientIp`. This differs from GET /api/usage/proxy-logs which exposes
* the value as `clientIp`. Callers of the export endpoint should read
* `public_ip`. This inconsistency will be resolved in a future DB migration
* (#2880).
*
* Sliced out of #3500 (proxy_logs cluster, slice 4).
*/
import { getDbInstance } from "./core";
// ---------------------------------------------------------------------------
// Queries
// ---------------------------------------------------------------------------
/**
* Returns all proxy_logs rows with timestamp >= `since`, ordered by timestamp
* descending (most recent first).
*
* @param since - ISO-8601 timestamp lower bound, e.g. "2024-01-01T00:00:00.000Z".
*/
export function exportProxyLogsSince(since: string): Record<string, unknown>[] {
const db = getDbInstance();
const stmt = db.prepare(
"SELECT * FROM proxy_logs WHERE timestamp >= @since ORDER BY timestamp DESC"
);
return stmt.all({ since }) as Record<string, unknown>[];
}
// 24h window for "last known egress IP" lookups. This helper answers a
// different question from proxyEgress.ts (#10677): that module reports which
// connections share an egress IP *right now*, derived from their proxy config
// and a live probe (5 min cache), while the lock needs the IP a connection
// actually *left through* on its recent traffic — history, which only
// proxy_logs holds. Hence a local window constant rather than a dependency.
// Exported so callers can build `since` without duplicating the window.
export const EGRESS_IP_LOOKUP_WINDOW_MS = 24 * 60 * 60 * 1000;
/**
* Last non-null egress IP observed for a connection within the window, or
* null. Best-effort by design: egress_ip is only populated once the egress IP
* has been probed (cache TTL 5 min), so a cold cache yields null and the
* caller must fall back to today's behavior. Synchronous read (#10539 — no
* in-memory cache to go stale). The table has no index on connection_id
* (migration 134, YAGNI); the scan is bounded by the window via
* idx_pl_timestamp and this helper only runs at 429 frequency.
*/
export function getRecentEgressIpForConnection(
connectionId: string,
since: string
): { egressIp: string; at: string } | null {
const db = getDbInstance();
const row = db
.prepare(
`SELECT egress_ip, timestamp FROM proxy_logs
WHERE connection_id = ? AND egress_ip IS NOT NULL AND timestamp >= ?
ORDER BY timestamp DESC LIMIT 1`
)
.get(connectionId, since) as { egress_ip: string; timestamp: string } | undefined;
if (!row) return null;
return { egressIp: row.egress_ip, at: row.timestamp };
}