UNPKG

google-oauth-cli-generator

Version:

CLI tool to quickly set up Google OAuth authentication for hackathons and projects

260 lines (232 loc) 8.31 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateFastifyTemplate = generateFastifyTemplate; const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); async function generateFastifyTemplate(data) { const { projectPath, config } = data; const backendPath = path_1.default.join(projectPath, 'backend'); // Create Fastify directory structure await fs_extra_1.default.ensureDir(path_1.default.join(backendPath, 'src', 'routes')); await fs_extra_1.default.ensureDir(path_1.default.join(backendPath, 'src', 'plugins')); await fs_extra_1.default.ensureDir(path_1.default.join(backendPath, 'src', 'config')); if (config.database !== 'none') { await fs_extra_1.default.ensureDir(path_1.default.join(backendPath, 'src', 'models')); } // Generate package.json const packageJson = { name: `${config.projectName}-backend`, version: '1.0.0', private: true, scripts: { dev: 'nodemon src/index.ts', build: 'tsc', start: 'node dist/index.js', 'build:start': 'npm run build && npm run start' }, dependencies: { fastify: '^4.23.2', '@fastify/cors': '^8.4.0', '@fastify/session': '^10.5.0', '@fastify/oauth2': '^7.3.0', '@fastify/cookie': '^9.1.0', dotenv: '^16.3.1', 'node-fetch': '^3.3.2', ...(config.database === 'mongodb' && { mongoose: '^7.5.0' }), ...(config.database === 'postgresql' && { pg: '^8.11.3', '@types/pg': '^8.10.2' }) }, devDependencies: { '@types/node': '^20.8.0', '@types/node-fetch': '^2.6.4', typescript: '^5.2.2', 'ts-node': '^10.9.1', nodemon: '^3.0.1' } }; await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'package.json'), JSON.stringify(packageJson, null, 2)); // Generate tsconfig.json const tsConfig = { compilerOptions: { target: 'ES2020', module: 'commonjs', lib: ['ES2020'], outDir: './dist', rootDir: './src', strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, resolveJsonModule: true }, include: ['src/**/*'], exclude: ['node_modules', 'dist'] }; await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2)); // Generate main server file const indexTs = `import Fastify from 'fastify'; import dotenv from 'dotenv'; import authPlugin from './plugins/auth'; ${config.database === 'mongodb' ? "import { connectDatabase } from './config/database';" : ''} dotenv.config(); const fastify = Fastify({ logger: { level: process.env.NODE_ENV === 'production' ? 'info' : 'debug' } }); const PORT = parseInt(process.env.PORT || '5000'); // Register plugins async function registerPlugins() { // CORS await fastify.register(require('@fastify/cors'), { origin: process.env.FRONTEND_URL || 'http://localhost:3000', credentials: true }); // Cookie support await fastify.register(require('@fastify/cookie')); // Session support await fastify.register(require('@fastify/session'), { secret: process.env.SESSION_SECRET || 'your-session-secret', cookie: { secure: process.env.NODE_ENV === 'production', maxAge: 24 * 60 * 60 * 1000 // 24 hours } }); // Auth plugin await fastify.register(authPlugin); } // Health check route fastify.get('/api/health', async (request, reply) => { return { status: 'OK', message: 'Server is running' }; }); // Start server const start = async () => { try { ${config.database === 'mongodb' ? 'await connectDatabase();' : ''} await registerPlugins(); await fastify.listen({ port: PORT, host: '0.0.0.0' }); console.log(\`🚀 Server running on port \${PORT}\`); console.log(\`📱 Frontend: \${process.env.FRONTEND_URL || 'http://localhost:3000'}\`); console.log(\`🔐 Google OAuth configured: \${process.env.GOOGLE_CLIENT_ID ? '✅' : '❌'}\`); } catch (error) { fastify.log.error(error); process.exit(1); } }; start();`; await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'src', 'index.ts'), indexTs); // Generate auth plugin const authPluginTs = `import { FastifyPluginAsync } from 'fastify'; import fetch from 'node-fetch'; ${config.database !== 'none' ? "import { User } from '../models/User';" : ''} interface UserProfile { id: string; name: string; email: string; picture: string; } ${config.database === 'none' ? ` // In-memory user storage (for demo purposes only) const users: Map<string, UserProfile> = new Map(); ` : ''} interface GoogleUserInfo { id: string; name: string; email: string; picture: string; } const authPlugin: FastifyPluginAsync = async (fastify) => { // Register OAuth2 plugin await fastify.register(require('@fastify/oauth2'), { name: 'googleOAuth2', scope: ['profile', 'email'], credentials: { client: { id: process.env.GOOGLE_CLIENT_ID!, secret: process.env.GOOGLE_CLIENT_SECRET! }, auth: { authorizeHost: 'https://accounts.google.com', authorizePath: '/o/oauth2/v2/auth', tokenHost: 'https://www.googleapis.com', tokenPath: '/oauth2/v4/token' } }, startRedirectPath: '/api/auth/google', callbackUri: process.env.REDIRECT_URI || 'http://localhost:5000/api/auth/google/callback' }); // Google OAuth initiate fastify.get('/api/auth/google', async (request, reply) => { const { token } = await (fastify as any).googleOAuth2.getAccessTokenFromAuthorizationCodeFlow(request); // Get user info from Google const userInfoResponse = await fetch(\`https://www.googleapis.com/oauth2/v1/userinfo?access_token=\${token.access_token}\`); const googleUser: GoogleUserInfo = await userInfoResponse.json() as GoogleUserInfo; const userProfile: UserProfile = { id: googleUser.id, name: googleUser.name, email: googleUser.email, picture: googleUser.picture }; ${config.database === 'none' ? ` // Store user in memory users.set(googleUser.id, userProfile); ` : ` // Check if user exists in database let user = await User.findByGoogleId(googleUser.id); if (!user) { // Create new user await User.create(userProfile); } else { // Update existing user await User.update(googleUser.id, userProfile); } `} // Store user in session request.session.user = userProfile; // Redirect to frontend reply.redirect(process.env.FRONTEND_URL || 'http://localhost:3000'); }); // Get current user fastify.get('/api/auth/user', async (request, reply) => { if (request.session.user) { return request.session.user; } else { reply.code(401).send({ error: 'Not authenticated' }); } }); // Logout fastify.post('/api/auth/logout', async (request, reply) => { request.session.destroy((err: any) => { if (err) { reply.code(500).send({ error: 'Logout failed' }); } else { reply.send({ message: 'Logged out successfully' }); } }); }); }; // Extend session type declare module 'fastify' { interface Session { user?: UserProfile; } } export default authPlugin;`; await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'src', 'plugins', 'auth.ts'), authPluginTs); // Generate nodemon config const nodemonJson = { watch: ['src'], ext: 'ts', ignore: ['src/**/*.test.ts'], exec: 'ts-node src/index.ts' }; await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'nodemon.json'), JSON.stringify(nodemonJson, null, 2)); } //# sourceMappingURL=fastify-template.js.map