#!/usr/bin/env node /** * Apply SurrealDB schema from db/schema.surql */ const Surreal = require('surrealdb').default; const fs = require('fs'); const path = require('path'); async function applySchema() { const db = new Surreal(); try { console.log('[Schema] Connecting to SurrealDB...'); await db.connect('http://localhost:8000/rpc'); console.log('[Schema] Signing in...'); await db.signin({ username: 'root', password: 'root', }); console.log('[Schema] Using namespace and database...'); await db.use({ namespace: 'ponderants', database: 'main', }); console.log('[Schema] Reading schema file...'); const schemaPath = path.join(__dirname, '..', 'db', 'schema.surql'); let schema = fs.readFileSync(schemaPath, 'utf-8'); // Load environment variables from .env file manually const envPath = path.join(__dirname, '..', '.env'); const envContent = fs.readFileSync(envPath, 'utf-8'); const envVars = {}; envContent.split('\n').forEach(line => { const match = line.match(/^([^#][^=]*)=(.*)$/); if (match) { envVars[match[1].trim()] = match[2].trim(); } }); // Replace $env.SURREALDB_JWT_SECRET with actual value const jwtSecret = envVars.SURREALDB_JWT_SECRET; if (!jwtSecret) { throw new Error('SURREALDB_JWT_SECRET not found in .env file'); } schema = schema.replace('$env.SURREALDB_JWT_SECRET', `'${jwtSecret}'`); console.log('[Schema] Executing schema...'); let result; try { result = await db.query(schema); } catch (error) { // If error contains "already exists", it's OK - schema was already applied if (error.message.includes('already exists')) { console.log('[Schema] ⚠ Some schema elements already exist (this is OK)'); console.log('[Schema] Continuing to ensure new tables are created...'); // Try to create just the new OAuth tables const oauthSchema = ` DEFINE TABLE oauth_state SCHEMAFULL; DEFINE FIELD key ON TABLE oauth_state TYPE string ASSERT $value != NONE; DEFINE FIELD value ON TABLE oauth_state TYPE object ASSERT $value != NONE; DEFINE FIELD created_at ON TABLE oauth_state TYPE datetime DEFAULT time::now(); DEFINE INDEX oauth_state_key_idx ON TABLE oauth_state COLUMNS key UNIQUE; DEFINE EVENT oauth_state_cleanup ON TABLE oauth_state WHEN time::now() - created_at > 1h THEN ( DELETE oauth_state WHERE id = $event.id ); DEFINE TABLE oauth_session SCHEMAFULL; DEFINE FIELD did ON TABLE oauth_session TYPE string ASSERT $value != NONE; DEFINE FIELD session_data ON TABLE oauth_session TYPE object ASSERT $value != NONE; DEFINE FIELD updated_at ON TABLE oauth_session TYPE datetime DEFAULT time::now(); DEFINE INDEX oauth_session_did_idx ON TABLE oauth_session COLUMNS did UNIQUE; `; try { result = await db.query(oauthSchema); } catch (oauthError) { if (oauthError.message.includes('already exists')) { console.log('[Schema] ✓ OAuth tables already exist'); console.log('[Schema] ✓ Schema is up to date!'); return; } throw oauthError; } } else { throw error; } } if (result) { console.log(`[Schema] Executed ${result.length} queries`); // Log any errors result.forEach((r, i) => { if (r.status === 'ERR') { console.error(`[Schema] Error in query ${i + 1}:`, r.result); } else { console.log(`[Schema] ✓ Query ${i + 1} succeeded`); } }); } console.log('[Schema] ✓ Schema applied successfully!'); } catch (error) { console.error('[Schema] ✗ Failed to apply schema:', error); process.exit(1); } finally { await db.close(); } } applySchema();