diff --git a/artifacts/api-server/src/index.ts b/artifacts/api-server/src/index.ts index 944efc8..3efdf09 100644 --- a/artifacts/api-server/src/index.ts +++ b/artifacts/api-server/src/index.ts @@ -81,6 +81,38 @@ async function ensureToolRelationsTable(): Promise { } } +async function ensureUserColumns(): Promise { + try { + const cols = await db.execute( + sql`SELECT column_name FROM information_schema.columns WHERE table_name = 'users'`, + ); + const existing = new Set((cols.rows as [{ column_name: string }]).map((r) => r.column_name)); + const toAdd: { name: string; def: string }[] = []; + if (!existing.has("tier")) toAdd.push({ name: "tier", def: "text NOT NULL DEFAULT 'free'" }); + if (!existing.has("auth_provider")) toAdd.push({ name: "auth_provider", def: "text NOT NULL DEFAULT 'local'" }); + if (!existing.has("auth_provider_id")) toAdd.push({ name: "auth_provider_id", def: "text" }); + if (!existing.has("display_name")) toAdd.push({ name: "display_name", def: "text" }); + if (!existing.has("password_hash")) { + toAdd.push({ name: "password_hash", def: "text" }); + } else { + const [ph] = await db.execute( + sql`SELECT is_nullable FROM information_schema.columns WHERE table_name = 'users' AND column_name = 'password_hash'`, + ); + const nullable = (ph.rows as [{ is_nullable: string }])[0]?.is_nullable; + if (nullable === "NO") { + await db.execute(sql`ALTER TABLE "users" ALTER COLUMN "password_hash" DROP NOT NULL`); + } + } + for (const col of toAdd) { + const stmt = `ALTER TABLE "users" ADD COLUMN "${col.name}" ${col.def}`; + await db.execute(sql.raw(stmt)); + logger.info({ column: col.name }, "Added column to users table"); + } + } catch (err) { + logger.error({ err }, "Failed to ensure user columns"); + } +} + async function ensureToolCostsTable(): Promise { try { const exists = await db.execute(