UNPKG

@neurolint/cli

Version:

NeuroLint CLI for React/Next.js modernization with advanced 6-layer orchestration and intelligent AST transformations

243 lines (201 loc) 6.2 kB
const { createClient } = require('@supabase/supabase-js'); const fs = require('fs-extra'); const path = require('path'); const os = require('os'); require('dotenv').config(); // Validate required environment variables const SUPABASE_URL = process.env.SUPABASE_URL; const SUPABASE_ANON_KEY = process.env.SUPABASE_ANON_KEY; if (!SUPABASE_URL || !SUPABASE_ANON_KEY) { console.error('Missing required environment variables: SUPABASE_URL and SUPABASE_ANON_KEY'); process.exit(1); } // Use production Supabase configuration const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY); class AuthManager { constructor() { this.user = null; this.configPath = path.join(os.homedir(), '.neurolint', 'config.json'); this.loadStoredAuth(); } async loadStoredAuth() { try { if (await fs.pathExists(this.configPath)) { const config = await fs.readJson(this.configPath); if (config.session) { const { data, error } = await supabase.auth.setSession(config.session); if (!error && data.user) { this.user = data.user; } } } } catch (error) { // Ignore auth loading errors - user will need to login } } async saveSession(session) { try { await fs.ensureDir(path.dirname(this.configPath)); await fs.writeJson(this.configPath, { session }, { spaces: 2 }); } catch (error) { console.warn('Failed to save session:', error.message); } } async login(email, password) { try { const { data, error } = await supabase.auth.signInWithPassword({ email, password }); if (error) throw error; this.user = data.user; // Save session for persistent login if (data.session) { await this.saveSession(data.session); } // Get or create user profile await this.ensureUserProfile(); return { success: true, user: data.user }; } catch (error) { return { success: false, error: error.message }; } } async signup(email, password) { try { const { data, error } = await supabase.auth.signUp({ email, password }); if (error) throw error; return { success: true, user: data.user, needsConfirmation: !data.session }; } catch (error) { return { success: false, error: error.message }; } } async logout() { try { await supabase.auth.signOut(); this.user = null; // Clear stored session if (await fs.pathExists(this.configPath)) { await fs.remove(this.configPath); } return { success: true }; } catch (error) { return { success: false, error: error.message }; } } async ensureUserProfile() { if (!this.user) return; try { // Check if profile exists const { data: existingProfile } = await supabase .from('user_profiles') .select('*') .eq('id', this.user.id) .single(); if (!existingProfile) { // Create profile with free tier defaults const { error } = await supabase .from('user_profiles') .insert({ id: this.user.id, email: this.user.email, tier: 'free', usage: { remainingFixes: 5, usedFixes: 0, monthlyResetDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString() } }); if (error) { console.warn('Failed to create user profile:', error.message); } } } catch (error) { console.warn('Failed to ensure user profile:', error.message); } } isAuthenticated() { return !!this.user; } getUserId() { return this.user?.id; } getUserEmail() { return this.user?.email; } async checkUsageLimit(action) { if (!this.user) { return { canUse: false, reason: 'Authentication required' }; } try { const { data: profile, error } = await supabase .from('user_profiles') .select('tier, usage') .eq('id', this.user.id) .single(); if (error) throw error; const tier = profile.tier || 'free'; const usage = profile.usage || { remainingFixes: 5 }; // Tier limits from your plan const limits = { free: { analyze: -1, fix: 5 }, // unlimited analyze, 5 fixes basic: { analyze: -1, fix: 2000 }, professional: { analyze: -1, fix: -1 }, business: { analyze: -1, fix: -1 }, enterprise: { analyze: -1, fix: -1 }, premium: { analyze: -1, fix: -1 } }; const tierLimits = limits[tier] || limits.free; const actionLimit = tierLimits[action]; if (actionLimit === -1) { return { canUse: true }; // unlimited } if (usage.remainingFixes > 0) { return { canUse: true, remaining: usage.remainingFixes }; } return { canUse: false, reason: `${tier} tier limit reached. Upgrade at https://neurolint.dev/pricing` }; } catch (error) { console.error('Usage check failed:', error); return { canUse: false, reason: 'Unable to verify usage limits' }; } } async recordUsage(action, metadata = {}) { if (!this.user) return; try { // Record usage log const { error: logError } = await supabase .from('usage_logs') .insert({ user_id: this.user.id, action, metadata, timestamp: new Date().toISOString() }); if (logError) { console.warn('Failed to log usage:', logError.message); } // Decrement remaining fixes for fix actions if (action === 'fix') { const { error: updateError } = await supabase.rpc('decrement_user_fixes', { p_user_id: this.user.id, p_count: metadata.filesFixed || 1 }); if (updateError) { console.warn('Failed to update usage limits:', updateError.message); } } } catch (error) { console.warn('Failed to record usage:', error.message); } } } module.exports = { AuthManager, supabase };