@hasna/logs 0.0.1 → 0.2.0

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 (65) hide show
  1. package/dashboard/README.md +73 -0
  2. package/dashboard/bun.lock +526 -0
  3. package/dashboard/eslint.config.js +23 -0
  4. package/dashboard/index.html +13 -0
  5. package/dashboard/package.json +32 -0
  6. package/dashboard/public/favicon.svg +1 -0
  7. package/dashboard/public/icons.svg +24 -0
  8. package/dashboard/src/App.css +184 -0
  9. package/dashboard/src/App.tsx +49 -0
  10. package/dashboard/src/api.ts +33 -0
  11. package/dashboard/src/assets/hero.png +0 -0
  12. package/dashboard/src/assets/react.svg +1 -0
  13. package/dashboard/src/assets/vite.svg +1 -0
  14. package/dashboard/src/index.css +111 -0
  15. package/dashboard/src/main.tsx +10 -0
  16. package/dashboard/src/pages/Alerts.tsx +69 -0
  17. package/dashboard/src/pages/Issues.tsx +50 -0
  18. package/dashboard/src/pages/Perf.tsx +75 -0
  19. package/dashboard/src/pages/Projects.tsx +67 -0
  20. package/dashboard/src/pages/Summary.tsx +67 -0
  21. package/dashboard/src/pages/Tail.tsx +65 -0
  22. package/dashboard/tsconfig.app.json +28 -0
  23. package/dashboard/tsconfig.json +7 -0
  24. package/dashboard/tsconfig.node.json +26 -0
  25. package/dashboard/vite.config.ts +14 -0
  26. package/dist/cli/index.js +116 -12
  27. package/dist/mcp/index.js +306 -100
  28. package/dist/server/index.js +592 -7
  29. package/package.json +12 -2
  30. package/sdk/package.json +3 -2
  31. package/sdk/src/index.ts +1 -1
  32. package/sdk/src/types.ts +56 -0
  33. package/src/cli/index.ts +114 -4
  34. package/src/db/index.ts +10 -0
  35. package/src/db/migrations/001_alert_rules.ts +21 -0
  36. package/src/db/migrations/002_issues.ts +21 -0
  37. package/src/db/migrations/003_retention.ts +15 -0
  38. package/src/db/migrations/004_page_auth.ts +13 -0
  39. package/src/lib/alerts.test.ts +67 -0
  40. package/src/lib/alerts.ts +117 -0
  41. package/src/lib/compare.test.ts +52 -0
  42. package/src/lib/compare.ts +85 -0
  43. package/src/lib/diagnose.test.ts +55 -0
  44. package/src/lib/diagnose.ts +76 -0
  45. package/src/lib/export.test.ts +66 -0
  46. package/src/lib/export.ts +65 -0
  47. package/src/lib/health.test.ts +48 -0
  48. package/src/lib/health.ts +51 -0
  49. package/src/lib/ingest.ts +25 -2
  50. package/src/lib/issues.test.ts +79 -0
  51. package/src/lib/issues.ts +70 -0
  52. package/src/lib/page-auth.test.ts +54 -0
  53. package/src/lib/page-auth.ts +48 -0
  54. package/src/lib/retention.test.ts +42 -0
  55. package/src/lib/retention.ts +62 -0
  56. package/src/lib/scanner.ts +21 -2
  57. package/src/lib/scheduler.ts +6 -0
  58. package/src/lib/session-context.ts +28 -0
  59. package/src/mcp/index.ts +133 -89
  60. package/src/server/index.ts +12 -1
  61. package/src/server/routes/alerts.ts +32 -0
  62. package/src/server/routes/issues.ts +43 -0
  63. package/src/server/routes/logs.ts +21 -0
  64. package/src/server/routes/projects.ts +25 -0
  65. package/src/server/routes/stream.ts +43 -0
@@ -0,0 +1,43 @@
1
+ import { Hono } from "hono"
2
+ import { streamSSE } from "hono/streaming"
3
+ import type { Database } from "bun:sqlite"
4
+ import type { LogLevel, LogRow } from "../../types/index.ts"
5
+
6
+ export function streamRoutes(db: Database) {
7
+ const app = new Hono()
8
+
9
+ // GET /api/logs/stream?project_id=&level=&service=
10
+ app.get("/", (c) => {
11
+ const { project_id, level, service } = c.req.query()
12
+
13
+ return streamSSE(c, async (stream) => {
14
+ let lastId: string | null = null
15
+
16
+ // Seed lastId with the most recent log so we only stream new ones
17
+ const latest = db.prepare("SELECT id FROM logs ORDER BY timestamp DESC LIMIT 1").get() as { id: string } | null
18
+ lastId = latest?.id ?? null
19
+
20
+ while (true) {
21
+ const conditions: string[] = []
22
+ const params: Record<string, unknown> = {}
23
+
24
+ if (lastId) { conditions.push("rowid > (SELECT rowid FROM logs WHERE id = $lastId)"); params.$lastId = lastId }
25
+ if (project_id) { conditions.push("project_id = $project_id"); params.$project_id = project_id }
26
+ if (level) { conditions.push("level IN (" + level.split(",").map((l, i) => `$l${i}`).join(",") + ")"); level.split(",").forEach((l, i) => { params[`$l${i}`] = l }) }
27
+ if (service) { conditions.push("service = $service"); params.$service = service }
28
+
29
+ const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : ""
30
+ const rows = db.prepare(`SELECT * FROM logs ${where} ORDER BY timestamp ASC LIMIT 50`).all(params) as LogRow[]
31
+
32
+ for (const row of rows) {
33
+ await stream.writeSSE({ data: JSON.stringify(row), id: row.id, event: row.level })
34
+ lastId = row.id
35
+ }
36
+
37
+ await stream.sleep(500)
38
+ }
39
+ })
40
+ })
41
+
42
+ return app
43
+ }