@antseed/dashboard 0.1.1

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.
Files changed (45) hide show
  1. package/README.md +45 -0
  2. package/dist/api/routes.d.ts +84 -0
  3. package/dist/api/routes.d.ts.map +1 -0
  4. package/dist/api/routes.js +454 -0
  5. package/dist/api/routes.js.map +1 -0
  6. package/dist/api/routes.test.d.ts +2 -0
  7. package/dist/api/routes.test.d.ts.map +1 -0
  8. package/dist/api/routes.test.js +77 -0
  9. package/dist/api/routes.test.js.map +1 -0
  10. package/dist/api/websocket.d.ts +25 -0
  11. package/dist/api/websocket.d.ts.map +1 -0
  12. package/dist/api/websocket.js +51 -0
  13. package/dist/api/websocket.js.map +1 -0
  14. package/dist/config-io.d.ts +7 -0
  15. package/dist/config-io.d.ts.map +1 -0
  16. package/dist/config-io.js +22 -0
  17. package/dist/config-io.js.map +1 -0
  18. package/dist/dht-query-service.d.ts +52 -0
  19. package/dist/dht-query-service.d.ts.map +1 -0
  20. package/dist/dht-query-service.js +276 -0
  21. package/dist/dht-query-service.js.map +1 -0
  22. package/dist/dht-query-service.test.d.ts +2 -0
  23. package/dist/dht-query-service.test.d.ts.map +1 -0
  24. package/dist/dht-query-service.test.js +77 -0
  25. package/dist/dht-query-service.test.js.map +1 -0
  26. package/dist/index.d.ts +7 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +4 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/server.d.ts +20 -0
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +65 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/status.d.ts +9 -0
  35. package/dist/status.d.ts.map +1 -0
  36. package/dist/status.js +97 -0
  37. package/dist/status.js.map +1 -0
  38. package/dist/types.d.ts +76 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +2 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist-web/assets/index-CsvLvJ8Z.css +1 -0
  43. package/dist-web/assets/index-Da6V1FWz.js +142 -0
  44. package/dist-web/index.html +13 -0
  45. package/package.json +43 -0
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # antseed-dashboard
2
+
3
+ Web dashboard for monitoring and configuring an Antseed node. Provides real-time status, peer discovery, and session tracking via a Fastify server with WebSocket support.
4
+
5
+ ## Usage
6
+
7
+ The dashboard is typically started through the CLI:
8
+
9
+ ```bash
10
+ antseed dashboard
11
+ ```
12
+
13
+ Or programmatically:
14
+
15
+ ```ts
16
+ import { createDashboardServer } from 'antseed-dashboard';
17
+
18
+ const server = await createDashboardServer({
19
+ port: 3000,
20
+ node: antseedNode,
21
+ });
22
+ ```
23
+
24
+ ## Key Exports
25
+
26
+ - `createDashboardServer()` -- Creates and configures the Fastify server
27
+ - `getNodeStatus()` -- Retrieve current node status
28
+ - `broadcastEvent()` -- Broadcast events to connected WebSocket clients
29
+ - `getConnectedClientCount()` -- Count active WebSocket connections
30
+
31
+ ## Architecture
32
+
33
+ - **Server**: Fastify with CORS, static file serving, and WebSocket support
34
+ - **API Routes**: RESTful endpoints for node status, peer info, and configuration
35
+ - **WebSocket**: Real-time event streaming to the frontend
36
+ - **DHT Queries**: Service layer for DHT peer discovery
37
+ - **Frontend**: Separate React app in `web/` (built with `npm run build:web`)
38
+
39
+ ## Development
40
+
41
+ ```bash
42
+ pnpm run build # Build server
43
+ pnpm run build:web # Build frontend (cd web && npm install && npm run build)
44
+ pnpm run build:all # Build both
45
+ ```
@@ -0,0 +1,84 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ import type { DashboardConfig, NodeStatus } from '../types.js';
3
+ import type { DHTQueryService, NetworkPeer, NetworkStats } from '../dht-query-service.js';
4
+ /** Internal readiness model for data sources */
5
+ export interface DataSourceReadiness {
6
+ meteringDbAvailable: boolean;
7
+ daemonStateAvailable: boolean;
8
+ degradedReasons: string[];
9
+ }
10
+ /** PeerInfo type for API responses */
11
+ export interface PeerInfo {
12
+ peerId: string;
13
+ providers: string[];
14
+ capacityMsgPerHour: number;
15
+ inputUsdPerMillion: number;
16
+ outputUsdPerMillion: number;
17
+ reputation: number;
18
+ location: string | null;
19
+ source?: 'daemon' | 'dht';
20
+ }
21
+ /** SessionMetrics type for API responses */
22
+ export interface SessionMetrics {
23
+ sessionId: string;
24
+ provider: string;
25
+ startedAt: number;
26
+ totalTokens: number;
27
+ totalRequests: number;
28
+ durationMs: number;
29
+ avgLatencyMs: number;
30
+ peerSwitches: number;
31
+ }
32
+ /** Response type for GET /api/status */
33
+ export interface StatusResponse extends NodeStatus {
34
+ }
35
+ /** Response type for GET /api/peers */
36
+ export interface PeersResponse {
37
+ peers: PeerInfo[];
38
+ total: number;
39
+ degraded: boolean;
40
+ }
41
+ /** Response type for GET /api/sessions */
42
+ export interface SessionsResponse {
43
+ sessions: SessionMetrics[];
44
+ total: number;
45
+ degraded: boolean;
46
+ }
47
+ /** Response type for GET /api/earnings */
48
+ export interface EarningsResponse {
49
+ today: string;
50
+ thisWeek: string;
51
+ thisMonth: string;
52
+ /** Daily earnings for chart data: { date: "2026-02-16", amount: "1.23" }[] */
53
+ daily: Array<{
54
+ date: string;
55
+ amount: string;
56
+ }>;
57
+ /** Per-provider breakdown: { provider: "anthropic", amount: "5.00" }[] */
58
+ byProvider: Array<{
59
+ provider: string;
60
+ amount: string;
61
+ }>;
62
+ degraded: boolean;
63
+ }
64
+ /** Response type for GET /api/config */
65
+ export interface ConfigResponse {
66
+ config: DashboardConfig;
67
+ }
68
+ /** Response type for GET /api/data-sources */
69
+ export interface DataSourcesResponse {
70
+ meteringDbAvailable: boolean;
71
+ daemonStateAvailable: boolean;
72
+ degradedReasons: string[];
73
+ timestamp: string;
74
+ }
75
+ /** Response type for GET /api/network */
76
+ export interface NetworkResponse {
77
+ peers: NetworkPeer[];
78
+ stats: NetworkStats;
79
+ }
80
+ /**
81
+ * Register all dashboard API routes on the Fastify instance.
82
+ */
83
+ export declare function registerApiRoutes(app: FastifyInstance, config: DashboardConfig, dhtQueryService?: DHTQueryService, configPath?: string): Promise<void>;
84
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ/D,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE1F,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AA6BD,sCAAsC;AACtC,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;CAC3B;AAED,4CAA4C;AAC5C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wCAAwC;AACxC,MAAM,WAAW,cAAe,SAAQ,UAAU;CAAG;AAErD,uCAAuC;AACvC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,0EAA0E;IAC1E,UAAU,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wCAAwC;AACxC,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,yCAAyC;AACzC,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,eAAe,EACvB,eAAe,CAAC,EAAE,eAAe,EACjC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CA2Mf"}
@@ -0,0 +1,454 @@
1
+ import { getNodeStatus } from '../status.js';
2
+ import { saveConfig } from '../config-io.js';
3
+ import { MeteringStorage } from '@antseed/node';
4
+ import { UsageAggregator } from '@antseed/node/metering';
5
+ import { join } from 'node:path';
6
+ import { homedir } from 'node:os';
7
+ import { readFile } from 'node:fs/promises';
8
+ /** Compute readiness state based on data source availability */
9
+ function computeReadiness(storage, daemonStateAvailable, meteringDbError = null) {
10
+ const degradedReasons = [];
11
+ const meteringDbAvailable = storage !== null;
12
+ if (!meteringDbAvailable) {
13
+ if (meteringDbError && meteringDbError.trim().length > 0) {
14
+ degradedReasons.push(`Metering database is unavailable: ${meteringDbError}`);
15
+ }
16
+ else {
17
+ degradedReasons.push('Metering database is unavailable');
18
+ }
19
+ }
20
+ if (!daemonStateAvailable) {
21
+ degradedReasons.push('Daemon state file is unavailable');
22
+ }
23
+ return {
24
+ meteringDbAvailable,
25
+ daemonStateAvailable,
26
+ degradedReasons,
27
+ };
28
+ }
29
+ /**
30
+ * Register all dashboard API routes on the Fastify instance.
31
+ */
32
+ export async function registerApiRoutes(app, config, dhtQueryService, configPath) {
33
+ const dbPath = join(homedir(), '.antseed', 'metering.db');
34
+ let storage = null;
35
+ let meteringDbError = null;
36
+ try {
37
+ storage = new MeteringStorage(dbPath);
38
+ }
39
+ catch (err) {
40
+ meteringDbError = err instanceof Error ? err.message : String(err);
41
+ // Metering DB not available — degraded mode will be used
42
+ }
43
+ const aggregator = new UsageAggregator();
44
+ // Check daemon state availability at startup
45
+ const stateFile = join(homedir(), '.antseed', 'daemon.state.json');
46
+ let daemonStateAvailable = false;
47
+ try {
48
+ await readFile(stateFile, 'utf-8');
49
+ daemonStateAvailable = true;
50
+ }
51
+ catch {
52
+ // Daemon state file not available
53
+ }
54
+ // Compute initial readiness
55
+ let readiness = computeReadiness(storage, daemonStateAvailable, meteringDbError);
56
+ // GET /api/status - Current node status
57
+ app.get('/api/status', async (_req, reply) => {
58
+ try {
59
+ const status = await getNodeStatus(config);
60
+ return reply.send(status);
61
+ }
62
+ catch (err) {
63
+ return reply.code(500).send({ error: `Failed to get status: ${err.message}` });
64
+ }
65
+ });
66
+ // GET /api/data-sources - Data source health
67
+ app.get('/api/data-sources', async (_req, reply) => {
68
+ // Refresh daemon state availability on each request
69
+ let currentDaemonStateAvailable = false;
70
+ try {
71
+ await readFile(stateFile, 'utf-8');
72
+ currentDaemonStateAvailable = true;
73
+ }
74
+ catch {
75
+ // Daemon state file not available
76
+ }
77
+ daemonStateAvailable = currentDaemonStateAvailable;
78
+ readiness = computeReadiness(storage, daemonStateAvailable, meteringDbError);
79
+ return reply.send({
80
+ meteringDbAvailable: readiness.meteringDbAvailable,
81
+ daemonStateAvailable: readiness.daemonStateAvailable,
82
+ degradedReasons: readiness.degradedReasons,
83
+ timestamp: new Date().toISOString(),
84
+ });
85
+ });
86
+ // GET /api/peers - Connected peers list (merged daemon + DHT)
87
+ app.get('/api/peers', async (_req, reply) => {
88
+ try {
89
+ const result = await getPeerList();
90
+ // Merge DHT peers if available
91
+ if (dhtQueryService) {
92
+ const dhtPeers = dhtQueryService.getNetworkPeers();
93
+ const merged = mergePeers(result.peers, dhtPeers);
94
+ return reply.send({ peers: merged, total: merged.length, degraded: result.degraded });
95
+ }
96
+ return reply.send({ peers: result.peers, total: result.peers.length, degraded: result.degraded });
97
+ }
98
+ catch (err) {
99
+ return reply.code(500).send({ error: `Failed to get peers: ${err.message}` });
100
+ }
101
+ });
102
+ // GET /api/network - DHT network peers and stats
103
+ app.get('/api/network', async (_req, reply) => {
104
+ try {
105
+ if (!dhtQueryService) {
106
+ return reply.send({
107
+ peers: [],
108
+ stats: {
109
+ totalPeers: 0,
110
+ dhtNodeCount: 0,
111
+ dhtHealthy: false,
112
+ lastScanAt: null,
113
+ totalLookups: 0,
114
+ successfulLookups: 0,
115
+ lookupSuccessRate: 0,
116
+ averageLookupLatencyMs: 0,
117
+ healthReason: 'dht query service unavailable',
118
+ },
119
+ });
120
+ }
121
+ // Also include daemon peers in the merged view
122
+ const daemonResult = await getPeerList();
123
+ const dhtPeers = dhtQueryService.getNetworkPeers();
124
+ const stats = dhtQueryService.getNetworkStats();
125
+ // Convert daemon peers to NetworkPeer format for merging
126
+ const allPeers = daemonResult.peers.map((p) => ({
127
+ peerId: p.peerId,
128
+ host: '',
129
+ port: 0,
130
+ providers: p.providers,
131
+ inputUsdPerMillion: p.inputUsdPerMillion,
132
+ outputUsdPerMillion: p.outputUsdPerMillion,
133
+ capacityMsgPerHour: p.capacityMsgPerHour,
134
+ reputation: p.reputation,
135
+ lastSeen: Date.now(),
136
+ source: 'daemon',
137
+ }));
138
+ // Add DHT peers, deduplicating by peerId
139
+ const seen = new Set(allPeers.map((p) => p.peerId));
140
+ for (const dp of dhtPeers) {
141
+ if (!seen.has(dp.peerId)) {
142
+ allPeers.push(dp);
143
+ seen.add(dp.peerId);
144
+ }
145
+ }
146
+ return reply.send({
147
+ peers: allPeers,
148
+ stats: { ...stats, totalPeers: allPeers.length },
149
+ });
150
+ }
151
+ catch (err) {
152
+ return reply.code(500).send({ error: `Failed to get network: ${err.message}` });
153
+ }
154
+ });
155
+ // POST /api/network/scan - Trigger an immediate DHT scan
156
+ app.post('/api/network/scan', async (_req, reply) => {
157
+ if (!dhtQueryService) {
158
+ return reply.code(503).send({ error: 'DHT query service not available' });
159
+ }
160
+ await dhtQueryService.scanNow();
161
+ return reply.send({ success: true, stats: dhtQueryService.getNetworkStats() });
162
+ });
163
+ // GET /api/sessions - Session history
164
+ app.get('/api/sessions', async (req, reply) => {
165
+ try {
166
+ const { limit = 50, offset = 0, status } = req.query;
167
+ const sessions = await getSessionList(storage, limit, offset, status);
168
+ return reply.send({ sessions: sessions.items, total: sessions.total, degraded: !readiness.meteringDbAvailable });
169
+ }
170
+ catch (err) {
171
+ return reply.code(500).send({ error: `Failed to get sessions: ${err.message}` });
172
+ }
173
+ });
174
+ // GET /api/earnings - Earnings data for charts
175
+ app.get('/api/earnings', async (req, reply) => {
176
+ try {
177
+ const earnings = await getEarningsData(storage, aggregator, req.query.period ?? 'month');
178
+ return reply.send({ ...earnings, degraded: !readiness.meteringDbAvailable });
179
+ }
180
+ catch (err) {
181
+ return reply.code(500).send({ error: `Failed to get earnings: ${err.message}` });
182
+ }
183
+ });
184
+ // GET /api/config - Current config (redacted)
185
+ app.get('/api/config', async (_req, reply) => {
186
+ try {
187
+ const redacted = JSON.parse(JSON.stringify(config));
188
+ if (Array.isArray(redacted.providers)) {
189
+ for (const p of redacted.providers) {
190
+ if (p && typeof p === 'object' && 'authValue' in p) {
191
+ p.authValue = '***';
192
+ }
193
+ }
194
+ }
195
+ if (redacted.payments?.crypto && 'privateKey' in redacted.payments.crypto) {
196
+ redacted.payments.crypto.privateKey = '***';
197
+ }
198
+ return reply.send({ config: redacted });
199
+ }
200
+ catch (err) {
201
+ return reply.code(500).send({ error: `Failed to get config: ${err.message}` });
202
+ }
203
+ });
204
+ // PUT /api/config - Update config
205
+ app.put('/api/config', async (req, reply) => {
206
+ const updates = req.body;
207
+ const SAFE_CONFIG_KEYS = ['seller', 'buyer', 'network', 'payments'];
208
+ for (const key of SAFE_CONFIG_KEYS) {
209
+ if (key in updates) {
210
+ config[key] = updates[key];
211
+ }
212
+ }
213
+ try {
214
+ await saveConfig(configPath ?? '~/.antseed/config.json', config);
215
+ }
216
+ catch {
217
+ return reply.code(500).send({ error: 'Failed to save config' });
218
+ }
219
+ return reply.send({ success: true, config });
220
+ });
221
+ }
222
+ /** Merge daemon peers with DHT peers, deduplicating by peerId */
223
+ function mergePeers(daemonPeers, dhtPeers) {
224
+ const merged = new Map();
225
+ // Daemon peers first
226
+ for (const p of daemonPeers) {
227
+ merged.set(p.peerId, { ...p, source: 'daemon' });
228
+ }
229
+ // DHT peers, skip duplicates
230
+ for (const dp of dhtPeers) {
231
+ if (!merged.has(dp.peerId)) {
232
+ merged.set(dp.peerId, {
233
+ peerId: dp.peerId,
234
+ providers: dp.providers,
235
+ capacityMsgPerHour: dp.capacityMsgPerHour,
236
+ inputUsdPerMillion: dp.inputUsdPerMillion,
237
+ outputUsdPerMillion: dp.outputUsdPerMillion,
238
+ reputation: dp.reputation,
239
+ location: null,
240
+ source: 'dht',
241
+ });
242
+ }
243
+ }
244
+ return Array.from(merged.values());
245
+ }
246
+ async function getPeerList() {
247
+ try {
248
+ const stateFile = join(homedir(), '.antseed', 'daemon.state.json');
249
+ const raw = await readFile(stateFile, 'utf-8');
250
+ const state = JSON.parse(raw);
251
+ const rawPeers = Array.isArray(state.peers) ? state.peers : [];
252
+ const peers = rawPeers.map((p) => {
253
+ const peer = p;
254
+ return {
255
+ peerId: peer.peerId ?? '',
256
+ providers: Array.isArray(peer.providers) ? peer.providers : [],
257
+ capacityMsgPerHour: typeof peer.capacityMsgPerHour === 'number' ? peer.capacityMsgPerHour : 0,
258
+ inputUsdPerMillion: typeof peer.inputUsdPerMillion === 'number' ? peer.inputUsdPerMillion : 0,
259
+ outputUsdPerMillion: typeof peer.outputUsdPerMillion === 'number' ? peer.outputUsdPerMillion : 0,
260
+ reputation: typeof peer.reputation === 'number' ? peer.reputation : 0,
261
+ location: typeof peer.location === 'string' ? peer.location : null,
262
+ source: 'daemon',
263
+ };
264
+ }).filter((peer) => peer.peerId.length > 0);
265
+ return { peers, degraded: false };
266
+ }
267
+ catch {
268
+ return { peers: [], degraded: true };
269
+ }
270
+ }
271
+ async function getSessionList(storage, limit, offset, filterStatus) {
272
+ const merged = new Map();
273
+ // Query persisted sessions from the last 30 days.
274
+ const now = Date.now();
275
+ const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1000;
276
+ if (storage) {
277
+ const allSessions = storage.getSessionsByTimeRange(thirtyDaysAgo, now);
278
+ for (const s of allSessions) {
279
+ merged.set(s.sessionId, {
280
+ metrics: {
281
+ sessionId: s.sessionId,
282
+ provider: s.provider,
283
+ startedAt: s.startedAt,
284
+ totalTokens: s.totalTokens,
285
+ totalRequests: s.totalRequests,
286
+ durationMs: (s.endedAt ?? now) - s.startedAt,
287
+ avgLatencyMs: s.avgLatencyMs,
288
+ peerSwitches: s.peerSwitches,
289
+ },
290
+ startedAt: s.startedAt,
291
+ active: s.endedAt == null,
292
+ });
293
+ }
294
+ }
295
+ // Merge live in-memory sessions exposed by the seeding daemon state.
296
+ // This closes the gap where status says "activeSessions > 0" but metering DB rows
297
+ // are delayed or unavailable for the current active stream.
298
+ const daemonActiveSessions = await getDaemonActiveSessions();
299
+ for (const active of daemonActiveSessions) {
300
+ const existing = merged.get(active.metrics.sessionId);
301
+ if (!existing) {
302
+ merged.set(active.metrics.sessionId, active);
303
+ continue;
304
+ }
305
+ const activeHasMoreData = active.metrics.totalRequests > existing.metrics.totalRequests ||
306
+ active.metrics.totalTokens > existing.metrics.totalTokens ||
307
+ active.startedAt > existing.startedAt;
308
+ if (activeHasMoreData || (!existing.active && active.active)) {
309
+ merged.set(active.metrics.sessionId, {
310
+ metrics: {
311
+ ...existing.metrics,
312
+ ...active.metrics,
313
+ peerSwitches: Math.max(existing.metrics.peerSwitches, active.metrics.peerSwitches),
314
+ },
315
+ startedAt: Math.max(existing.startedAt, active.startedAt),
316
+ active: existing.active || active.active,
317
+ });
318
+ continue;
319
+ }
320
+ merged.set(active.metrics.sessionId, {
321
+ metrics: existing.metrics,
322
+ startedAt: Math.max(existing.startedAt, active.startedAt),
323
+ active: existing.active || active.active,
324
+ });
325
+ }
326
+ const normalizedStatus = (filterStatus ?? '').trim().toLowerCase();
327
+ const filtered = [...merged.values()].filter((entry) => {
328
+ if (normalizedStatus === 'active')
329
+ return entry.active;
330
+ if (normalizedStatus === 'closed' || normalizedStatus === 'ended')
331
+ return !entry.active;
332
+ return true;
333
+ });
334
+ filtered.sort((a, b) => b.startedAt - a.startedAt);
335
+ const total = filtered.length;
336
+ const items = filtered.slice(offset, offset + limit).map((entry) => entry.metrics);
337
+ return { items, total };
338
+ }
339
+ function asFiniteNumber(value, fallback) {
340
+ const parsed = Number(value);
341
+ return Number.isFinite(parsed) ? parsed : fallback;
342
+ }
343
+ function asText(value, fallback) {
344
+ return typeof value === 'string' && value.trim().length > 0 ? value : fallback;
345
+ }
346
+ async function getDaemonActiveSessions() {
347
+ const stateFile = join(homedir(), '.antseed', 'daemon.state.json');
348
+ let raw;
349
+ try {
350
+ raw = await readFile(stateFile, 'utf-8');
351
+ }
352
+ catch {
353
+ return [];
354
+ }
355
+ let parsed;
356
+ try {
357
+ parsed = JSON.parse(raw);
358
+ }
359
+ catch {
360
+ return [];
361
+ }
362
+ const root = parsed && typeof parsed === 'object' ? parsed : null;
363
+ if (!root) {
364
+ return [];
365
+ }
366
+ const details = Array.isArray(root['activeSessionDetails']) ? root['activeSessionDetails'] : [];
367
+ const activeSessionsCount = Math.max(0, Math.round(asFiniteNumber(root['activeSessions'], 0)));
368
+ if (details.length === 0 && activeSessionsCount === 0) {
369
+ return [];
370
+ }
371
+ const now = Date.now();
372
+ const entries = [];
373
+ for (const detail of details) {
374
+ const sessionId = asText(detail?.sessionId, '').trim();
375
+ if (sessionId.length === 0) {
376
+ continue;
377
+ }
378
+ const startedAt = asFiniteNumber(detail?.startedAt, now);
379
+ const durationMs = Math.max(0, now - startedAt);
380
+ entries.push({
381
+ metrics: {
382
+ sessionId,
383
+ provider: asText(detail?.provider, 'unknown'),
384
+ startedAt,
385
+ totalTokens: Math.max(0, Math.round(asFiniteNumber(detail?.totalTokens, 0))),
386
+ totalRequests: Math.max(0, Math.round(asFiniteNumber(detail?.totalRequests, 0))),
387
+ durationMs,
388
+ avgLatencyMs: Math.max(0, asFiniteNumber(detail?.avgLatencyMs, 0)),
389
+ peerSwitches: 0,
390
+ },
391
+ startedAt,
392
+ active: true,
393
+ });
394
+ }
395
+ // Fallback: if daemon reports active sessions but does not expose detailed rows yet,
396
+ // synthesize placeholders so Sessions UI still reflects live load.
397
+ if (entries.length === 0 && activeSessionsCount > 0) {
398
+ for (let i = 0; i < activeSessionsCount; i += 1) {
399
+ entries.push({
400
+ metrics: {
401
+ sessionId: `live-${i + 1}`,
402
+ provider: 'live',
403
+ startedAt: now,
404
+ totalTokens: 0,
405
+ totalRequests: 0,
406
+ durationMs: 0,
407
+ avgLatencyMs: 0,
408
+ peerSwitches: 0,
409
+ },
410
+ startedAt: now,
411
+ active: true,
412
+ });
413
+ }
414
+ }
415
+ return entries;
416
+ }
417
+ async function getEarningsData(storage, aggregator, period) {
418
+ if (!storage) {
419
+ return { today: '0.00', thisWeek: '0.00', thisMonth: '0.00', daily: [], byProvider: [] };
420
+ }
421
+ const now = Date.now();
422
+ const todayStart = new Date();
423
+ todayStart.setUTCHours(0, 0, 0, 0);
424
+ const weekStart = new Date(todayStart);
425
+ weekStart.setUTCDate(weekStart.getUTCDate() - weekStart.getUTCDay());
426
+ const monthStart = new Date(todayStart.getUTCFullYear(), todayStart.getUTCMonth(), 1);
427
+ const todayCostCents = storage.getTotalCost(todayStart.getTime(), now);
428
+ const weekCostCents = storage.getTotalCost(weekStart.getTime(), now);
429
+ const monthCostCents = storage.getTotalCost(monthStart.getTime(), now);
430
+ // Get sessions for the selected period for charts
431
+ const periodMap = { day: 1, week: 7, month: 30 };
432
+ const days = periodMap[period];
433
+ const periodStart = now - days * 24 * 60 * 60 * 1000;
434
+ const sessions = storage.getSessionsByTimeRange(periodStart, now);
435
+ const dailyAggregates = aggregator.aggregate(sessions, 'daily');
436
+ const daily = dailyAggregates.map((agg) => ({
437
+ date: new Date(agg.periodStart).toISOString().slice(0, 10),
438
+ amount: (agg.totalCostCents / 100).toFixed(2),
439
+ }));
440
+ // Provider breakdown from all sessions in the period
441
+ const allTimeAgg = aggregator.aggregateAll(sessions);
442
+ const byProvider = Object.entries(allTimeAgg.byProvider).map(([provider, data]) => ({
443
+ provider,
444
+ amount: (data.costCents / 100).toFixed(2),
445
+ }));
446
+ return {
447
+ today: (todayCostCents / 100).toFixed(2),
448
+ thisWeek: (weekCostCents / 100).toFixed(2),
449
+ thisMonth: (monthCostCents / 100).toFixed(2),
450
+ daily,
451
+ byProvider,
452
+ };
453
+ }
454
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=routes.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.test.d.ts","sourceRoot":"","sources":["../../src/api/routes.test.ts"],"names":[],"mappings":""}