mirror of
https://github.com/pupperpowell/bibdle.git
synced 2026-10-22 13:54:10 -04:00
first pass analytics redo
This commit is contained in:
1 parent
b656fd04c0
commit
45ffa39f2a
69 files changed
+6400
-1138
No files matched your search
@@ -0,0 +1,82 @@
|
||||
import { db as defaultDb } from '$lib/server/db';
|
||||
import { dashboardSettings } from '$lib/server/db/schema';
|
||||
import {
|
||||
SETTINGS_DEFAULTS,
|
||||
type SettingsKey,
|
||||
type StatsSettings
|
||||
} from '$lib/types/stats';
|
||||
import type { StatsDb } from './db';
|
||||
|
||||
const SETTINGS_KEYS = Object.keys(SETTINGS_DEFAULTS) as SettingsKey[];
|
||||
|
||||
/** `core_plays_per_week` → `STATS_CORE_PLAYS_PER_WEEK` */
|
||||
export function settingsEnvVar(key: SettingsKey): string {
|
||||
return `STATS_${key.toUpperCase()}`;
|
||||
}
|
||||
|
||||
/** Defaults from `SETTINGS_DEFAULTS`, overridden by `STATS_*` env vars. */
|
||||
export function envSettings(): StatsSettings {
|
||||
const out = { ...SETTINGS_DEFAULTS } as StatsSettings;
|
||||
for (const key of SETTINGS_KEYS) {
|
||||
const raw = Bun.env[settingsEnvVar(key)];
|
||||
if (raw === undefined || raw === '') continue;
|
||||
const value = Number(raw);
|
||||
if (Number.isFinite(value)) out[key] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function coerce(key: SettingsKey, raw: string): number {
|
||||
const value = Number(raw);
|
||||
return Number.isFinite(value) ? value : SETTINGS_DEFAULTS[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads persisted overrides from `dashboard_settings` and overlays them on the
|
||||
* env/default baseline. Safe to call when the table does not yet exist.
|
||||
*/
|
||||
export async function getSettings(database: StatsDb = defaultDb): Promise<StatsSettings> {
|
||||
const settings = envSettings();
|
||||
try {
|
||||
const rows = await database.select().from(dashboardSettings);
|
||||
for (const row of rows) {
|
||||
if ((SETTINGS_KEYS as string[]).includes(row.key)) {
|
||||
settings[row.key as SettingsKey] = coerce(row.key as SettingsKey, row.value);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Table missing / DB unavailable — fall back to defaults.
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
/** Upserts a partial set of setting overrides. */
|
||||
export async function updateSettings(
|
||||
partial: Partial<StatsSettings>,
|
||||
database: StatsDb = defaultDb
|
||||
): Promise<StatsSettings> {
|
||||
const now = new Date();
|
||||
for (const [key, value] of Object.entries(partial)) {
|
||||
if (!(SETTINGS_KEYS as string[]).includes(key)) continue;
|
||||
if (value === undefined || value === null || !Number.isFinite(value)) continue;
|
||||
await database
|
||||
.insert(dashboardSettings)
|
||||
.values({ key, value: String(value), updatedAt: now })
|
||||
.onConflictDoUpdate({
|
||||
target: dashboardSettings.key,
|
||||
set: { value: String(value), updatedAt: now }
|
||||
});
|
||||
}
|
||||
return getSettings(database);
|
||||
}
|
||||
|
||||
/** Stable short hash of the resolved settings — used to detect stale snapshots. */
|
||||
export function hashSettings(settings: StatsSettings): string {
|
||||
const canonical = SETTINGS_KEYS.map((k) => `${k}=${settings[k]}`).join(';');
|
||||
const digest = new Bun.CryptoHasher('sha256').update(canonical).digest('hex');
|
||||
return digest.slice(0, 12);
|
||||
}
|
||||
|
||||
export async function configVersion(database: StatsDb = defaultDb): Promise<string> {
|
||||
return hashSettings(await getSettings(database));
|
||||
}
|
||||
Reference in new issue
Block a user