Codex fixes
Some checks failed
Deploy Website / build-and-deploy (push) Has been cancelled

This commit is contained in:
2026-05-25 09:49:40 -04:00
parent 78ec3d58e3
commit 014b1836c0
101 changed files with 1048 additions and 7327 deletions

View File

@@ -2,39 +2,86 @@ import Database from 'better-sqlite3';
import type BetterSqlite3 from 'better-sqlite3';
import path from 'path';
import fs from 'fs';
import crypto from 'crypto';
let db: BetterSqlite3.Database | null = null;
let insertStmt: BetterSqlite3.Statement | null = null;
const runtimeAnalyticsSalt = crypto.randomBytes(32).toString('hex');
function getAnalyticsSalt() {
return process.env.ANALYTICS_SALT || runtimeAnalyticsSalt;
}
function getDbPath() {
if (process.env.VISIT_DB_PATH) {
return process.env.VISIT_DB_PATH;
}
const serverStorage = '/server_storage';
try {
fs.mkdirSync(serverStorage, { recursive: true, mode: 0o700 });
fs.accessSync(serverStorage, fs.constants.W_OK);
return path.join(serverStorage, 'visitors.db');
} catch {
const localStorage = path.join(process.cwd(), '.data');
fs.mkdirSync(localStorage, { recursive: true, mode: 0o700 });
return path.join(localStorage, 'visitors.db');
}
}
function createVisitorId(clientAddress: string, userAgent: string) {
const day = new Date().toISOString().slice(0, 10);
return crypto
.createHmac('sha256', getAnalyticsSalt())
.update(`${day}:${clientAddress}:${userAgent}`)
.digest('hex')
.slice(0, 32);
}
function ensureSchema(database: BetterSqlite3.Database) {
database.exec(`
CREATE TABLE IF NOT EXISTS visits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
visitor_id TEXT NOT NULL,
path TEXT NOT NULL,
visited_at TEXT NOT NULL DEFAULT (datetime('now'))
);
`);
const columns = database
.prepare("PRAGMA table_info('visits')")
.all() as { name: string; notnull: number }[];
const columnNames = new Set(columns.map((column) => column.name));
if (!columnNames.has('visitor_id')) {
database.exec("ALTER TABLE visits ADD COLUMN visitor_id TEXT NOT NULL DEFAULT 'legacy'");
columnNames.add('visitor_id');
}
if (!columnNames.has('path')) {
throw new Error('visits table is missing required path column');
}
return {
hasLegacyIpAddress: columnNames.has('ip_address'),
};
}
function getDb() {
if (db) return db;
try {
const SERVER_STORAGE = '/server_storage';
let dbDir: string;
try {
fs.accessSync(SERVER_STORAGE, fs.constants.W_OK);
dbDir = SERVER_STORAGE;
} catch {
dbDir = process.cwd();
}
const dbPath = path.join(dbDir, 'visitors.db');
const dbPath = getDbPath();
db = new Database(dbPath);
db.pragma('busy_timeout = 5000');
db.pragma('journal_mode = WAL');
db.pragma('synchronous = NORMAL');
db.exec(`
CREATE TABLE IF NOT EXISTS visits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip_address TEXT NOT NULL,
path TEXT NOT NULL,
visited_at TEXT NOT NULL DEFAULT (datetime('now'))
);
`);
const schema = ensureSchema(db);
insertStmt = db.prepare(
'INSERT INTO visits (ip_address, path) VALUES (?, ?)'
);
insertStmt = schema.hasLegacyIpAddress
? db.prepare("INSERT INTO visits (ip_address, visitor_id, path) VALUES ('redacted', ?, ?)")
: db.prepare('INSERT INTO visits (visitor_id, path) VALUES (?, ?)');
return db;
} catch (e) {
@@ -45,8 +92,11 @@ function getDb() {
}
}
export function logVisit(ip: string, visitPath: string) {
export function logVisit(clientAddress: string, userAgent: string, visitPath: string) {
const database = getDb();
if (!database || !insertStmt) return;
insertStmt.run(ip, visitPath);
if (!database || !insertStmt) return null;
const visitorId = createVisitorId(clientAddress, userAgent);
insertStmt.run(visitorId, visitPath);
return visitorId;
}