import { ApolloServer } from 'apollo-server'; import { PrismaClient } from '@prisma/client'; import * as fs from 'fs'; import * as path from 'path'; import bcrypt from 'bcryptjs'; import jwt from 'jsonwebtoken'; // Get __dirname equivalent in ES Modules const __dirname = path.dirname(new URL(import.meta.url).pathname); // Load schema.graphql const typeDefs = fs.readFileSync(path.join(__dirname, 'schema.graphql'), 'utf8'); // Initialize Prisma const prisma = new PrismaClient(); const JWT_SECRET = 'your-jwt-secret'; // You should store this in environment variables // Generate JWT token function generateToken(user) { return jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '1h' }); } // GraphQL Resolvers const resolvers = { Query: { info: () => `This is the API of a Hackernews Clone`, feed: async (parent, args, context) => { // Check if the user is authenticated if (!context.user) { throw new Error('Not authenticated'); } // If authenticated, return the feed return context.prisma.link.findMany(); }, }, Mutation: { signup: async (parent, args, context) => { const { email, password, name } = args; // Check if the user already exists const existingUser = await context.prisma.User.findUnique({ where: { email }, }); if (existingUser) { throw new Error('User already exists'); } // Hash the password before storing it const hashedPassword = await bcrypt.hash(password, 10); // Create a new user const user = await context.prisma.User.create({ data: { email, password: hashedPassword, name, }, }); const token = generateToken(user); return { token, user, }; }, login: async (parent, args, context) => { const { email, password } = args; // Find the user by email const user = await context.prisma.user.findUnique({ where: { email }, }); if (!user) { throw new Error('User not found'); } // Check if the password is correct const isValid = await bcrypt.compare(password, user.password); if (!isValid) { throw new Error('Invalid password'); } const token = generateToken(user); return { token, user, }; }, post: (parent, args, context) => { if (!context.user) { throw new Error('Not authenticated'); } const newLink = context.prisma.link.create({ data: { url: args.url, description: args.description, postedById: context.user.id, }, }); return newLink; }, updatePost: async (parent, args, context) => { if (!context.user) { throw new Error('Not authenticated'); } const { id, description, url } = args; const updatedLink = await context.prisma.link.update({ where: { id }, data: { description, url, }, }); return updatedLink; }, deletePost: async (parent, args, context) => { if (!context.user) { throw new Error('Not authenticated'); } const { id } = args; const link = await context.prisma.link.findUnique({ where: { id }, }); if (!link) { throw new Error(`Link with ID ${id} not found`); } const deletedLink = await context.prisma.link.delete({ where: { id }, }); return deletedLink; }, }, }; // Middleware to authenticate users const getUserFromToken = (token) => { try { return jwt.verify(token, JWT_SECRET); } catch (error) { return null; } }; // Initialize Apollo Server const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => { const token = req.headers.authorization || ''; const user = token ? getUserFromToken(token.replace('Bearer ', '')) : null; return { prisma, user, }; }, }); // Start the server server.listen().then(({ url }) => { console.log(`🚀 Server is running at ${url}`); });