{
  "name": "express-prisma-api",
  "description": "Express.js REST API with Prisma ORM and middleware",
  "files": {
    "package.json": "{\"name\":\"api-server\",\"dependencies\":{\"express\":\"4.18.0\",\"@prisma/client\":\"5.0.0\",\"cors\":\"2.8.5\",\"helmet\":\"7.0.0\",\"express-rate-limit\":\"7.0.0\",\"jsonwebtoken\":\"9.0.0\"},\"devDependencies\":{\"typescript\":\"5.3.0\",\"@types/express\":\"4.17.0\",\"@types/node\":\"20.0.0\",\"prisma\":\"5.0.0\"}}",
    "tsconfig.json": "{\"compilerOptions\":{\"target\":\"es2017\",\"module\":\"commonjs\",\"outDir\":\"dist\"}}",
    ".env.example": "DATABASE_URL=postgresql://localhost:5432/api\nJWT_SECRET=changeme\nPORT=3000\nREDIS_URL=redis://localhost:6379\nCORS_ORIGIN=http://localhost:3001",
    "prisma/schema.prisma": "datasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n\ngenerator client {\n  provider = \"prisma-client-js\"\n}\n\nmodel User {\n  id        Int      @id @default(autoincrement())\n  email     String   @unique\n  password  String\n  name      String?\n  role      Role     @default(USER)\n  posts     Post[]\n  createdAt DateTime @default(now())\n}\n\nmodel Post {\n  id        Int       @id @default(autoincrement())\n  title     String\n  content   String?\n  published Boolean   @default(false)\n  author    User      @relation(fields: [authorId], references: [id])\n  authorId  Int\n  tags      Tag[]\n  createdAt DateTime  @default(now())\n}\n\nmodel Tag {\n  id    Int    @id @default(autoincrement())\n  name  String @unique\n  posts Post[]\n}\n\nenum Role {\n  USER\n  ADMIN\n}",
    "src/index.ts": "import express from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport { authRouter } from './routes/auth';\nimport { usersRouter } from './routes/users';\nimport { postsRouter } from './routes/posts';\nimport { errorHandler } from './middleware/error';\nimport { rateLimiter } from './middleware/rate-limit';\n\nconst app = express();\n\napp.use(cors());\napp.use(helmet());\napp.use(express.json());\napp.use(rateLimiter);\n\napp.use('/api/auth', authRouter);\napp.use('/api/users', usersRouter);\napp.use('/api/posts', postsRouter);\n\napp.use(errorHandler);\n\napp.listen(process.env.PORT || 3000);",
    "src/routes/auth.ts": "import { Router } from 'express';\nimport { prisma } from '../lib/prisma';\nimport { generateToken } from '../lib/jwt';\n\nexport const authRouter = Router();\n\nauthRouter.post('/login', async (req, res) => {\n  const { email, password } = req.body;\n  const user = await prisma.user.findUnique({ where: { email } });\n  if (!user) return res.status(401).json({ error: 'Invalid credentials' });\n  const token = generateToken(user.id);\n  res.json({ token });\n});\n\nauthRouter.post('/register', async (req, res) => {\n  const { email, password, name } = req.body;\n  const user = await prisma.user.create({ data: { email, password, name } });\n  const token = generateToken(user.id);\n  res.status(201).json({ token });\n});",
    "src/routes/users.ts": "import { Router } from 'express';\nimport { prisma } from '../lib/prisma';\nimport { authenticate } from '../middleware/auth';\n\nexport const usersRouter = Router();\n\nusersRouter.get('/', authenticate, async (req, res) => {\n  const users = await prisma.user.findMany();\n  res.json(users);\n});\n\nusersRouter.get('/:id', authenticate, async (req, res) => {\n  const user = await prisma.user.findUnique({ where: { id: parseInt(req.params.id) } });\n  res.json(user);\n});\n\nusersRouter.put('/:id', authenticate, async (req, res) => {\n  const user = await prisma.user.update({ where: { id: parseInt(req.params.id) }, data: req.body });\n  res.json(user);\n});\n\nusersRouter.delete('/:id', authenticate, async (req, res) => {\n  await prisma.user.delete({ where: { id: parseInt(req.params.id) } });\n  res.json({ deleted: true });\n});",
    "src/routes/posts.ts": "import { Router } from 'express';\nimport { prisma } from '../lib/prisma';\nimport { authenticate } from '../middleware/auth';\n\nexport const postsRouter = Router();\n\npostsRouter.get('/', async (req, res) => {\n  const posts = await prisma.post.findMany({ include: { author: true, tags: true } });\n  res.json(posts);\n});\n\npostsRouter.get('/:id', async (req, res) => {\n  const post = await prisma.post.findUnique({ where: { id: parseInt(req.params.id) }, include: { author: true, tags: true } });\n  res.json(post);\n});\n\npostsRouter.post('/', authenticate, async (req, res) => {\n  const post = await prisma.post.create({ data: { ...req.body, authorId: req.userId } });\n  res.status(201).json(post);\n});\n\npostsRouter.put('/:id', authenticate, async (req, res) => {\n  const post = await prisma.post.update({ where: { id: parseInt(req.params.id) }, data: req.body });\n  res.json(post);\n});\n\npostsRouter.delete('/:id', authenticate, async (req, res) => {\n  await prisma.post.delete({ where: { id: parseInt(req.params.id) } });\n  res.json({ deleted: true });\n});",
    "src/middleware/auth.ts": "import { Request, Response, NextFunction } from 'express';\nimport { verifyToken } from '../lib/jwt';\n\nexport function authenticate(req: Request, res: Response, next: NextFunction) {\n  const token = req.headers.authorization?.replace('Bearer ', '');\n  if (!token) return res.status(401).json({ error: 'No token' });\n  try {\n    const payload = verifyToken(token);\n    (req as any).userId = payload.userId;\n    next();\n  } catch {\n    res.status(401).json({ error: 'Invalid token' });\n  }\n}",
    "src/middleware/error.ts": "import { Request, Response, NextFunction } from 'express';\n\nexport function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {\n  console.error(err.stack);\n  res.status(500).json({ error: 'Internal server error' });\n}",
    "src/middleware/rate-limit.ts": "import rateLimit from 'express-rate-limit';\n\nexport const rateLimiter = rateLimit({\n  windowMs: 15 * 60 * 1000,\n  max: 100,\n  message: { error: 'Too many requests' }\n});",
    "src/lib/prisma.ts": "import { PrismaClient } from '@prisma/client';\n\nexport const prisma = new PrismaClient();",
    "src/lib/jwt.ts": "import jwt from 'jsonwebtoken';\n\nconst SECRET = process.env.JWT_SECRET || 'dev-secret';\n\nexport function generateToken(userId: number): string {\n  return jwt.sign({ userId }, SECRET, { expiresIn: '24h' });\n}\n\nexport function verifyToken(token: string): { userId: number } {\n  return jwt.verify(token, SECRET) as { userId: number };\n}"
  }
}
