import fs from 'fs'; import path from 'path'; import { createClient } from '@supabase/supabase-js'; import dotenv from 'dotenv'; dotenv.config(); const supabaseUrl = process.env.VITE_SUPABASE_URL; const supabaseAnonKey = process.env.VITE_SUPABASE_ANON_KEY; if (!supabaseUrl || !supabaseAnonKey) { console.error('Missing Supabase environment variables.'); process.exit(1); } const supabase = createClient(supabaseUrl, supabaseAnonKey); async function syncFile(filePath: string) { console.log(`Syncing: ${filePath}`); const content = fs.readFileSync(filePath, 'utf-8'); // 1. Metadata extractor (Regex based on the MD fields) const nameMatch = content.match(/\*\*User\*\*: (.*)/); const dobMatch = content.match(/\*\*DOB\*\*: (.*)/); const timeMatch = content.match(/\*\*Time\*\*: (.*)/); const userName = nameMatch?.[1]?.trim() || 'Unknown'; const dob = dobMatch?.[1]?.trim() || ''; const birthTimeRaw = timeMatch?.[1]?.trim() || ''; const isEstimate = birthTimeRaw.toLowerCase().includes('estimate: yes'); const birthTime = birthTimeRaw.split(' ')[0]; // 2. Longitude Table extractor (Extracts the block between ## 📊 Longitude Table and the next header) const longTableStart = content.indexOf('## 📊 Longitude Table'); const longTableEnd = content.indexOf('###', longTableStart + 20); const longitudeTable = content.substring(longTableStart, longTableEnd).replace('## 📊 Longitude Table', '').trim(); // 3. Divisional Charts Parser (Extracts the Markdown Table blocks) const charts: Record = {}; const vargaSections = content.split('### ').slice(1); vargaSections.forEach(section => { const lines = section.split('\n'); const headerLine = lines[0].trim(); // e.g. "Rasi (D1)" or "D9" const vargaKey = headerLine.includes('(') ? headerLine.match(/\((.*?)\)/)?.[1] || 'D1' : headerLine; // Extract the markdown table block (lines starting with '|') const tableLines = lines.filter(l => l.trim().startsWith('|')); if (tableLines.length >= 14) { // At least 12 rows + 2 header rows charts[vargaKey] = tableLines.join('\n').trim(); } else if (section.includes('+---')) { // Fallback for raw ASCII if present (like D11) const asciiMatch = section.match(/\+[\s\S]*?\+/); if (asciiMatch) { charts[vargaKey] = asciiMatch[0]; } } }); // 4. Dasha extractor const dashaStart = content.indexOf('**Dasha**:'); const dashaEnd = content.indexOf('**Additional**:', dashaStart); const dasha = content.substring(dashaStart, dashaEnd).replace('**Dasha**:', '').trim(); // 5. Additional Info extractor const additionalStart = content.indexOf('**Additional**:'); const additionalInfo = content.substring(additionalStart).replace('**Additional**:', '').trim(); const rasiChartText = charts['D1'] || charts['Rasi'] || ''; const divisionalCharts: Record = {}; Object.entries(charts).forEach(([k, v]) => { if (k !== 'D1' && k !== 'Rasi') divisionalCharts[k] = v; }); const profileData = { name: userName, dob, birth_time: birthTime, longitude_table: longitudeTable, rasi_chart_text: rasiChartText, divisional_charts: divisionalCharts, dasha, additional_info: additionalInfo, is_birth_time_estimate: isEstimate, updated_at: new Date().toISOString() }; // 6. Upsert to Supabase const { data, error } = await supabase .from('profiles') .upsert(profileData, { onConflict: 'name' }) .select(); if (error) { console.error(`Error syncing ${userName}:`, error.message); } else { console.log(`Successfully synced profile: ${userName}`); } } // CLI Execution const targetFile = process.argv[2]; if (targetFile) { syncFile(targetFile); } else { console.log('Usage: npm run sync-user -- [path-to-file]'); }