lynkr 9.4.4 → 9.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lynkr",
3
- "version": "9.4.4",
3
+ "version": "9.4.6",
4
4
  "description": "Self-hosted LLM gateway and tier-routing proxy for Claude Code, Cursor, and Codex. Routes across Ollama, AWS Bedrock, OpenRouter, Databricks, Azure OpenAI, llama.cpp, and LM Studio with prompt caching, MCP tools, and 60-80% cost savings.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -112,59 +112,69 @@ function overview(req, res) {
112
112
  }
113
113
 
114
114
  function usage(req, res) {
115
- const window = req.query.window || '7d';
116
- const provider = req.query.provider || undefined;
117
- const model = req.query.model || undefined;
115
+ try {
116
+ const window = req.query.window || '7d';
117
+ const provider = req.query.provider || undefined;
118
+ const model = req.query.model || undefined;
118
119
 
119
- const data = getUsage({ window, provider, model });
120
+ const data = getUsage({ window, provider, model });
120
121
 
121
- // Add daily breakdown for chart (last 7 or 30 days depending on window)
122
- const days = window === '1d' ? 1 : window === '30d' ? 30 : 7;
123
- const since = window === 'all' ? 0 : Date.now() - days * 86400000;
124
- const rawRows = since > 0
125
- ? telemetry.query({ since, limit: 50000 })
126
- : telemetry.query({ limit: 50000 });
122
+ const days = window === '1d' ? 1 : window === '30d' ? 30 : 7;
123
+ const since = window === 'all' ? 0 : Date.now() - days * 86400000;
124
+ const rawRows = since > 0
125
+ ? telemetry.query({ since, limit: 50000 })
126
+ : telemetry.query({ limit: 50000 });
127
127
 
128
- data.daily = dailyBreakdown(rawRows, Math.min(days, 30));
128
+ data.daily = dailyBreakdown(rawRows, Math.min(days, 30));
129
129
 
130
- res.json(data);
130
+ res.json(data);
131
+ } catch (e) {
132
+ res.status(500).json({ error: 'usage_api_error', detail: e.message });
133
+ }
131
134
  }
132
135
 
133
136
  function routing(req, res) {
134
- const win = findActiveWindow();
135
- const { since } = win;
136
-
137
- const accuracy = telemetry.getRoutingAccuracy({ since });
138
- const stats = telemetry.getStats({ since });
139
- const cbStates = getCircuitBreakerStates();
140
-
141
- // Derive providers from actual DB rows — never miss a provider not in config
142
- const dbRows = telemetry.query({ limit: 100000, since });
143
- const dbProviders = [...new Set(
144
- dbRows.map(r => r.provider).filter(p => p && !TEST_PROVIDER_RE.test(p))
145
- )];
146
-
147
- const providerStats = {};
148
- for (const p of dbProviders) {
149
- const s = telemetry.getProviderStats(p, { since });
150
- if (s) providerStats[p] = s;
151
- }
137
+ try {
138
+ const win = findActiveWindow();
139
+ const { since } = win;
140
+
141
+ const accuracy = telemetry.getRoutingAccuracy({ since });
142
+ const stats = telemetry.getStats({ since });
143
+ const cbStates = getCircuitBreakerStates();
144
+
145
+ const dbRows = telemetry.query({ limit: 100000, since });
146
+ const dbProviders = [...new Set(
147
+ dbRows.map(r => r.provider).filter(p => p && !TEST_PROVIDER_RE.test(p))
148
+ )];
149
+
150
+ const providerStats = {};
151
+ for (const p of dbProviders) {
152
+ const s = telemetry.getProviderStats(p, { since });
153
+ if (s) providerStats[p] = s;
154
+ }
152
155
 
153
- res.json({ tierDefinitions: TIER_DEFINITIONS, accuracy, stats, providerStats, circuitBreakers: cbStates, window: win.label });
156
+ res.json({ tierDefinitions: TIER_DEFINITIONS, accuracy, stats, providerStats, circuitBreakers: cbStates, window: win.label });
157
+ } catch (e) {
158
+ res.status(500).json({ error: 'routing_api_error', detail: e.message });
159
+ }
154
160
  }
155
161
 
156
162
  function logs(req, res) {
157
- const limit = Math.min(parseInt(req.query.limit || '100', 10), 500);
158
- const filters = { limit };
163
+ try {
164
+ const limit = Math.min(parseInt(req.query.limit || '100', 10), 500);
165
+ const filters = { limit };
159
166
 
160
- if (req.query.provider) filters.provider = req.query.provider;
161
- if (req.query.tier) filters.tier = req.query.tier;
162
- if (req.query.since) filters.since = parseInt(req.query.since, 10);
167
+ if (req.query.provider) filters.provider = req.query.provider;
168
+ if (req.query.tier) filters.tier = req.query.tier;
169
+ if (req.query.since) filters.since = parseInt(req.query.since, 10);
163
170
 
164
- let rows = telemetry.query(filters);
165
- if (req.query.error === 'true') rows = rows.filter(r => r.error_type);
171
+ let rows = telemetry.query(filters);
172
+ if (req.query.error === 'true') rows = rows.filter(r => r.error_type);
166
173
 
167
- res.json(rows);
174
+ res.json(rows);
175
+ } catch (e) {
176
+ res.status(500).json({ error: 'logs_api_error', detail: e.message });
177
+ }
168
178
  }
169
179
 
170
180
  module.exports = { overview, usage, routing, logs };
package/src/server.js CHANGED
@@ -68,10 +68,19 @@ if (LAZY_TOOLS_ENABLED) {
68
68
  function createApp() {
69
69
  const app = express();
70
70
  const path = require('path');
71
+ const fs = require('fs');
71
72
 
72
73
  // Dashboard — registered first so it is never shadowed by the main router
73
74
  const DASHBOARD_HTML = path.resolve(__dirname, '../public/dashboard.html');
74
- app.get('/dashboard', (_req, res) => res.sendFile(DASHBOARD_HTML));
75
+ app.get('/dashboard', (_req, res) => {
76
+ try {
77
+ const html = fs.readFileSync(DASHBOARD_HTML, 'utf8');
78
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
79
+ res.send(html);
80
+ } catch (e) {
81
+ res.status(500).json({ error: 'dashboard_read_failed', path: DASHBOARD_HTML, detail: e.message });
82
+ }
83
+ });
75
84
  app.get('/dashboard/api/overview', require('./dashboard/api').overview);
76
85
  app.get('/dashboard/api/usage', require('./dashboard/api').usage);
77
86
  app.get('/dashboard/api/routing', require('./dashboard/api').routing);