/** * Auth Feature - Database * Creates and drops zen_auth_* tables. */ import { query, tableExists } from '@zen/core/database'; import { done, warn } from '@zen/core/shared/logger'; import { createTables as createUserCoreTables, dropTables as dropUserCoreTables } from '../../core/users/db.js'; const AUTH_TABLES = [ { name: 'zen_auth_users', sql: ` CREATE TABLE zen_auth_users ( id text NOT NULL PRIMARY KEY, name text NOT NULL, email text NOT NULL UNIQUE, email_verified boolean NOT NULL DEFAULT false, image text, created_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL, updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL, role text DEFAULT 'user' CHECK (role IN ('admin', 'user')) ) ` }, { name: 'zen_auth_sessions', sql: ` CREATE TABLE zen_auth_sessions ( id text NOT NULL PRIMARY KEY, expires_at timestamptz NOT NULL, token text NOT NULL UNIQUE, created_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL, updated_at timestamptz NOT NULL, ip_address text, user_agent text, user_id text NOT NULL REFERENCES zen_auth_users (id) ON DELETE CASCADE ) ` }, { name: 'zen_auth_accounts', sql: ` CREATE TABLE zen_auth_accounts ( id text NOT NULL PRIMARY KEY, account_id text NOT NULL, provider_id text NOT NULL, user_id text NOT NULL REFERENCES zen_auth_users (id) ON DELETE CASCADE, access_token text, refresh_token text, id_token text, access_token_expires_at timestamptz, refresh_token_expires_at timestamptz, scope text, password text, created_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL, updated_at timestamptz NOT NULL ) ` }, { name: 'zen_auth_verifications', sql: ` CREATE TABLE zen_auth_verifications ( id text NOT NULL PRIMARY KEY, identifier text NOT NULL, value text NOT NULL, token text NOT NULL, expires_at timestamptz NOT NULL, created_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL, updated_at timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ) ` } ]; /** * Create all authentication tables. * @returns {Promise<{ created: string[], skipped: string[] }>} */ export async function createTables() { const created = []; const skipped = []; for (const table of AUTH_TABLES) { const exists = await tableExists(table.name); if (!exists) { await query(table.sql); created.push(table.name); done(`Created table: ${table.name}`); } else { skipped.push(table.name); } } // Create role/permission tables and seed defaults const coreResult = await createUserCoreTables(); created.push(...coreResult.created); skipped.push(...coreResult.skipped); return { created, skipped }; } /** * Drop all authentication tables in reverse dependency order. * @returns {Promise} */ export async function dropTables() { const dropOrder = [...AUTH_TABLES].reverse().map(t => t.name); warn('Dropping all Zen authentication tables...'); for (const tableName of dropOrder) { const exists = await tableExists(tableName); if (exists) { await query(`DROP TABLE IF EXISTS "${tableName}" CASCADE`); done(`Dropped table: ${tableName}`); } } await dropUserCoreTables(); done('All authentication tables dropped'); }