- React + TipTap editor with formatting toolbar (bold, italic, underline, strikethrough, alignment, highlight, scene breaks) - Custom image node view with resize and alignment controls; server-side WebP conversion via sharp - Express + SQLite backend with JWT auth and admin user management - Export to PDF, EPUB, and ODT - Five themes (Midnight, Gothic Night, Enchanted Forest, Aged Manuscript, Neon Noir); Lora body font for readability - Writing streak, daily word goal, milestones, and Ollama writing prompts - Docker Compose setup for self-hosted deployment behind NPMplus Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
27 lines
827 B
JavaScript
27 lines
827 B
JavaScript
import { Router } from 'express'
|
|
import bcrypt from 'bcryptjs'
|
|
import jwt from 'jsonwebtoken'
|
|
import db from '../db.js'
|
|
import { JWT_SECRET } from '../middleware/auth.js'
|
|
|
|
const router = Router()
|
|
|
|
router.post('/login', (req, res) => {
|
|
const { email, password } = req.body || {}
|
|
if (!email || !password) return res.status(400).json({ error: 'Email and password required' })
|
|
|
|
const user = db.prepare('SELECT * FROM users WHERE email = ?').get(email)
|
|
if (!user || !bcrypt.compareSync(password, user.password)) {
|
|
return res.status(401).json({ error: 'Wrong email or password' })
|
|
}
|
|
|
|
const token = jwt.sign(
|
|
{ id: user.id, email: user.email, name: user.name },
|
|
JWT_SECRET,
|
|
{ expiresIn: '30d' }
|
|
)
|
|
res.json({ token, user: { id: user.id, email: user.email, name: user.name } })
|
|
})
|
|
|
|
export default router
|