#!/usr/bin/env node /** * ๐Ÿงช Testing Environment Supabase Setup Script * * This script helps you set up the testing Supabase environment with the required * exec_sql function and database schema. */ const { createClient } = require('@supabase/supabase-js'); const fs = require('fs'); const path = require('path'); console.log('๐Ÿงช Testing Environment Supabase Setup'); console.log('=====================================\n'); // Check if .env exists (which is configured for testing) const envPath = path.join(__dirname, '.env'); if (!fs.existsSync(envPath)) { console.log('โŒ Environment file not found: .env'); console.log('Please ensure the .env file exists and is configured for testing'); process.exit(1); } // Load environment require('dotenv').config({ path: envPath }); const supabaseUrl = process.env.SUPABASE_URL; const supabaseServiceKey = process.env.SUPABASE_SERVICE_KEY; if (!supabaseUrl || !supabaseServiceKey) { console.log('โŒ Missing Supabase credentials in .env.testing'); console.log('Please ensure SUPABASE_URL and SUPABASE_SERVICE_KEY are set'); process.exit(1); } console.log('โœ… Testing environment loaded'); console.log(`๐Ÿ“ก Supabase URL: ${supabaseUrl}`); console.log(`๐Ÿ”‘ Service Key: ${supabaseServiceKey.substring(0, 20)}...\n`); const supabase = createClient(supabaseUrl, supabaseServiceKey); async function createExecSqlFunction() { console.log('๐Ÿ”„ Creating exec_sql function...'); const execSqlFunction = ` CREATE OR REPLACE FUNCTION exec_sql(sql text) RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN EXECUTE sql; END; $$; `; try { // Try to execute the function creation directly const { error } = await supabase.rpc('exec_sql', { sql: execSqlFunction }); if (error) { console.log('โš ๏ธ exec_sql function not available, trying direct SQL execution...'); // If exec_sql doesn't exist, we need to create it manually console.log('๐Ÿ“ You need to manually create the exec_sql function in your Supabase SQL Editor:'); console.log('\n' + execSqlFunction); console.log('\n๐Ÿ“‹ Instructions:'); console.log('1. Go to your Supabase Dashboard'); console.log('2. Navigate to SQL Editor'); console.log('3. Paste the above SQL and execute it'); console.log('4. Run this script again'); return false; } console.log('โœ… exec_sql function created successfully'); return true; } catch (error) { console.log('โŒ Error creating exec_sql function:', error.message); return false; } } async function setupDatabaseSchema() { console.log('\n๐Ÿ”„ Setting up database schema...'); try { // Create users table console.log('๐Ÿ“‹ Creating users table...'); const { error: usersError } = await supabase.rpc('exec_sql', { sql: ` CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), firebase_uid VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(255), email VARCHAR(255) UNIQUE NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); ` }); if (usersError) { console.log(`โŒ Users table error: ${usersError.message}`); } else { console.log('โœ… Users table created successfully'); } // Create documents table console.log('๐Ÿ“‹ Creating documents table...'); const { error: docsError } = await supabase.rpc('exec_sql', { sql: ` CREATE TABLE IF NOT EXISTS documents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id VARCHAR(255) NOT NULL, original_file_name VARCHAR(255) NOT NULL, file_path TEXT NOT NULL, file_size BIGINT NOT NULL, status VARCHAR(50) DEFAULT 'uploaded', extracted_text TEXT, generated_summary TEXT, error_message TEXT, analysis_data JSONB, processing_completed_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); ` }); if (docsError) { console.log(`โŒ Documents table error: ${docsError.message}`); } else { console.log('โœ… Documents table created successfully'); } // Create processing_jobs table console.log('๐Ÿ“‹ Creating processing_jobs table...'); const { error: jobsError } = await supabase.rpc('exec_sql', { sql: ` CREATE TABLE IF NOT EXISTS processing_jobs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), document_id UUID REFERENCES documents(id) ON DELETE CASCADE, user_id VARCHAR(255) NOT NULL, status VARCHAR(50) DEFAULT 'pending', processing_strategy VARCHAR(50), started_at TIMESTAMP WITH TIME ZONE, completed_at TIMESTAMP WITH TIME ZONE, error_message TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); ` }); if (jobsError) { console.log(`โŒ Processing jobs table error: ${jobsError.message}`); } else { console.log('โœ… Processing jobs table created successfully'); } // Create indexes console.log('๐Ÿ“‹ Creating indexes...'); const indexSql = ` CREATE INDEX IF NOT EXISTS idx_documents_user_id ON documents(user_id); CREATE INDEX IF NOT EXISTS idx_documents_status ON documents(status); CREATE INDEX IF NOT EXISTS idx_documents_created_at ON documents(created_at); CREATE INDEX IF NOT EXISTS idx_processing_jobs_document_id ON processing_jobs(document_id); CREATE INDEX IF NOT EXISTS idx_processing_jobs_status ON processing_jobs(status); CREATE INDEX IF NOT EXISTS idx_processing_jobs_user_id ON processing_jobs(user_id); `; const { error: indexError } = await supabase.rpc('exec_sql', { sql: indexSql }); if (indexError) { console.log(`โŒ Index creation error: ${indexError.message}`); } else { console.log('โœ… Indexes created successfully'); } console.log('\nโœ… Database schema setup completed'); return true; } catch (error) { console.log('โŒ Database schema setup failed:', error.message); return false; } } async function setupVectorDatabase() { console.log('\n๐Ÿ”„ Setting up vector database...'); try { // Read the vector setup script const vectorSetupPath = path.join(__dirname, 'backend', 'supabase_vector_setup.sql'); if (!fs.existsSync(vectorSetupPath)) { console.log('โš ๏ธ Vector setup script not found, skipping vector database setup'); return true; } const sqlScript = fs.readFileSync(vectorSetupPath, 'utf8'); const statements = sqlScript .split(';') .map(stmt => stmt.trim()) .filter(stmt => stmt.length > 0 && !stmt.startsWith('--')); console.log(`๐Ÿ“ Executing ${statements.length} vector setup statements...`); for (let i = 0; i < statements.length; i++) { const statement = statements[i]; if (statement.trim()) { console.log(` Executing statement ${i + 1}/${statements.length}...`); const { error } = await supabase.rpc('exec_sql', { sql: statement }); if (error) { console.log(` โš ๏ธ Statement ${i + 1} error: ${error.message}`); } else { console.log(` โœ… Statement ${i + 1} executed successfully`); } } } console.log('โœ… Vector database setup completed'); return true; } catch (error) { console.log('โŒ Vector database setup failed:', error.message); return false; } } async function main() { console.log('๐Ÿš€ Starting testing environment setup...\n'); // Step 1: Create exec_sql function const execSqlCreated = await createExecSqlFunction(); if (!execSqlCreated) { console.log('\nโŒ Setup cannot continue without exec_sql function'); console.log('Please create the function manually and run this script again'); process.exit(1); } // Step 2: Setup database schema const schemaCreated = await setupDatabaseSchema(); if (!schemaCreated) { console.log('\nโŒ Database schema setup failed'); process.exit(1); } // Step 3: Setup vector database const vectorCreated = await setupVectorDatabase(); if (!vectorCreated) { console.log('\nโš ๏ธ Vector database setup failed, but continuing...'); } console.log('\n๐ŸŽ‰ Testing environment setup completed successfully!'); console.log('\n๐Ÿ“‹ Next steps:'); console.log('1. Run the deployment script: ./deploy-testing.sh'); console.log('2. Test the authentication improvements'); console.log('3. Verify the 401 upload error is resolved'); } main().catch(error => { console.error('โŒ Setup failed:', error); process.exit(1); });