From 2f7c10e4b8d76896ca60fd8f585d6074465b2416 Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 9 Mar 2026 01:05:47 +0000 Subject: [PATCH] fix: defer analytics prepared statements to avoid crash before migrations The sqlite.prepare() calls ran at module import time, before runMigrations() created the analytics table, causing a crash loop. Co-Authored-By: Claude Opus 4.6 --- server/src/engine/analytics.ts | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/server/src/engine/analytics.ts b/server/src/engine/analytics.ts index c7b70d9..13da7aa 100644 --- a/server/src/engine/analytics.ts +++ b/server/src/engine/analytics.ts @@ -4,24 +4,31 @@ function today(): string { return new Date().toISOString().slice(0, 10) } -const incrementStmt = sqlite.prepare( - `INSERT INTO analytics (date, metric, value) VALUES (?, ?, 1) - ON CONFLICT(date, metric) DO UPDATE SET value = value + 1` -) +let _incrementStmt: ReturnType | null = null +let _incrementByStmt: ReturnType | null = null -const incrementByStmt = sqlite.prepare( - `INSERT INTO analytics (date, metric, value) VALUES (?, ?, ?) - ON CONFLICT(date, metric) DO UPDATE SET value = value + ?` -) +function getIncrementStmt() { + return _incrementStmt ??= sqlite.prepare( + `INSERT INTO analytics (date, metric, value) VALUES (?, ?, 1) + ON CONFLICT(date, metric) DO UPDATE SET value = value + 1` + ) +} + +function getIncrementByStmt() { + return _incrementByStmt ??= sqlite.prepare( + `INSERT INTO analytics (date, metric, value) VALUES (?, ?, ?) + ON CONFLICT(date, metric) DO UPDATE SET value = value + ?` + ) +} /** Increment a metric counter for today */ export function trackMetric(metric: string): void { - try { incrementStmt.run(today(), metric) } catch { /* best-effort */ } + try { getIncrementStmt().run(today(), metric) } catch { /* best-effort */ } } /** Increment a metric by a specific amount */ export function trackMetricBy(metric: string, amount: number): void { - try { incrementByStmt.run(today(), metric, amount, amount) } catch { /* best-effort */ } + try { getIncrementByStmt().run(today(), metric, amount, amount) } catch { /* best-effort */ } } /** Record a fight completion with aggregate counters */