diff --git a/client/package-lock.json b/client/package-lock.json index 68f3c57..adf6f99 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -345,16 +345,20 @@ "node": ">=6.9.0" } }, - "node_modules/@esbuild/darwin-arm64": { + + "node_modules/@esbuild/win32-x64": { "version": "0.25.3", "cpu": [ - "arm64" + "x64" + ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + + "win32" + ], "engines": { "node": ">=18" @@ -494,6 +498,7 @@ "license": "MIT", "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } }, "node_modules/@humanfs/core": { @@ -512,10 +517,12 @@ "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" }, + "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { "version": "0.3.1", "dev": true, @@ -534,24 +541,14 @@ "license": "Apache-2.0", "engines": { "node": ">=12.22" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, + "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "dev": true, @@ -727,6 +724,7 @@ "@types/react": { "optional": true } + } }, "node_modules/@radix-ui/react-focus-scope": { @@ -736,6 +734,7 @@ "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1" + }, "peerDependencies": { "@types/react": "*", @@ -752,27 +751,36 @@ } } }, + "node_modules/@radix-ui/react-id": { "version": "1.1.1", "license": "MIT", "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, + "node_modules/@radix-ui/react-portal": { "version": "1.1.6", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { @@ -790,12 +798,14 @@ } } }, + "node_modules/@radix-ui/react-presence": { "version": "1.1.4", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" + }, "peerDependencies": { "@types/react": "*", @@ -812,27 +822,25 @@ } } }, + "node_modules/@radix-ui/react-primitive": { "version": "2.1.0", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.0" }, + "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, + "node_modules/@radix-ui/react-slot": { "version": "1.2.0", "license": "MIT", @@ -849,6 +857,7 @@ } } }, + "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "license": "MIT", @@ -879,6 +888,7 @@ } } }, + "node_modules/@radix-ui/react-use-effect-event": { "version": "0.0.2", "license": "MIT", @@ -924,8 +934,10 @@ } } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.40.0", + + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.40.1", + "cpu": [ "arm64" ], @@ -933,7 +945,9 @@ "license": "MIT", "optional": true, "os": [ - "darwin" + + "win32" + ] }, "node_modules/@tailwindcss/node": { @@ -1045,8 +1059,6 @@ }, "node_modules/@types/howler": { "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@types/howler/-/howler-2.2.12.tgz", - "integrity": "sha512-hy769UICzOSdK0Kn1FBk4gN+lswcj1EKRkmiDtMkUGvFfYJzgaDXmVXkSShS2m89ERAatGIPnTUlp2HhfkVo5g==", "dev": true, "license": "MIT" }, @@ -1073,8 +1085,6 @@ }, "node_modules/@types/react-howler": { "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/react-howler/-/react-howler-5.2.3.tgz", - "integrity": "sha512-0XJ+vHLgobVcc8G8f3jlnfIv3FVnUvEuxOyq3TwW9qNBeko7EhHDc9QYtY7mUTcrT86mPTAVCKWitY+TyzHWZw==", "dev": true, "license": "MIT", "dependencies": { @@ -1102,7 +1112,8 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.31.0", + "version": "8.31.1", + "dev": true, "license": "MIT", "dependencies": { @@ -1130,7 +1141,9 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.31.0", + + "version": "8.31.1", + "dev": true, "license": "MIT", "dependencies": { @@ -1153,7 +1166,9 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.31.0", + + "version": "8.31.1", + "dev": true, "license": "MIT", "dependencies": { @@ -1169,7 +1184,9 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.31.0", + + "version": "8.31.1", + "dev": true, "license": "MIT", "dependencies": { @@ -1191,7 +1208,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.31.0", + + "version": "8.31.1", + "dev": true, "license": "MIT", "engines": { @@ -1203,7 +1222,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.31.0", + + "version": "8.31.1", + "dev": true, "license": "MIT", "dependencies": { @@ -1261,7 +1282,9 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.31.0", + + "version": "8.31.1", + "dev": true, "license": "MIT", "dependencies": { @@ -1283,7 +1306,9 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.31.0", + + "version": "8.31.1", + "dev": true, "license": "MIT", "dependencies": { @@ -1638,7 +1663,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.143", + + "version": "1.5.144", + "dev": true, "license": "ISC" }, @@ -2069,8 +2096,6 @@ }, "node_modules/howler": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz", - "integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==", "license": "MIT" }, "node_modules/ignore": { @@ -2250,17 +2275,20 @@ "lightningcss-win32-x64-msvc": "1.29.2" } }, - "node_modules/lightningcss-darwin-arm64": { + + "node_modules/lightningcss-win32-x64-msvc": { "version": "1.29.2", "cpu": [ - "arm64" + "x64" + ], "dev": true, "license": "MPL-2.0", "optional": true, "os": [ - "darwin" - ], + + "win32" + "engines": { "node": ">= 12.0.0" }, @@ -2583,8 +2611,6 @@ }, "node_modules/react-howler": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-howler/-/react-howler-5.2.0.tgz", - "integrity": "sha512-oDK+zML0MHf3nVNM4lMxh+re87NDa7fHowea2WK8197yqnMiZfPVHoMXtfb/PtuoOsWLO06vmEAtovwTRWpTFg==", "license": "MIT", "dependencies": { "howler": "^2.2.0", @@ -2647,7 +2673,9 @@ } }, "node_modules/react-router": { - "version": "7.5.2", + + "version": "7.5.3", + "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -2668,10 +2696,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.5.2", + + "version": "7.5.3", + "license": "MIT", "dependencies": { - "react-router": "7.5.2" + "react-router": "7.5.3" }, "engines": { "node": ">=20.0.0" @@ -2735,7 +2765,9 @@ } }, "node_modules/rollup": { - "version": "4.40.0", + + "version": "4.40.1", + "dev": true, "license": "MIT", "dependencies": { @@ -2982,7 +3014,9 @@ } }, "node_modules/typescript-eslint": { - "version": "8.31.0", + + "version": "8.31.1", + "dev": true, "license": "MIT", "dependencies": { diff --git a/client/vite.config.ts b/client/vite.config.ts index e02c105..2428004 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -1,21 +1,18 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; -import path from 'path'; +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +// https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], - resolve: { - alias: { - '@': path.resolve(__dirname, 'src'), - }, - }, server: { + port: 3000, + open: true, proxy: { - '/api': { - target: 'http://localhost:3001', // Your backend port + '/graphql': { + target: 'http://localhost:3001/', changeOrigin: true, secure: false, }, }, }, -}); +}) \ No newline at end of file diff --git a/server/package-lock.json b/server/package-lock.json index 58d7164..814e95f 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -14,7 +14,7 @@ "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^5.1.0", - "graphql": "^16.10.0", + "graphql": "^16.11.0", "jsonwebtoken": "^9.0.2", "multer": "^1.4.5-lts.2", "openai": "^4.96.0" diff --git a/server/package.json b/server/package.json index b555474..a3b27e8 100644 --- a/server/package.json +++ b/server/package.json @@ -5,9 +5,9 @@ "main": "index.js", "scripts": { "start": "node dist/server.js", + "dev": "nodemon --watch src --exec ts-node src/server.ts", "build": "tsc", "test": "echo \"Error: no test specified\" && exit 1", - "dev": "nodemon index.ts", "watch": "nodemon dist/server.js" }, "keywords": [], @@ -20,7 +20,7 @@ "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^5.1.0", - "graphql": "^16.10.0", + "graphql": "^16.11.0", "jsonwebtoken": "^9.0.2", "multer": "^1.4.5-lts.2", "openai": "^4.96.0" diff --git a/server/seed.ts b/server/seed.ts deleted file mode 100644 index b6a8c75..0000000 --- a/server/seed.ts +++ /dev/null @@ -1,29 +0,0 @@ -import mongoose from "mongoose"; -import dotenv from "dotenv"; -import User from "../server/src/models/User"; -import { Question } from "../server/src/models/Questions"; - -dotenv.config(); - -async function seedDatabase() { - await mongoose.connect(process.env.MONGODB_URI!); - - // Wipe collections - await User.deleteMany({}); - await Question.deleteMany({}); - - // Seed data - await User.create({ username: "playerOne", email: "player@example.com", password: "123456" }); - await Question.insertMany([ - { prompt: "Explain closures in JavaScript", difficulty: "hard" }, - { prompt: "What is a component in React?", difficulty: "easy" } - ]); - - console.log("🌱 Seeding complete!"); - mongoose.connection.close(); -} - -seedDatabase().catch((error) => { - console.error("Error seeding database:", error); - mongoose.connection.close(); -}); diff --git a/server/src/config/connections.ts b/server/src/config/connections.ts index 41ad3cc..ada07f4 100644 --- a/server/src/config/connections.ts +++ b/server/src/config/connections.ts @@ -17,3 +17,4 @@ const db = async (): Promise => { }; export default db; + diff --git a/server/src/schemas/typeDefs.ts b/server/src/schemas/typeDefs.ts index cb40de0..a1b57eb 100644 --- a/server/src/schemas/typeDefs.ts +++ b/server/src/schemas/typeDefs.ts @@ -26,12 +26,20 @@ const typeDefs = gql` choices: [String!]! answer: String! } + type Character { + _id: ID + name: String! + picture: String! + voice: String! + } type Query { users: [User] user(username: String!): User me: User generateQuestion(track: String!, level: String!, minion: String!): Question + characters: [Character]! + } type Mutation { diff --git a/server/src/server.ts b/server/src/server.ts index 86478b2..dee3c59 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1,71 +1,54 @@ -import express, { type Request, type Response } from 'express'; - +import express, { Application, Request, Response } from 'express'; import dotenv from 'dotenv'; import { OpenAI } from 'openai'; - import path from 'path'; import { ApolloServer } from '@apollo/server'; -import { expressMiddleware } from '@apollo/server/express4'; -import typeDefs from './schemas/typeDefs'; -import resolvers from './schemas/resolvers'; -import { authenticateToken } from './utils/auth'; - - -// Extend the Request interface to include the user property -declare global { - namespace Express { - interface Request { - user?: any; // Replace 'any' with the appropriate type for your user object - } - } -} +// import { expressMiddleware } from '@apollo/server/express4'; +import { typeDefs, resolvers } from './schemas/index'; +import db from './config/connections'; +// import { authenticateToken } from './utils/auth.js'; dotenv.config(); - const app = express(); - const PORT = process.env.PORT || 3001; - const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! }); +const app: Application = express(); +const PORT = process.env.PORT || 3001; +const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! }); - // Create a new instance of an Apollo server with the GraphQL schema - const startApolloServer = async () => { - const server = new ApolloServer({ - typeDefs, - resolvers, - }); +const server = new ApolloServer({ + typeDefs, + resolvers, +}); - const startApolloServer = async () => { - await server.start(); - await db; +const startApolloServer = async () => { + await server.start(); + await db(); - app.use(express.static('public')); // serve generated mp3 file - app.use(express.urlencoded({ extended: false })); - app.use(express.json()); - - app.use('/graphql', expressMiddleware(server as any, - { - context: authenticateToken as any - } - )); - // if we're in production, serve client/build as static assets - if (process.env.NODE_ENV === 'production') { - app.use(express.static(path.join(__dirname, '../client/dist'))); - - app.get('*', (_req: Request, res: Response) => { - res.sendFile(path.join(__dirname, '../client/dist/index.html')); - }); - } + app.use(express.urlencoded({ extended: false })); + app.use(express.json()); - // Start the server - app.listen(PORT, () => { - console.log(`✅ Server is running on http://localhost:${PORT}`); - console.log(`✅ GraphQL endpoint is available at http://localhost:${PORT}/graphql`); - }); - }; + // Apollo Server v4 middleware with correct typing + const authenticateToken = async ({ req }: { req: Request }) => { + const token = (req.headers.authorization as string | undefined)?.split(' ')[1]; + let user = null; + + if (token) { + try { + const { verifyToken } = require('./utils/auth'); + user = verifyToken(token); + } catch (err) { + console.error('Token verification failed:', err); + } + } + // Serve static files in production + app.use(express.static(path.join(__dirname, '../client/dist'))); + app.get('*', (_req: Request, res: Response) => { + res.sendFile(path.join(__dirname, '../client/dist/index.html')); + }); + } - // TTS Route for Dr. Dan + // POST /api/tts - OpenAI text-to-speech app.post('/api/tts', async (req: Request, res: Response) => { const { text } = req.body; - try { const speech = await openai.audio.speech.create({ model: 'tts-1', @@ -83,8 +66,14 @@ dotenv.config(); }); // Root route - app.get('/', (req: Request, res: Response) => { + app.get('/', (_req: Request, res: Response) => { res.send('🎙️ Codezilla server is up!'); }); -startApolloServer(); \ No newline at end of file + app.listen(PORT, () => { + console.log(`✅ Server is running on http://localhost:${PORT}`); + console.log(`✅ GraphQL endpoint is available at http://localhost:${PORT}/graphql`); + }); +}; + +startApolloServer(); diff --git a/server/src/utils/auth.ts b/server/src/utils/auth.ts index e0efdd3..ccb89ae 100644 --- a/server/src/utils/auth.ts +++ b/server/src/utils/auth.ts @@ -43,7 +43,7 @@ export const authMiddleware = ({ req }: { req: any }) => { }; export const authenticateToken = async ({ req }: { req: Request }) => { - const authHeader = req.headers.authorization; + const authHeader = req.headers.get('authorization'); let user = null; console.log('AUTH HEADER', authHeader);