From e6081c28f1ef40bd00912f59deca12a33a2e8ee6 Mon Sep 17 00:00:00 2001 From: George Powell Date: Wed, 18 Feb 2026 13:25:40 -0500 Subject: [PATCH] Refactor game logic into utility modules and add cross-device sync Extracted game state management, share logic, and stats API calls into dedicated modules (game-persistence.svelte.ts, share.ts, stats-client.ts), and moved daily verse loading to client-side to fix timezone issues. Added a guesses column to daily_completions for cross-device state restoration for logged-in users, a new GET /api/stats endpoint, and a staging deploy script. Co-Authored-By: Claude Sonnet 4.6 --- deploy-staging.sh | 22 + scripts/dedup-completions.ts | 41 ++ src/lib/components/GuessesTable.svelte | 19 +- src/lib/components/Imposter.svelte | 16 +- src/lib/index.ts | 5 - src/lib/server/db/schema.ts | 13 +- src/lib/stores/game-persistence.svelte.ts | 148 ++++++ src/lib/utils/game.ts | 52 +- src/lib/utils/share.ts | 65 +++ src/lib/utils/stats-client.ts | 68 +++ src/routes/+page.server.ts | 11 - src/routes/+page.svelte | 556 +++++--------------- src/routes/+page.ts | 23 + src/routes/api/daily-verse/+server.ts | 7 +- src/routes/api/stats/+server.ts | 63 +++ src/routes/api/submit-completion/+server.ts | 69 +-- svelte.config.js | 5 +- 17 files changed, 640 insertions(+), 543 deletions(-) create mode 100755 deploy-staging.sh create mode 100644 scripts/dedup-completions.ts create mode 100644 src/lib/stores/game-persistence.svelte.ts create mode 100644 src/lib/utils/share.ts create mode 100644 src/lib/utils/stats-client.ts create mode 100644 src/routes/+page.ts create mode 100644 src/routes/api/stats/+server.ts diff --git a/deploy-staging.sh b/deploy-staging.sh new file mode 100755 index 0000000..5e8b76d --- /dev/null +++ b/deploy-staging.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +cd "$(dirname "$0")" + +echo "Pulling latest changes..." +git pull + +echo "Installing dependencies..." +bun i + +echo "Pushing database changes..." +bun run db:generate +bun run db:migrate + +echo "Building..." +bun --bun run build + +echo "Restarting service..." +sudo systemctl restart bibdle-test + +echo "Done!" diff --git a/scripts/dedup-completions.ts b/scripts/dedup-completions.ts new file mode 100644 index 0000000..6ef9966 --- /dev/null +++ b/scripts/dedup-completions.ts @@ -0,0 +1,41 @@ +import { Database } from 'bun:sqlite'; +import path from 'path'; + +const dbUrl = process.env.DATABASE_URL; +if (!dbUrl) throw new Error('DATABASE_URL is not set'); + +const dbPath = dbUrl.startsWith('file:') ? dbUrl.slice(5) : dbUrl; +const db = new Database(path.resolve(dbPath)); + +const duplicates = db.query(` + SELECT anonymous_id, date, COUNT(*) as count + FROM daily_completions + GROUP BY anonymous_id, date + HAVING count > 1 +`).all() as { anonymous_id: string; date: string; count: number }[]; + +if (duplicates.length === 0) { + console.log('No duplicates found.'); + process.exit(0); +} + +console.log(`Found ${duplicates.length} duplicate group(s):`); + +const deleteStmt = db.query(` + DELETE FROM daily_completions + WHERE anonymous_id = $anonymous_id AND date = $date + AND id NOT IN ( + SELECT id FROM daily_completions + WHERE anonymous_id = $anonymous_id AND date = $date + ORDER BY completed_at ASC + LIMIT 1 + ) +`); + +for (const { anonymous_id, date, count } of duplicates) { + deleteStmt.run({ $anonymous_id: anonymous_id, $date: date }); + console.log(` ${anonymous_id} / ${date}: kept earliest, deleted ${count - 1} row(s) (had ${count})`); +} + +console.log('Done.'); +db.close(); diff --git a/src/lib/components/GuessesTable.svelte b/src/lib/components/GuessesTable.svelte index 0f2974f..a5103e1 100644 --- a/src/lib/components/GuessesTable.svelte +++ b/src/lib/components/GuessesTable.svelte @@ -1,20 +1,8 @@