// src/index.js export default { async fetch(request, env, ctx) { const url = new URL(request.url); // API endpoints if (url.pathname === '/api/chat') { return handleChat(request, env); } if (url.pathname === '/api/generate') { return handleDirectGeneration(request, env); } // NEW: Auth endpoints if (url.pathname === '/api/auth') { return handleAuth(request, env); } if (url.pathname === '/api/login') { return handleLogin(request, env); } // Serve the enhanced interface return new Response(generateEnhancedInterface(), { headers: { 'Content-Type': 'text/html' } }); } }; // NEW: Auth handler for magic links async function handleAuth(request, env) { if (request.method !== 'POST') { return new Response('Method not allowed', { status: 405 }); } try { const { email } = await request.json(); if (!email || !email.includes('@')) { return new Response(JSON.stringify({ error: 'Valid email required' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } // Generate magic token const token = crypto.randomUUID(); const expires = Date.now() + (24 * 60 * 60 * 1000); // 24 hours // Store in D1 await env.DB.prepare( 'INSERT INTO auth_tokens (token, email, expires) VALUES (?, ?, ?)' ).bind(token, email, expires).run(); // For MVP testing - in production, send email instead const magicLink = `${url.origin}/api/login?token=${token}`; return new Response(JSON.stringify({ message: "Magic link created! Check your email (or use the link below for testing)", magicLink, // Remove in production expiresIn: "24 hours" }), { headers: { 'Content-Type': 'application/json' } }); } catch (error) { return new Response(JSON.stringify({ error: 'Failed to create magic link' }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } } // NEW: Login handler async function handleLogin(request, env) { const url = new URL(request.url); const token = url.searchParams.get('token'); if (!token) { return new Response('Token required', { status: 400 }); } try { // Verify token const result = await env.DB.prepare( 'SELECT * FROM auth_tokens WHERE token = ? AND expires > ? AND used = 0' ).bind(token, Date.now()).first(); if (!result) { return new Response('Invalid or expired token', { status: 401 }); } // Mark as used await env.DB.prepare( 'UPDATE auth_tokens SET used = 1 WHERE token = ?' ).bind(token).run(); // Create or get user let user = await env.DB.prepare( 'SELECT * FROM users WHERE email = ?' ).bind(result.email).first(); if (!user) { const userId = crypto.randomUUID(); await env.DB.prepare( 'INSERT INTO users (id, email) VALUES (?, ?)' ).bind(userId, result.email).run(); user = { id: userId, email: result.email }; } // Create session const sessionToken = crypto.randomUUID(); await env.NOVELS.put( `session:${sessionToken}`, JSON.stringify(user), { expirationTtl: 30 * 24 * 60 * 60 } // 30 days ); // Redirect with session return Response.redirect( `${url.origin}/?session=${sessionToken}`, 302 ); } catch (error) { return new Response('Login failed', { status: 500 }); } } // Update your existing functions to include the script section with auth function generateEnhancedInterface() { return `
Your AI-Powered Publishing House