/** * Chat unread state lives on the server so it survives reloads and agrees * across tabs and devices: `users.chat_read_at` is the created_at of the newest * message the user has seen. Existing users start caught up (now) rather than * with the whole history unread; new users fall back to their own created_at. * * The history cursor now pages on (created_at, id) so two messages sharing a * millisecond can't be skipped at a page boundary; the index follows suit. * * Idempotent: also runs against fresh databases created from schema.sql, where * the column and index already exist. * * @module */ import type { DatabaseSync } from "node:sqlite"; /** Applies this migration to `db`. */ export function up(db: DatabaseSync): void { const cols = db.prepare(`PRAGMA table_info(users);`).all() as { name: string; }[]; if (!cols.some((c) => c.name === "chat_read_at")) { db.exec(`ALTER TABLE users ADD COLUMN chat_read_at TEXT;`); db.prepare(`UPDATE users SET chat_read_at = ?;`).run( new Date().toISOString(), ); } db.exec(`DROP INDEX IF EXISTS idx_chat_messages_created;`); db.exec( `CREATE INDEX IF NOT EXISTS idx_chat_messages_created_id ON chat_messages(created_at, id);`, ); }