@oh-my-pi/omp-stats 17.0.0 → 17.0.2

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.
@@ -72,7 +72,7 @@ export declare function getOverviewStats(range?: string | null): Promise<Pick<Da
72
72
  export declare function getModelDashboardStats(range?: string | null): Promise<Pick<DashboardStats, "byModel" | "modelSeries" | "modelPerformanceSeries">>;
73
73
  export declare function getCostDashboardStats(range?: string | null): Promise<Pick<DashboardStats, "costSeries">>;
74
74
  export declare function getRecentRequests(limit?: number): Promise<MessageStats[]>;
75
- export declare function getRecentErrors(limit?: number): Promise<MessageStats[]>;
75
+ export declare function getRecentErrors(range?: string | null, limit?: number): Promise<MessageStats[]>;
76
76
  export declare function getRequestDetails(id: number): Promise<RequestDetails | null>;
77
77
  /**
78
78
  * Get the current message count in the database.
@@ -8,7 +8,7 @@ export declare function getOverviewStats(range?: TimeRange, signal?: AbortSignal
8
8
  export declare function getModelDashboardStats(range?: TimeRange, signal?: AbortSignal): Promise<ModelDashboardStats>;
9
9
  export declare function getCostDashboardStats(range?: TimeRange, signal?: AbortSignal): Promise<CostDashboardStats>;
10
10
  export declare function getRecentRequests(limit?: number, signal?: AbortSignal): Promise<MessageStats[]>;
11
- export declare function getRecentErrors(limit?: number, signal?: AbortSignal): Promise<MessageStats[]>;
11
+ export declare function getRecentErrors(range?: TimeRange, limit?: number, signal?: AbortSignal): Promise<MessageStats[]>;
12
12
  export declare function getRequestDetails(id: number, signal?: AbortSignal): Promise<RequestDetails>;
13
13
  export declare function sync(signal?: AbortSignal): Promise<{
14
14
  processed: number;
@@ -5,4 +5,4 @@ export interface ErrorsRouteProps {
5
5
  refreshTrigger: number;
6
6
  onRequestClick: (id: number) => void;
7
7
  }
8
- export declare function ErrorsRoute({ active, refreshTrigger, onRequestClick }: ErrorsRouteProps): import("react").JSX.Element;
8
+ export declare function ErrorsRoute({ active, range, refreshTrigger, onRequestClick }: ErrorsRouteProps): import("react").JSX.Element;
@@ -73,7 +73,7 @@ export declare function getMessageCount(): number;
73
73
  */
74
74
  export declare function closeDb(): void;
75
75
  export declare function getRecentRequests(limit?: number): MessageStats[];
76
- export declare function getRecentErrors(limit?: number): MessageStats[];
76
+ export declare function getRecentErrors(limit?: number, cutoff?: number | null): MessageStats[];
77
77
  export declare function getMessageById(id: number): MessageStats | null;
78
78
  /**
79
79
  * Get daily cost time series data for the last N days, broken down by model.
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Handle API requests.
3
+ */
4
+ export declare function handleApi(req: Request): Promise<Response>;
1
5
  /**
2
6
  * Start the HTTP server.
3
7
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/omp-stats",
4
- "version": "17.0.0",
4
+ "version": "17.0.2",
5
5
  "description": "Local observability dashboard for pi AI usage statistics",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -39,9 +39,9 @@
39
39
  "fmt": "biome format --write ."
40
40
  },
41
41
  "dependencies": {
42
- "@oh-my-pi/pi-ai": "17.0.0",
43
- "@oh-my-pi/pi-catalog": "17.0.0",
44
- "@oh-my-pi/pi-utils": "17.0.0",
42
+ "@oh-my-pi/pi-ai": "17.0.2",
43
+ "@oh-my-pi/pi-catalog": "17.0.2",
44
+ "@oh-my-pi/pi-utils": "17.0.2",
45
45
  "@tailwindcss/node": "^4.3.2",
46
46
  "chart.js": "^4.5.1",
47
47
  "date-fns": "^4.4.0",
@@ -55,6 +55,7 @@
55
55
  "@types/bun": "^1.3.14",
56
56
  "@types/react": "^19.2.17",
57
57
  "@types/react-dom": "^19.2.3",
58
+ "linkedom": "^0.18.13",
58
59
  "postcss": "^8.5.16"
59
60
  },
60
61
  "engines": {
package/src/aggregator.ts CHANGED
@@ -444,9 +444,10 @@ export async function getRecentRequests(limit?: number): Promise<MessageStats[]>
444
444
  return dbGetRecentRequests(limit);
445
445
  }
446
446
 
447
- export async function getRecentErrors(limit?: number): Promise<MessageStats[]> {
447
+ export async function getRecentErrors(range?: string | null, limit?: number): Promise<MessageStats[]> {
448
448
  await initDb();
449
- return dbGetRecentErrors(limit);
449
+ const { cutoff } = getTimeRangeConfig(range);
450
+ return dbGetRecentErrors(limit, cutoff);
450
451
  }
451
452
 
452
453
  export async function getRequestDetails(id: number): Promise<RequestDetails | null> {
package/src/client/api.ts CHANGED
@@ -59,8 +59,14 @@ export async function getRecentRequests(limit = 50, signal?: AbortSignal): Promi
59
59
  return fetchJson<MessageStats[]>(`${API_BASE}/stats/recent?limit=${limit}`, { signal });
60
60
  }
61
61
 
62
- export async function getRecentErrors(limit = 50, signal?: AbortSignal): Promise<MessageStats[]> {
63
- return fetchJson<MessageStats[]>(`${API_BASE}/stats/errors?limit=${limit}`, { signal });
62
+ export async function getRecentErrors(
63
+ range: TimeRange = "24h",
64
+ limit = 50,
65
+ signal?: AbortSignal,
66
+ ): Promise<MessageStats[]> {
67
+ return fetchJson<MessageStats[]>(`${API_BASE}/stats/errors?range=${encodeURIComponent(range)}&limit=${limit}`, {
68
+ signal,
69
+ });
64
70
  }
65
71
 
66
72
  export async function getRequestDetails(id: number, signal?: AbortSignal): Promise<RequestDetails> {
@@ -12,12 +12,12 @@ export interface ErrorsRouteProps {
12
12
  onRequestClick: (id: number) => void;
13
13
  }
14
14
 
15
- export function ErrorsRoute({ active, refreshTrigger, onRequestClick }: ErrorsRouteProps) {
15
+ export function ErrorsRoute({ active, range, refreshTrigger, onRequestClick }: ErrorsRouteProps) {
16
16
  const {
17
17
  data: recentErrors,
18
18
  error,
19
19
  loading,
20
- } = useResource(["recent-errors-dense", refreshTrigger], signal => getRecentErrors(50, signal), {
20
+ } = useResource(["recent-errors-dense", range, refreshTrigger], signal => getRecentErrors(range, 50, signal), {
21
21
  pollMs: 30000,
22
22
  enabled: active,
23
23
  });
package/src/db.ts CHANGED
@@ -832,15 +832,18 @@ export function getRecentRequests(limit = 100): MessageStats[] {
832
832
  return (stmt.all(limit) as any[]).map(rowToMessageStats);
833
833
  }
834
834
 
835
- export function getRecentErrors(limit = 100): MessageStats[] {
835
+ export function getRecentErrors(limit = 100, cutoff?: number | null): MessageStats[] {
836
836
  if (!db) return [];
837
+ const hasCutoff = cutoff !== undefined && cutoff !== null;
837
838
  const stmt = db.prepare(`
838
- SELECT * FROM messages
839
+ SELECT * FROM messages
839
840
  WHERE stop_reason = 'error'
840
- ORDER BY timestamp DESC
841
+ ${hasCutoff ? "AND timestamp >= ?" : ""}
842
+ ORDER BY timestamp DESC
841
843
  LIMIT ?
842
844
  `);
843
- return (stmt.all(limit) as any[]).map(rowToMessageStats);
845
+ const rows = hasCutoff ? stmt.all(cutoff, limit) : stmt.all(limit);
846
+ return rows.map(rowToMessageStats);
844
847
  }
845
848
 
846
849
  export function getMessageById(id: number): MessageStats | null {
package/src/server.ts CHANGED
@@ -184,7 +184,7 @@ const ensureClientBuild = async () => {
184
184
  /**
185
185
  * Handle API requests.
186
186
  */
187
- async function handleApi(req: Request): Promise<Response> {
187
+ export async function handleApi(req: Request): Promise<Response> {
188
188
  const url = new URL(req.url);
189
189
  const path = url.pathname;
190
190
 
@@ -229,7 +229,7 @@ async function handleApi(req: Request): Promise<Response> {
229
229
 
230
230
  if (path === "/api/stats/errors") {
231
231
  const limit = url.searchParams.get("limit");
232
- const stats = await getRecentErrors(limit ? parseInt(limit, 10) : undefined);
232
+ const stats = await getRecentErrors(range, limit ? parseInt(limit, 10) : undefined);
233
233
  return Response.json(stats);
234
234
  }
235
235