@hasna/logs 0.3.17 → 0.3.19

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 (38) hide show
  1. package/bun.lock +2 -2
  2. package/dist/cli/index.js +4 -3
  3. package/dist/{index-5qwba140.js → index-8pwbytc6.js} +2 -2
  4. package/dist/{index-6zrkek5y.js → index-9n6bpjxf.js} +4448 -3115
  5. package/dist/{index-vmr85wa1.js → index-hwabsrfh.js} +4303 -3140
  6. package/dist/{index-2sbhn1ye.js → index-sgg59p1t.js} +2 -2
  7. package/dist/mcp/index.js +11 -67
  8. package/dist/server/index.js +11 -3
  9. package/package.json +3 -3
  10. package/src/cli/entrypoints.test.ts +63 -0
  11. package/src/cli/index.ts +2 -1
  12. package/src/lib/ingest.ts +6 -6
  13. package/src/lib/package-meta.ts +62 -0
  14. package/src/mcp/index.ts +10 -3
  15. package/src/server/index.ts +9 -1
  16. package/dist/export-yjaar93b.js +0 -10
  17. package/dist/health-9792c1rc.js +0 -8
  18. package/dist/health-egdb00st.js +0 -8
  19. package/dist/index-14dvwcf1.js +0 -45
  20. package/dist/index-1f2ghyhm.js +0 -540
  21. package/dist/index-4ba0sabv.js +0 -1241
  22. package/dist/index-4hj4sakk.js +0 -1241
  23. package/dist/index-5tvnhvgr.js +0 -536
  24. package/dist/index-6y8pmes4.js +0 -45
  25. package/dist/index-7qhh666n.js +0 -1241
  26. package/dist/index-86j0hn03.js +0 -540
  27. package/dist/index-exeq2gs6.js +0 -79
  28. package/dist/index-fzmz9aqs.js +0 -1241
  29. package/dist/index-g8dczzvv.js +0 -30
  30. package/dist/index-rbrsvsyh.js +0 -88
  31. package/dist/index-t97ttm0a.js +0 -543
  32. package/dist/index-wbsq8qjd.js +0 -1241
  33. package/dist/index-xjn8gam3.js +0 -39
  34. package/dist/index-yb8yd4j6.js +0 -39
  35. package/dist/jobs-02z4fzsn.js +0 -22
  36. package/dist/query-6s5gqkck.js +0 -15
  37. package/dist/query-shjjj67k.js +0 -14
  38. package/dist/query-tcg3bm9s.js +0 -14
@@ -5,7 +5,7 @@ import {
5
5
  listPages,
6
6
  saveSnapshot,
7
7
  touchPage
8
- } from "./index-t97ttm0a.js";
8
+ } from "./index-9n6bpjxf.js";
9
9
  import {
10
10
  createScanRun,
11
11
  finishScanRun,
@@ -894,7 +894,7 @@ var require_scheduled_task = __commonJS((exports, module) => {
894
894
 
895
895
  // node_modules/node-cron/src/background-scheduled-task/index.js
896
896
  var require_background_scheduled_task = __commonJS((exports, module) => {
897
- var __dirname = "/Users/hasna/Workspace/hasna/opensource/opensourcedev/open-logs/node_modules/node-cron/src/background-scheduled-task";
897
+ var __dirname = "/home/hasna/workspace/hasna/opensource/opensourcedev/open-logs/node_modules/node-cron/src/background-scheduled-task";
898
898
  var EventEmitter = __require("events");
899
899
  var path = __require("path");
900
900
  var { fork } = __require("child_process");
package/dist/mcp/index.js CHANGED
@@ -4,10 +4,12 @@ import {
4
4
  getHealth
5
5
  } from "../index-cpvq9np9.js";
6
6
  import {
7
+ PACKAGE_VERSION,
7
8
  createAlertRule,
8
9
  createPage,
9
10
  createProject,
10
11
  deleteAlertRule,
12
+ exitIfMetadataRequest,
11
13
  getDb,
12
14
  getLatestSnapshot,
13
15
  getPerfTrend,
@@ -17,11 +19,12 @@ import {
17
19
  listIssues,
18
20
  listPages,
19
21
  listProjects,
22
+ registerCloudTools,
20
23
  resolveProjectId,
21
24
  scoreLabel,
22
25
  summarizeLogs,
23
26
  updateIssueStatus
24
- } from "../index-vmr85wa1.js";
27
+ } from "../index-9n6bpjxf.js";
25
28
  import {
26
29
  createJob,
27
30
  listJobs
@@ -6523,69 +6526,6 @@ var require_dist = __commonJS((exports, module) => {
6523
6526
  exports.default = formatsPlugin;
6524
6527
  });
6525
6528
 
6526
- // package.json
6527
- var require_package = __commonJS((exports, module) => {
6528
- module.exports = {
6529
- name: "@hasna/logs",
6530
- version: "0.3.16",
6531
- description: "Log aggregation + browser script + headless page scanner + performance monitoring for AI agents",
6532
- type: "module",
6533
- main: "./dist/index.js",
6534
- types: "./dist/index.d.ts",
6535
- bin: {
6536
- logs: "./dist/cli/index.js",
6537
- "logs-mcp": "./dist/mcp/index.js",
6538
- "logs-serve": "./dist/server/index.js"
6539
- },
6540
- scripts: {
6541
- build: "bun build src/cli/index.ts src/mcp/index.ts src/server/index.ts --outdir dist --target bun --splitting --external playwright --external playwright-core --external electron --external chromium-bidi --external lighthouse",
6542
- "build:dashboard": "cd dashboard && bun run build",
6543
- "build:all": "bun run build:dashboard && bun run build",
6544
- dev: "bun run src/server/index.ts",
6545
- test: "bun test",
6546
- "test:coverage": "bun test --coverage",
6547
- lint: "biome check src/",
6548
- postinstall: "mkdir -p $HOME/.hasna/logs 2>/dev/null || true"
6549
- },
6550
- repository: {
6551
- type: "git",
6552
- url: "https://github.com/hasna/logs.git"
6553
- },
6554
- publishConfig: {
6555
- registry: "https://registry.npmjs.org",
6556
- access: "public"
6557
- },
6558
- keywords: [
6559
- "logs",
6560
- "monitoring",
6561
- "mcp",
6562
- "ai-agents",
6563
- "sentry",
6564
- "performance",
6565
- "lighthouse"
6566
- ],
6567
- author: "Andrei Hasna <andrei@hasna.com>",
6568
- license: "Apache-2.0",
6569
- dependencies: {
6570
- "@hasna/cloud": "0.1.5",
6571
- "@modelcontextprotocol/sdk": "^1.12.1",
6572
- commander: "^14.0.0",
6573
- hono: "^4.7.11",
6574
- ink: "^5.1.0",
6575
- "node-cron": "^3.0.3",
6576
- playwright: "^1.52.0",
6577
- react: "^19.1.0"
6578
- },
6579
- devDependencies: {
6580
- "@biomejs/biome": "^1.9.4",
6581
- "@types/bun": "latest",
6582
- "@types/node-cron": "^3.0.11",
6583
- "@types/react": "^19.1.4",
6584
- typescript: "^5.9.3"
6585
- }
6586
- };
6587
- });
6588
-
6589
6529
  // node_modules/@modelcontextprotocol/sdk/node_modules/zod/v3/helpers/util.js
6590
6530
  var util;
6591
6531
  (function(util2) {
@@ -23995,8 +23935,12 @@ async function getSessionContext(db, sessionId) {
23995
23935
  }
23996
23936
 
23997
23937
  // src/mcp/index.ts
23938
+ exitIfMetadataRequest({
23939
+ name: "logs-mcp",
23940
+ description: "Start the @hasna/logs MCP server over stdio."
23941
+ });
23998
23942
  var db = getDb();
23999
- var server = new McpServer({ name: "logs", version: "0.3.0" });
23943
+ var server = new McpServer({ name: "logs", version: PACKAGE_VERSION });
24000
23944
  var _logsAgents = new Map;
24001
23945
  function applyBrief(rows, brief = true) {
24002
23946
  if (!brief)
@@ -24325,12 +24269,11 @@ server.tool("send_feedback", "Send feedback about this service", {
24325
24269
  category: exports_external.enum(["bug", "feature", "general"]).optional()
24326
24270
  }, async (params) => {
24327
24271
  try {
24328
- const pkg = require_package();
24329
24272
  db.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [
24330
24273
  params.message,
24331
24274
  params.email || null,
24332
24275
  params.category || "general",
24333
- pkg.version
24276
+ PACKAGE_VERSION
24334
24277
  ]);
24335
24278
  return { content: [{ type: "text", text: "Feedback saved. Thank you!" }] };
24336
24279
  } catch (e) {
@@ -24376,4 +24319,5 @@ server.tool("list_agents", "List all registered agents.", {}, async () => {
24376
24319
  return { content: [{ type: "text", text: JSON.stringify([..._logsAgents.values()]) }] };
24377
24320
  });
24378
24321
  var transport = new StdioServerTransport;
24322
+ registerCloudTools(server, "logs");
24379
24323
  await server.connect(transport);
@@ -6,7 +6,7 @@ import {
6
6
  setPageAuth,
7
7
  setRetentionPolicy,
8
8
  startScheduler
9
- } from "../index-4ba0sabv.js";
9
+ } from "../index-sgg59p1t.js";
10
10
  import {
11
11
  getHealth
12
12
  } from "../index-cpvq9np9.js";
@@ -15,6 +15,7 @@ import {
15
15
  createPage,
16
16
  createProject,
17
17
  deleteAlertRule,
18
+ exitIfMetadataRequest,
18
19
  getDb,
19
20
  getIssue,
20
21
  getLatestSnapshot,
@@ -26,12 +27,13 @@ import {
26
27
  listIssues,
27
28
  listPages,
28
29
  listProjects,
30
+ readOptionValue,
29
31
  resolveProjectId,
30
32
  summarizeLogs,
31
33
  updateAlertRule,
32
34
  updateIssueStatus,
33
35
  updateProject
34
- } from "../index-vmr85wa1.js";
36
+ } from "../index-9n6bpjxf.js";
35
37
  import {
36
38
  createJob,
37
39
  deleteJob,
@@ -2442,7 +2444,13 @@ function streamRoutes(db) {
2442
2444
  }
2443
2445
 
2444
2446
  // src/server/index.ts
2445
- var PORT = Number(process.env.LOGS_PORT ?? 3460);
2447
+ exitIfMetadataRequest({
2448
+ name: "logs-serve",
2449
+ description: "Start the @hasna/logs REST API server.",
2450
+ options: [" -p, --port <n> Port to listen on (default: LOGS_PORT or 3460)"]
2451
+ });
2452
+ var portArg = readOptionValue(["--port", "-p"]);
2453
+ var PORT = Number(portArg ?? process.env.LOGS_PORT ?? 3460);
2446
2454
  var db = getDb();
2447
2455
  var app = new Hono2;
2448
2456
  app.use("*", cors());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/logs",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
4
4
  "description": "Log aggregation + browser script + headless page scanner + performance monitoring for AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "author": "Andrei Hasna <andrei@hasna.com>",
41
41
  "license": "Apache-2.0",
42
42
  "dependencies": {
43
- "@hasna/cloud": "0.1.5",
43
+ "@hasna/cloud": "^0.1.24",
44
44
  "@modelcontextprotocol/sdk": "^1.12.1",
45
45
  "commander": "^14.0.0",
46
46
  "hono": "^4.7.11",
@@ -56,4 +56,4 @@
56
56
  "@types/react": "^19.1.4",
57
57
  "typescript": "^5.9.3"
58
58
  }
59
- }
59
+ }
@@ -0,0 +1,63 @@
1
+ import { expect, test } from "bun:test"
2
+ import { readFileSync } from "node:fs"
3
+ import { fileURLToPath } from "node:url"
4
+
5
+ const packageJson = JSON.parse(
6
+ readFileSync(new URL("../../package.json", import.meta.url), "utf8"),
7
+ ) as { version: string }
8
+
9
+ async function runEntrypoint(entryRelativePath: string, args: string[]) {
10
+ const entry = fileURLToPath(new URL(entryRelativePath, import.meta.url))
11
+ const proc = Bun.spawn(["bun", entry, ...args], {
12
+ env: {
13
+ ...process.env,
14
+ LOGS_PORT: "0",
15
+ },
16
+ stdout: "pipe",
17
+ stderr: "pipe",
18
+ })
19
+
20
+ const timeout = new Promise<never>((_, reject) => {
21
+ const timer = setTimeout(() => {
22
+ proc.kill()
23
+ reject(new Error(`Timed out running ${entryRelativePath} ${args.join(" ")}`.trim()))
24
+ }, 2000)
25
+
26
+ proc.exited.finally(() => clearTimeout(timer))
27
+ })
28
+
29
+ const exitCode = await Promise.race([proc.exited, timeout])
30
+ const stdout = await new Response(proc.stdout).text()
31
+ const stderr = await new Response(proc.stderr).text()
32
+
33
+ return { exitCode, stdout, stderr }
34
+ }
35
+
36
+ test("logs --version matches package.json", async () => {
37
+ const result = await runEntrypoint("./index.ts", ["--version"])
38
+
39
+ expect(result.exitCode).toBe(0)
40
+ expect(result.stdout.trim()).toBe(packageJson.version)
41
+ expect(result.stderr.trim()).toBe("")
42
+ })
43
+
44
+ test("logs-mcp --help prints usage and exits without starting stdio transport", async () => {
45
+ const result = await runEntrypoint("../mcp/index.ts", ["--help"])
46
+
47
+ expect(result.exitCode).toBe(0)
48
+ expect(result.stdout).toContain("Usage: logs-mcp [options]")
49
+ expect(result.stdout).toContain("Start the @hasna/logs MCP server over stdio.")
50
+ expect(result.stdout).not.toContain("Listening")
51
+ expect(result.stderr.trim()).toBe("")
52
+ })
53
+
54
+ test("logs-serve --help prints usage and exits without starting the server", async () => {
55
+ const result = await runEntrypoint("../server/index.ts", ["--help"])
56
+
57
+ expect(result.exitCode).toBe(0)
58
+ expect(result.stdout).toContain("Usage: logs-serve [options]")
59
+ expect(result.stdout).toContain("Start the @hasna/logs REST API server.")
60
+ expect(result.stdout).not.toContain("server running")
61
+ expect(result.stdout).not.toContain("Scheduler started")
62
+ expect(result.stderr.trim()).toBe("")
63
+ })
package/src/cli/index.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  import { Command } from "commander"
3
3
  import { getDb } from "../db/index.ts"
4
4
  import { ingestLog } from "../lib/ingest.ts"
5
+ import { PACKAGE_VERSION } from "../lib/package-meta.ts"
5
6
  import { searchLogs, tailLogs } from "../lib/query.ts"
6
7
  import { summarizeLogs } from "../lib/summarize.ts"
7
8
  import { createJob, listJobs } from "../lib/jobs.ts"
@@ -39,7 +40,7 @@ function resolveProject(nameOrId: string | undefined): string | undefined {
39
40
  const program = new Command()
40
41
  .name("logs")
41
42
  .description("@hasna/logs — log aggregation and monitoring")
42
- .version("0.0.1")
43
+ .version(PACKAGE_VERSION)
43
44
 
44
45
  // ── logs list ──────────────────────────────────────────────
45
46
  program.command("list")
package/src/lib/ingest.ts CHANGED
@@ -1,11 +1,11 @@
1
- import type { Database } from "bun:sqlite"
1
+ import type { DbAdapter } from "@hasna/cloud"
2
2
  import type { LogEntry, LogRow } from "../types/index.ts"
3
3
  import { upsertIssue } from "./issues.ts"
4
4
  import { evaluateAlerts } from "./alerts.ts"
5
5
 
6
6
  const ERROR_LEVELS = new Set(["warn", "error", "fatal"])
7
7
 
8
- export function ingestLog(db: Database, entry: LogEntry): LogRow {
8
+ export function ingestLog(db: DbAdapter, entry: LogEntry): LogRow {
9
9
  const stmt = db.prepare(`
10
10
  INSERT INTO logs (project_id, page_id, level, source, service, message, trace_id, session_id, agent, url, stack_trace, metadata)
11
11
  VALUES ($project_id, $page_id, $level, $source, $service, $message, $trace_id, $session_id, $agent, $url, $stack_trace, $metadata)
@@ -37,7 +37,7 @@ export function ingestLog(db: Database, entry: LogEntry): LogRow {
37
37
  return row
38
38
  }
39
39
 
40
- export function ingestBatch(db: Database, entries: LogEntry[], sharedTraceId?: string | null): LogRow[] {
40
+ export function ingestBatch(db: DbAdapter, entries: LogEntry[], sharedTraceId?: string | null): LogRow[] {
41
41
  // Apply shared trace_id to entries that don't have their own
42
42
  if (sharedTraceId) {
43
43
  entries = entries.map(e => e.trace_id ? e : { ...e, trace_id: sharedTraceId })
@@ -47,8 +47,9 @@ export function ingestBatch(db: Database, entries: LogEntry[], sharedTraceId?: s
47
47
  VALUES ($project_id, $page_id, $level, $source, $service, $message, $trace_id, $session_id, $agent, $url, $stack_trace, $metadata)
48
48
  RETURNING *
49
49
  `)
50
- const tx = db.transaction((items: LogEntry[]) =>
51
- items.map(entry =>
50
+ // @hasna/cloud executes the callback inside the transaction immediately.
51
+ const rows = db.transaction(() =>
52
+ entries.map(entry =>
52
53
  insert.get({
53
54
  $project_id: entry.project_id ?? null,
54
55
  $page_id: entry.page_id ?? null,
@@ -65,7 +66,6 @@ export function ingestBatch(db: Database, entries: LogEntry[], sharedTraceId?: s
65
66
  }) as LogRow
66
67
  )
67
68
  )
68
- const rows = tx(entries)
69
69
 
70
70
  // Issue grouping for error-level entries (outside transaction for perf)
71
71
  for (const entry of entries) {
@@ -0,0 +1,62 @@
1
+ import { readFileSync } from "node:fs"
2
+
3
+ type StandaloneCliSpec = {
4
+ name: string
5
+ description: string
6
+ options?: string[]
7
+ }
8
+
9
+ type PackageJson = {
10
+ version?: string
11
+ }
12
+
13
+ const packageJson = JSON.parse(
14
+ readFileSync(new URL("../../package.json", import.meta.url), "utf8"),
15
+ ) as PackageJson
16
+
17
+ export const PACKAGE_VERSION = packageJson.version ?? "0.0.0"
18
+
19
+ export function exitIfMetadataRequest(spec: StandaloneCliSpec, argv = process.argv.slice(2)): void {
20
+ if (argv.includes("--version") || argv.includes("-V")) {
21
+ console.log(PACKAGE_VERSION)
22
+ process.exit(0)
23
+ }
24
+
25
+ if (argv.includes("--help") || argv.includes("-h")) {
26
+ const options = spec.options ?? []
27
+ const renderedOptions = [
28
+ " -V, --version output the version number",
29
+ " -h, --help display help for command",
30
+ ...options,
31
+ ]
32
+
33
+ console.log(
34
+ [
35
+ `Usage: ${spec.name} [options]`,
36
+ "",
37
+ spec.description,
38
+ "",
39
+ "Options:",
40
+ ...renderedOptions,
41
+ ].join("\n"),
42
+ )
43
+ process.exit(0)
44
+ }
45
+ }
46
+
47
+ export function readOptionValue(names: string[], argv = process.argv.slice(2)): string | undefined {
48
+ for (let index = 0; index < argv.length; index += 1) {
49
+ const arg = argv[index]
50
+ if (!arg) continue
51
+
52
+ const inline = names.find((name) => arg.startsWith(`${name}=`))
53
+ if (inline) return arg.slice(inline.length + 1)
54
+
55
+ if (names.includes(arg)) {
56
+ const next = argv[index + 1]
57
+ if (next && !next.startsWith("-")) return next
58
+ }
59
+ }
60
+
61
+ return undefined
62
+ }
package/src/mcp/index.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env bun
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4
+ import { registerCloudTools } from "@hasna/cloud"
4
5
  import { z } from "zod"
5
6
  import { getDb } from "../db/index.ts"
7
+ import { exitIfMetadataRequest, PACKAGE_VERSION } from "../lib/package-meta.ts"
6
8
  import { ingestBatch, ingestLog } from "../lib/ingest.ts"
7
9
  import { getLogContext, getLogContextFromId, searchLogs, tailLogs } from "../lib/query.ts"
8
10
  import { summarizeLogs } from "../lib/summarize.ts"
@@ -20,8 +22,13 @@ import { getSessionContext } from "../lib/session-context.ts"
20
22
  import { parseTime } from "../lib/parse-time.ts"
21
23
  import type { LogLevel, LogRow } from "../types/index.ts"
22
24
 
25
+ exitIfMetadataRequest({
26
+ name: "logs-mcp",
27
+ description: "Start the @hasna/logs MCP server over stdio.",
28
+ })
29
+
23
30
  const db = getDb()
24
- const server = new McpServer({ name: "logs", version: "0.3.0" })
31
+ const server = new McpServer({ name: "logs", version: PACKAGE_VERSION })
25
32
 
26
33
  // --- in-memory agent registry ---
27
34
  interface _LogsAgent { id: string; name: string; session_id?: string; last_seen_at: string; project_id?: string }
@@ -354,9 +361,8 @@ server.tool(
354
361
  },
355
362
  async (params) => {
356
363
  try {
357
- const pkg = require("../../package.json")
358
364
  db.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [
359
- params.message, params.email || null, params.category || "general", pkg.version,
365
+ params.message, params.email || null, params.category || "general", PACKAGE_VERSION,
360
366
  ])
361
367
  return { content: [{ type: "text" as const, text: "Feedback saved. Thank you!" }] }
362
368
  } catch (e) {
@@ -403,4 +409,5 @@ server.tool("list_agents", "List all registered agents.", {}, async () => {
403
409
  })
404
410
 
405
411
  const transport = new StdioServerTransport()
412
+ registerCloudTools(server, "logs")
406
413
  await server.connect(transport)
@@ -5,6 +5,7 @@ import { serveStatic } from "hono/bun"
5
5
  import { getDb } from "../db/index.ts"
6
6
  import { getBrowserScript } from "../lib/browser-script.ts"
7
7
  import { getHealth } from "../lib/health.ts"
8
+ import { exitIfMetadataRequest, readOptionValue } from "../lib/package-meta.ts"
8
9
  import { startScheduler } from "../lib/scheduler.ts"
9
10
  import { alertsRoutes } from "./routes/alerts.ts"
10
11
  import { issuesRoutes } from "./routes/issues.ts"
@@ -14,7 +15,14 @@ import { perfRoutes } from "./routes/perf.ts"
14
15
  import { projectsRoutes } from "./routes/projects.ts"
15
16
  import { streamRoutes } from "./routes/stream.ts"
16
17
 
17
- const PORT = Number(process.env.LOGS_PORT ?? 3460)
18
+ exitIfMetadataRequest({
19
+ name: "logs-serve",
20
+ description: "Start the @hasna/logs REST API server.",
21
+ options: [" -p, --port <n> Port to listen on (default: LOGS_PORT or 3460)"],
22
+ })
23
+
24
+ const portArg = readOptionValue(["--port", "-p"])
25
+ const PORT = Number(portArg ?? process.env.LOGS_PORT ?? 3460)
18
26
  const db = getDb()
19
27
  const app = new Hono()
20
28
 
@@ -1,10 +0,0 @@
1
- // @bun
2
- import {
3
- exportToCsv,
4
- exportToJson
5
- } from "./index-eh9bkbpa.js";
6
- import"./index-g8dczzvv.js";
7
- export {
8
- exportToJson,
9
- exportToCsv
10
- };
@@ -1,8 +0,0 @@
1
- // @bun
2
- import {
3
- getHealth
4
- } from "./index-xjn8gam3.js";
5
- import"./index-re3ntm60.js";
6
- export {
7
- getHealth
8
- };
@@ -1,8 +0,0 @@
1
- // @bun
2
- import {
3
- getHealth
4
- } from "./index-yb8yd4j6.js";
5
- import"./index-g8dczzvv.js";
6
- export {
7
- getHealth
8
- };
@@ -1,45 +0,0 @@
1
- // @bun
2
- import {
3
- parseTime
4
- } from "./index-997bkzr2.js";
5
-
6
- // src/lib/count.ts
7
- function countLogs(db, opts) {
8
- const conditions = [];
9
- const params = {};
10
- if (opts.project_id) {
11
- conditions.push("project_id = $p");
12
- params.$p = opts.project_id;
13
- }
14
- if (opts.service) {
15
- conditions.push("service = $service");
16
- params.$service = opts.service;
17
- }
18
- if (opts.level) {
19
- conditions.push("level = $level");
20
- params.$level = opts.level;
21
- }
22
- const since = parseTime(opts.since);
23
- const until = parseTime(opts.until);
24
- if (since) {
25
- conditions.push("timestamp >= $since");
26
- params.$since = since;
27
- }
28
- if (until) {
29
- conditions.push("timestamp <= $until");
30
- params.$until = until;
31
- }
32
- const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
33
- const byLevel = db.prepare(`SELECT level, COUNT(*) as c FROM logs ${where} GROUP BY level`).all(params);
34
- const by_level = Object.fromEntries(byLevel.map((r) => [r.level, r.c]));
35
- const total = byLevel.reduce((s, r) => s + r.c, 0);
36
- return {
37
- total,
38
- errors: by_level["error"] ?? 0,
39
- warns: by_level["warn"] ?? 0,
40
- fatals: by_level["fatal"] ?? 0,
41
- by_level
42
- };
43
- }
44
-
45
- export { countLogs };