routstrd 0.3.2 → 0.3.3

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/dist/index.js CHANGED
@@ -2188,7 +2188,7 @@ var init_logger = __esm(() => {
2188
2188
  });
2189
2189
 
2190
2190
  // src/utils/config.ts
2191
- var HOME2, CONFIG_DIR, SOCKET_PATH, PID_FILE, DB_PATH, CONFIG_FILE, LOGS_DIR2, DEFAULT_CONFIG;
2191
+ var HOME2, CONFIG_DIR, SOCKET_PATH, PID_FILE, DB_PATH, CONFIG_FILE, LOGS_DIR2, REQUEST_RESPONSE_LOGS_DIR, DEFAULT_CONFIG;
2192
2192
  var init_config = __esm(() => {
2193
2193
  HOME2 = process.env.HOME || process.env.USERPROFILE || "";
2194
2194
  CONFIG_DIR = process.env.ROUTSTRD_DIR || `${HOME2}/.routstrd`;
@@ -2197,6 +2197,7 @@ var init_config = __esm(() => {
2197
2197
  DB_PATH = `${CONFIG_DIR}/routstr.db`;
2198
2198
  CONFIG_FILE = `${CONFIG_DIR}/config.json`;
2199
2199
  LOGS_DIR2 = `${CONFIG_DIR}/logs`;
2200
+ REQUEST_RESPONSE_LOGS_DIR = `${CONFIG_DIR}/request-response-logs`;
2200
2201
  DEFAULT_CONFIG = {
2201
2202
  port: 8008,
2202
2203
  provider: null,
@@ -13911,42 +13912,30 @@ async function fetchBalance() {
13911
13912
  return null;
13912
13913
  }
13913
13914
  }
13914
- async function fetchUsage(limit = 1e4) {
13915
+ async function fetchUsageSummary() {
13915
13916
  try {
13916
13917
  const running = await isDaemonRunning();
13917
13918
  if (!running)
13918
13919
  return null;
13919
- const result = await callDaemon(`/usage?limit=${limit}`);
13920
+ const tz = new Date().getTimezoneOffset();
13921
+ const result = await callDaemon(`/usage/summary?tz=${tz}`);
13920
13922
  if (result.error)
13921
13923
  return null;
13922
- const entries = result.output;
13923
- const visibleEntries = Array.isArray(entries) ? entries : [];
13924
- const totals = visibleEntries.reduce((acc, entry) => ({
13925
- promptTokens: acc.promptTokens + entry.promptTokens,
13926
- completionTokens: acc.completionTokens + entry.completionTokens,
13927
- totalTokens: acc.totalTokens + entry.totalTokens,
13928
- satsCost: acc.satsCost + entry.satsCost
13929
- }), { promptTokens: 0, completionTokens: 0, totalTokens: 0, satsCost: 0 });
13924
+ const summary = result.output;
13925
+ if (!summary || typeof summary.totals !== "object")
13926
+ return null;
13930
13927
  return {
13931
- entries: visibleEntries,
13932
- totalEntries: visibleEntries.length,
13933
- totalSatsCost: totals.satsCost,
13934
- recentSatsCost: totals.satsCost,
13935
- limit
13928
+ entries: summary.recent,
13929
+ totalEntries: summary.totals.requests,
13930
+ totalSatsCost: summary.totals.satsCost,
13931
+ recentSatsCost: summary.totals.satsCost,
13932
+ limit: 50,
13933
+ summary
13936
13934
  };
13937
13935
  } catch {
13938
13936
  return null;
13939
13937
  }
13940
13938
  }
13941
- function getTodayStart() {
13942
- const now2 = new Date;
13943
- return new Date(now2.getFullYear(), now2.getMonth(), now2.getDate()).getTime();
13944
- }
13945
- function formatDate(timestamp) {
13946
- const d = new Date(timestamp);
13947
- const p = (n) => String(n).padStart(2, "0");
13948
- return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
13949
- }
13950
13939
  function formatTime(timestamp) {
13951
13940
  const d = new Date(timestamp);
13952
13941
  const p = (n) => String(n).padStart(2, "0");
@@ -13959,116 +13948,6 @@ function formatNumber(n) {
13959
13948
  return (n / 1000).toFixed(1) + "K";
13960
13949
  return n.toString();
13961
13950
  }
13962
- function getDayStats(entries) {
13963
- const days = new Map;
13964
- for (const entry of entries) {
13965
- const date = formatDate(entry.timestamp);
13966
- const existing = days.get(date) || { date, requests: 0, satsCost: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0 };
13967
- days.set(date, {
13968
- ...existing,
13969
- requests: existing.requests + 1,
13970
- satsCost: existing.satsCost + entry.satsCost,
13971
- promptTokens: existing.promptTokens + entry.promptTokens,
13972
- completionTokens: existing.completionTokens + entry.completionTokens,
13973
- totalTokens: existing.totalTokens + entry.totalTokens
13974
- });
13975
- }
13976
- return days;
13977
- }
13978
- function getHourlyToday(entries) {
13979
- const todayStart = getTodayStart();
13980
- const hours = new Map;
13981
- for (const entry of entries) {
13982
- if (entry.timestamp < todayStart)
13983
- continue;
13984
- const hour = new Date(entry.timestamp).getHours();
13985
- const existing = hours.get(hour) || {
13986
- date: formatDate(entry.timestamp),
13987
- requests: 0,
13988
- satsCost: 0,
13989
- promptTokens: 0,
13990
- completionTokens: 0,
13991
- totalTokens: 0
13992
- };
13993
- hours.set(hour, {
13994
- ...existing,
13995
- requests: existing.requests + 1,
13996
- satsCost: existing.satsCost + entry.satsCost,
13997
- promptTokens: existing.promptTokens + entry.promptTokens,
13998
- completionTokens: existing.completionTokens + entry.completionTokens,
13999
- totalTokens: existing.totalTokens + entry.totalTokens
14000
- });
14001
- }
14002
- return hours;
14003
- }
14004
- function getModelStats(entries) {
14005
- const models = new Map;
14006
- for (const entry of entries) {
14007
- const existing = models.get(entry.modelId) || {
14008
- modelId: entry.modelId,
14009
- requests: 0,
14010
- satsCost: 0,
14011
- promptTokens: 0,
14012
- completionTokens: 0,
14013
- totalTokens: 0
14014
- };
14015
- models.set(entry.modelId, {
14016
- ...existing,
14017
- requests: existing.requests + 1,
14018
- satsCost: existing.satsCost + entry.satsCost,
14019
- promptTokens: existing.promptTokens + entry.promptTokens,
14020
- completionTokens: existing.completionTokens + entry.completionTokens,
14021
- totalTokens: existing.totalTokens + entry.totalTokens
14022
- });
14023
- }
14024
- return Array.from(models.values()).sort((a, b) => b.satsCost - a.satsCost);
14025
- }
14026
- function getProviderStats(entries) {
14027
- const providers = new Map;
14028
- for (const entry of entries) {
14029
- const url = entry.baseUrl || "unknown";
14030
- const existing = providers.get(url) || {
14031
- baseUrl: url,
14032
- requests: 0,
14033
- satsCost: 0,
14034
- promptTokens: 0,
14035
- completionTokens: 0,
14036
- totalTokens: 0
14037
- };
14038
- providers.set(url, {
14039
- ...existing,
14040
- requests: existing.requests + 1,
14041
- satsCost: existing.satsCost + entry.satsCost,
14042
- promptTokens: existing.promptTokens + entry.promptTokens,
14043
- completionTokens: existing.completionTokens + entry.completionTokens,
14044
- totalTokens: existing.totalTokens + entry.totalTokens
14045
- });
14046
- }
14047
- return Array.from(providers.values()).sort((a, b) => b.satsCost - a.satsCost);
14048
- }
14049
- function getClientStats(entries) {
14050
- const clients = new Map;
14051
- for (const entry of entries) {
14052
- const client = entry.client || "unknown";
14053
- const existing = clients.get(client) || {
14054
- client,
14055
- requests: 0,
14056
- satsCost: 0,
14057
- promptTokens: 0,
14058
- completionTokens: 0,
14059
- totalTokens: 0
14060
- };
14061
- clients.set(client, {
14062
- ...existing,
14063
- requests: existing.requests + 1,
14064
- satsCost: existing.satsCost + entry.satsCost,
14065
- promptTokens: existing.promptTokens + entry.promptTokens,
14066
- completionTokens: existing.completionTokens + entry.completionTokens,
14067
- totalTokens: existing.totalTokens + entry.totalTokens
14068
- });
14069
- }
14070
- return Array.from(clients.values()).sort((a, b) => b.satsCost - a.satsCost);
14071
- }
14072
13951
  async function fetchClients() {
14073
13952
  try {
14074
13953
  const running = await isDaemonRunning();
@@ -14090,48 +13969,6 @@ async function fetchClients() {
14090
13969
  function hasAnyNpubs(clients) {
14091
13970
  return clients.some((c) => !!c.ownerNpub);
14092
13971
  }
14093
- function getNpubStats(entries, clients) {
14094
- const clientNpubMap = new Map;
14095
- for (const c of clients) {
14096
- if (c.ownerNpub) {
14097
- clientNpubMap.set(c.clientId, c.ownerNpub);
14098
- }
14099
- }
14100
- const npubs = new Map;
14101
- for (const entry of entries) {
14102
- const npub = clientNpubMap.get(entry.client || "");
14103
- if (!npub)
14104
- continue;
14105
- const existing = npubs.get(npub) || {
14106
- npub,
14107
- requests: 0,
14108
- satsCost: 0,
14109
- promptTokens: 0,
14110
- completionTokens: 0,
14111
- totalTokens: 0
14112
- };
14113
- npubs.set(npub, {
14114
- ...existing,
14115
- requests: existing.requests + 1,
14116
- satsCost: existing.satsCost + entry.satsCost,
14117
- promptTokens: existing.promptTokens + entry.promptTokens,
14118
- completionTokens: existing.completionTokens + entry.completionTokens,
14119
- totalTokens: existing.totalTokens + entry.totalTokens
14120
- });
14121
- }
14122
- return Array.from(npubs.values()).sort((a, b) => b.satsCost - a.satsCost);
14123
- }
14124
- function getTotals(entries) {
14125
- if (!entries || !Array.isArray(entries)) {
14126
- return { promptTokens: 0, completionTokens: 0, totalTokens: 0, satsCost: 0 };
14127
- }
14128
- return entries.reduce((acc, entry) => ({
14129
- promptTokens: acc.promptTokens + entry.promptTokens,
14130
- completionTokens: acc.completionTokens + entry.completionTokens,
14131
- totalTokens: acc.totalTokens + entry.totalTokens,
14132
- satsCost: acc.satsCost + entry.satsCost
14133
- }), { promptTokens: 0, completionTokens: 0, totalTokens: 0, satsCost: 0 });
14134
- }
14135
13972
  var init_data = __esm(() => {
14136
13973
  init_daemon_client();
14137
13974
  });
@@ -14331,7 +14168,7 @@ function renderBarChart(label, value, maxValue, width, color, percentageValue, s
14331
14168
  return `${paddedLabel} ${bar}${suffix}`;
14332
14169
  }
14333
14170
  function renderOverview(stats, balance, status, width) {
14334
- const totals = getTotals(stats.entries);
14171
+ const totals = stats.summary.totals;
14335
14172
  const totalRequests = stats.totalEntries;
14336
14173
  const totalVisibleCost = stats.totalSatsCost;
14337
14174
  const avgCost = totalRequests > 0 ? totalVisibleCost / totalRequests : 0;
@@ -14440,7 +14277,7 @@ function renderOverview(stats, balance, status, width) {
14440
14277
  output = renderBox(statusLines, width, "System Status") + `
14441
14278
  ` + output;
14442
14279
  }
14443
- const modelStats = getModelStats(stats.entries);
14280
+ const modelStats = stats.summary.models;
14444
14281
  if (modelStats.length > 0) {
14445
14282
  const maxCost = modelStats[0].satsCost;
14446
14283
  const totalCost = Math.max(totalVisibleCost, 1);
@@ -14451,7 +14288,7 @@ function renderOverview(stats, balance, status, width) {
14451
14288
  output += `
14452
14289
  ` + renderBox(modelLines, width, "Top Models by Cost");
14453
14290
  }
14454
- const clientStats = getClientStats(stats.entries);
14291
+ const clientStats = stats.summary.clients;
14455
14292
  if (clientStats.length > 0) {
14456
14293
  const maxCost = clientStats[0].satsCost;
14457
14294
  const totalCost = Math.max(totalVisibleCost, 1);
@@ -14465,18 +14302,18 @@ function renderOverview(stats, balance, status, width) {
14465
14302
  return output;
14466
14303
  }
14467
14304
  function renderToday(stats, width) {
14468
- const hourly = getHourlyToday(stats.entries);
14469
- const todayStart = getTodayStart();
14470
14305
  const currentHour = new Date().getHours();
14471
- const todayStats = { date: formatDate(Date.now()), requests: 0, satsCost: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0 };
14472
- for (const entry of stats.entries) {
14473
- if (entry.timestamp >= todayStart) {
14474
- todayStats.requests++;
14475
- todayStats.satsCost += entry.satsCost;
14476
- todayStats.promptTokens += entry.promptTokens;
14477
- todayStats.completionTokens += entry.completionTokens;
14478
- todayStats.totalTokens += entry.totalTokens;
14479
- }
14306
+ const _now = new Date;
14307
+ const todayDateStr = `${_now.getFullYear()}-${String(_now.getMonth() + 1).padStart(2, "0")}-${String(_now.getDate()).padStart(2, "0")}`;
14308
+ let todayStats;
14309
+ let recentDays;
14310
+ let hourlyMap;
14311
+ if (stats.summary) {
14312
+ const { days, hoursToday } = stats.summary;
14313
+ const todayDayStat = days[0]?.date === todayDateStr ? days[0] : undefined;
14314
+ todayStats = todayDayStat ? { date: todayDayStat.date, requests: todayDayStat.requests, satsCost: todayDayStat.satsCost, promptTokens: todayDayStat.promptTokens, completionTokens: todayDayStat.completionTokens, totalTokens: todayDayStat.totalTokens } : { date: todayDateStr, requests: 0, satsCost: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0 };
14315
+ recentDays = days.filter((d) => d.date !== todayDateStr).slice(0, 6);
14316
+ hourlyMap = new Map(hoursToday.map((h) => [h.hour, { requests: h.requests, satsCost: h.satsCost }]));
14480
14317
  }
14481
14318
  const summaryLines = [
14482
14319
  `${COLORS.bold}Date:${COLORS.reset} ${todayStats.date}`,
@@ -14485,18 +14322,17 @@ function renderToday(stats, width) {
14485
14322
  `${COLORS.bold}Tokens:${COLORS.reset} ${formatNumber(todayStats.totalTokens)} (p: ${formatNumber(todayStats.promptTokens)} + c: ${formatNumber(todayStats.completionTokens)})`
14486
14323
  ];
14487
14324
  let output = renderBox(summaryLines, width, "Today");
14488
- const days = Array.from(getDayStats(stats.entries).values()).slice(0, 7);
14489
- if (days.length > 1) {
14490
- const dayLines = days.slice(1).map((d) => `${d.date}: ${formatReqs(d.requests)} req, ${formatCost(d.satsCost)} sats, ${formatNumber(d.totalTokens)} tokens`);
14325
+ if (recentDays.length > 0) {
14326
+ const dayLines = recentDays.map((d) => `${d.date}: ${formatReqs(d.requests)} req, ${formatCost(d.satsCost)} sats, ${formatNumber(d.totalTokens)} tokens`);
14491
14327
  output += `
14492
14328
  ` + renderBox(dayLines, width, "Recent Days");
14493
14329
  }
14494
14330
  const hourLines = [];
14495
- const maxHourCost = Math.max(...Array.from(hourly.values()).map((h) => h.satsCost), 1);
14331
+ const maxHourCost = Math.max(...Array.from(hourlyMap.values()).map((h) => h.satsCost), 1);
14496
14332
  const totalTodayCost = Math.max(todayStats.satsCost, 1);
14497
14333
  const hourLabels = [];
14498
14334
  for (let h = currentHour;h >= 0; h--) {
14499
- const hStat = hourly.get(h);
14335
+ const hStat = hourlyMap.get(h);
14500
14336
  const reqs = hStat?.requests || 0;
14501
14337
  const cost = hStat?.satsCost || 0;
14502
14338
  hourLabels.push(`${h.toString().padStart(2, "0")}:00 (${formatReqs(reqs)} req, ${formatCost(cost)} sats) `);
@@ -14504,7 +14340,7 @@ function renderToday(stats, width) {
14504
14340
  const maxHourLabel = Math.max(...hourLabels.map((l) => l.length));
14505
14341
  startBarSection("hourly", maxHourLabel);
14506
14342
  for (let i2 = currentHour;i2 >= 0; i2--) {
14507
- const hStat = hourly.get(i2);
14343
+ const hStat = hourlyMap.get(i2);
14508
14344
  const reqs = hStat?.requests || 0;
14509
14345
  const cost = hStat?.satsCost || 0;
14510
14346
  hourLines.push(renderBarChart(hourLabels[currentHour - i2], cost, maxHourCost, width - 4, i2 === currentHour ? COLORS.green : COLORS.cyan, cost / totalTodayCost * 100, "hourly"));
@@ -14515,7 +14351,7 @@ function renderToday(stats, width) {
14515
14351
  return output;
14516
14352
  }
14517
14353
  function renderModels(stats, width) {
14518
- const modelStats = getModelStats(stats.entries);
14354
+ const modelStats = stats.summary.models;
14519
14355
  if (modelStats.length === 0)
14520
14356
  return renderBox(["No model data available"], width, "Models");
14521
14357
  const totalCost = stats.totalSatsCost;
@@ -14538,7 +14374,7 @@ function renderModels(stats, width) {
14538
14374
  return renderBox(lines, width, "Model Breakdown");
14539
14375
  }
14540
14376
  function renderProviders(stats, width) {
14541
- const providerStats = getProviderStats(stats.entries);
14377
+ const providerStats = stats.summary.providers;
14542
14378
  if (providerStats.length === 0)
14543
14379
  return renderBox(["No provider data available"], width, "Providers");
14544
14380
  const lines = [];
@@ -14553,8 +14389,8 @@ function renderProviders(stats, width) {
14553
14389
  return renderBox(lines, width, "Provider Breakdown");
14554
14390
  }
14555
14391
  function renderTokens(stats, width) {
14556
- const totals = getTotals(stats.entries);
14557
- const modelStats = getModelStats(stats.entries);
14392
+ const totals = stats.summary.totals;
14393
+ const modelStats = stats.summary.models;
14558
14394
  const summaryLines = [
14559
14395
  `${COLORS.bold}Total Prompt Tokens:${COLORS.reset} ${formatNumber(totals.promptTokens)}`,
14560
14396
  `${COLORS.bold}Total Completion Tokens:${COLORS.reset} ${formatNumber(totals.completionTokens)}`,
@@ -14572,29 +14408,14 @@ function renderTokens(stats, width) {
14572
14408
  output += `
14573
14409
  ` + renderBox(tokenLines, width, "Tokens by Model");
14574
14410
  }
14575
- const sizeBuckets = {
14576
- tiny: { min: 0, max: 1000, count: 0, cost: 0 },
14577
- small: { min: 1000, max: 1e4, count: 0, cost: 0 },
14578
- medium: { min: 1e4, max: 50000, count: 0, cost: 0 },
14579
- large: { min: 50000, max: 1e5, count: 0, cost: 0 },
14580
- huge: { min: 1e5, max: Infinity, count: 0, cost: 0 }
14581
- };
14582
- for (const entry of stats.entries) {
14583
- for (const bucket of Object.values(sizeBuckets)) {
14584
- if (entry.totalTokens >= bucket.min && entry.totalTokens < bucket.max) {
14585
- bucket.count++;
14586
- bucket.cost += entry.satsCost;
14587
- break;
14588
- }
14589
- }
14590
- }
14411
+ const sizeBuckets = stats.summary.sizeBuckets;
14591
14412
  const sizeLines = Object.entries(sizeBuckets).map(([name, bucket]) => `${name.padEnd(6)}: ${formatReqs(bucket.count).padStart(5)} reqs, ${formatCost(bucket.cost)} sats`);
14592
14413
  output += `
14593
14414
  ` + renderBox(sizeLines, width, "Request Size Distribution");
14594
14415
  return output;
14595
14416
  }
14596
14417
  function renderClients(stats, width) {
14597
- const clientStats = getClientStats(stats.entries);
14418
+ const clientStats = stats.summary.clients;
14598
14419
  if (clientStats.length === 0)
14599
14420
  return renderBox(["No client data available (API key auth not used)"], width, "Client Breakdown");
14600
14421
  const totalCost = stats.totalSatsCost;
@@ -14626,31 +14447,17 @@ function renderClients(stats, width) {
14626
14447
  }
14627
14448
  endBarSection("client-detail");
14628
14449
  let output = renderBox(lines, width, "Client Breakdown");
14629
- const clientModelMap = new Map;
14630
- for (const entry of stats.entries) {
14631
- const client = entry.client || "unknown";
14632
- const model = entry.modelId;
14633
- if (!clientModelMap.has(client))
14634
- clientModelMap.set(client, new Map);
14635
- const modelMap = clientModelMap.get(client);
14636
- const existing = modelMap.get(model) || { requests: 0, satsCost: 0, tokens: 0 };
14637
- modelMap.set(model, {
14638
- requests: existing.requests + 1,
14639
- satsCost: existing.satsCost + entry.satsCost,
14640
- tokens: existing.tokens + entry.totalTokens
14641
- });
14642
- }
14643
14450
  const clientModelLines = [];
14644
- for (const topClient of clientStats.slice(0, 3)) {
14645
- const modelMap = clientModelMap.get(topClient.client);
14646
- if (!modelMap)
14647
- continue;
14648
- const models = Array.from(modelMap.entries()).sort((a, b) => b[1].satsCost - a[1].satsCost).slice(0, 5);
14649
- clientModelLines.push(`${COLORS.bold}${topClient.client}${COLORS.reset} (${formatReqs(topClient.requests)} reqs, ${formatCost(topClient.satsCost)} sats)`);
14650
- for (const [model, data] of models) {
14651
- clientModelLines.push(` ${MODEL_COLORS[model] || MODEL_COLORS.default}${model.padEnd(18)}${COLORS.reset} ${formatNumber(data.tokens).padEnd(8)} tokens ${formatCost(data.satsCost)} sats`);
14451
+ if (stats.summary) {
14452
+ for (const topClient of stats.summary.clients.filter((c) => c.client !== "unknown").slice(0, 3)) {
14453
+ if (topClient.topModels.length === 0)
14454
+ continue;
14455
+ clientModelLines.push(`${COLORS.bold}${topClient.client}${COLORS.reset} (${formatReqs(topClient.requests)} reqs, ${formatCost(topClient.satsCost)} sats)`);
14456
+ for (const m of topClient.topModels) {
14457
+ clientModelLines.push(` ${MODEL_COLORS[m.modelId] || MODEL_COLORS.default}${m.modelId.padEnd(18)}${COLORS.reset} ${formatNumber(m.totalTokens).padEnd(8)} tokens ${formatCost(m.satsCost)} sats`);
14458
+ }
14459
+ clientModelLines.push("");
14652
14460
  }
14653
- clientModelLines.push("");
14654
14461
  }
14655
14462
  if (clientModelLines.length > 0) {
14656
14463
  output += `
@@ -14659,7 +14466,7 @@ function renderClients(stats, width) {
14659
14466
  return output;
14660
14467
  }
14661
14468
  function renderNpubs(stats, clients, width) {
14662
- const npubStats = getNpubStats(stats.entries, clients);
14469
+ const npubStats = stats.summary.npubs;
14663
14470
  if (npubStats.length === 0)
14664
14471
  return renderBox(["No npub data available"], width, "Npub Breakdown");
14665
14472
  const totalCost = stats.totalSatsCost;
@@ -14692,38 +14499,17 @@ function renderNpubs(stats, clients, width) {
14692
14499
  }
14693
14500
  endBarSection("npub-detail");
14694
14501
  let output = renderBox(lines, width, "Npub Breakdown");
14695
- const npubModelMap = new Map;
14696
- const clientNpubMap = new Map;
14697
- for (const c of clients) {
14698
- if (c.ownerNpub)
14699
- clientNpubMap.set(c.clientId, c.ownerNpub);
14700
- }
14701
- for (const entry of stats.entries) {
14702
- const npub = clientNpubMap.get(entry.client || "");
14703
- if (!npub)
14704
- continue;
14705
- const model = entry.modelId;
14706
- if (!npubModelMap.has(npub))
14707
- npubModelMap.set(npub, new Map);
14708
- const modelMap = npubModelMap.get(npub);
14709
- const existing = modelMap.get(model) || { requests: 0, satsCost: 0, tokens: 0 };
14710
- modelMap.set(model, {
14711
- requests: existing.requests + 1,
14712
- satsCost: existing.satsCost + entry.satsCost,
14713
- tokens: existing.tokens + entry.totalTokens
14714
- });
14715
- }
14716
14502
  const npubModelLines = [];
14717
- for (const topNpub of npubStats.slice(0, 5)) {
14718
- const modelMap = npubModelMap.get(topNpub.npub);
14719
- if (!modelMap)
14720
- continue;
14721
- const models = Array.from(modelMap.entries()).sort((a, b) => b[1].satsCost - a[1].satsCost).slice(0, 5);
14722
- npubModelLines.push(`${COLORS.bold}${truncateNpub(topNpub.npub)}${COLORS.reset} (${formatReqs(topNpub.requests)} reqs, ${formatCost(topNpub.satsCost)} sats)`);
14723
- for (const [model, data] of models) {
14724
- npubModelLines.push(` ${MODEL_COLORS[model] || MODEL_COLORS.default}${model.padEnd(18)}${COLORS.reset} ${formatNumber(data.tokens).padEnd(8)} tokens ${formatCost(data.satsCost)} sats`);
14503
+ if (stats.summary) {
14504
+ for (const topNpub of stats.summary.npubs.slice(0, 5)) {
14505
+ if (topNpub.topModels.length === 0)
14506
+ continue;
14507
+ npubModelLines.push(`${COLORS.bold}${truncateNpub(topNpub.npub)}${COLORS.reset} (${formatReqs(topNpub.requests)} reqs, ${formatCost(topNpub.satsCost)} sats)`);
14508
+ for (const m of topNpub.topModels) {
14509
+ npubModelLines.push(` ${MODEL_COLORS[m.modelId] || MODEL_COLORS.default}${m.modelId.padEnd(18)}${COLORS.reset} ${formatNumber(m.totalTokens).padEnd(8)} tokens ${formatCost(m.satsCost)} sats`);
14510
+ }
14511
+ npubModelLines.push("");
14725
14512
  }
14726
- npubModelLines.push("");
14727
14513
  }
14728
14514
  if (npubModelLines.length > 0) {
14729
14515
  output += `
@@ -14855,7 +14641,7 @@ async function runUsageTui() {
14855
14641
  const width = getWidth();
14856
14642
  const height = getHeight();
14857
14643
  if (forceFetch || shouldUpdate) {
14858
- stats = await fetchUsage(1e4);
14644
+ stats = await fetchUsageSummary();
14859
14645
  balance = await fetchBalance();
14860
14646
  status = await fetchStatus();
14861
14647
  clients = await fetchClients();
@@ -15802,7 +15588,7 @@ async function isCocodInstalled(cocodPath) {
15802
15588
  // package.json
15803
15589
  var package_default = {
15804
15590
  name: "routstrd",
15805
- version: "0.3.2",
15591
+ version: "0.3.3",
15806
15592
  module: "src/index.ts",
15807
15593
  type: "module",
15808
15594
  private: false,
@@ -15826,7 +15612,7 @@ var package_default = {
15826
15612
  },
15827
15613
  dependencies: {
15828
15614
  "@cashu/cashu-ts": "^4.3.0",
15829
- "@routstr/sdk": "^0.3.10",
15615
+ "@routstr/sdk": "^0.3.11",
15830
15616
  "applesauce-core": "^5.1.0",
15831
15617
  "applesauce-relay": "^5.1.0",
15832
15618
  "applesauce-wallet-connect": "^6.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "routstrd",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "module": "src/index.ts",
5
5
  "type": "module",
6
6
  "private": false,
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@cashu/cashu-ts": "^4.3.0",
27
- "@routstr/sdk": "^0.3.10",
27
+ "@routstr/sdk": "^0.3.11",
28
28
  "applesauce-core": "^5.1.0",
29
29
  "applesauce-relay": "^5.1.0",
30
30
  "applesauce-wallet-connect": "^6.0.0",