UNPKG

google-oauth-cli-generator

Version:

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

399 lines (362 loc) 10.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateNextTemplate = generateNextTemplate; const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); async function generateNextTemplate(data) { const { projectPath } = data; const frontendPath = path_1.default.join(projectPath, 'frontend'); // Create Next.js directory structure await fs_extra_1.default.ensureDir(path_1.default.join(frontendPath, 'src', 'app')); await fs_extra_1.default.ensureDir(path_1.default.join(frontendPath, 'src', 'components')); await fs_extra_1.default.ensureDir(path_1.default.join(frontendPath, 'public')); // Generate package.json const packageJson = { name: `${data.config.projectName}-frontend`, version: '1.0.0', private: true, scripts: { dev: 'next dev', build: 'next build', start: 'next start', lint: 'next lint' }, dependencies: { next: '^14.0.0', react: '^18.2.0', 'react-dom': '^18.2.0', axios: '^1.5.0' }, devDependencies: { '@types/node': '^20.8.0', '@types/react': '^18.2.22', '@types/react-dom': '^18.2.7', eslint: '^8.50.0', 'eslint-config-next': '^14.0.0', typescript: '^5.2.2' } }; await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'package.json'), JSON.stringify(packageJson, null, 2)); // Generate next.config.js const nextConfig = `/** @type {import('next').NextConfig} */ const nextConfig = { async rewrites() { return [ { source: '/api/:path*', destination: 'http://localhost:5000/api/:path*', }, ] }, } module.exports = nextConfig`; await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'next.config.js'), nextConfig); // Generate tsconfig.json const tsConfig = { compilerOptions: { target: 'es5', lib: ['dom', 'dom.iterable', 'es6'], allowJs: true, skipLibCheck: true, strict: true, noEmit: true, esModuleInterop: true, module: 'esnext', moduleResolution: 'bundler', resolveJsonModule: true, isolatedModules: true, jsx: 'preserve', incremental: true, plugins: [ { name: 'next' } ], paths: { '@/*': ['./src/*'] } }, include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'], exclude: ['node_modules'] }; await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2)); // Generate app/layout.tsx const layoutTsx = `import type { Metadata } from 'next' import { Inter } from 'next/font/google' import './globals.css' const inter = Inter({ subsets: ['latin'] }) export const metadata: Metadata = { title: '${data.config.projectName}', description: 'Google OAuth authentication demo', } export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <html lang="en"> <body className={inter.className}>{children}</body> </html> ) }`; await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'src', 'app', 'layout.tsx'), layoutTsx); // Generate app/page.tsx const pageTsx = `'use client' import { useState, useEffect } from 'react' import LoginButton from '@/components/LoginButton' import UserProfile from '@/components/UserProfile' interface User { id: string; name: string; email: string; picture: string; } export default function Home() { const [user, setUser] = useState<User | null>(null); const [loading, setLoading] = useState(true); useEffect(() => { checkAuthStatus(); }, []); const checkAuthStatus = async () => { try { const response = await fetch('/api/auth/user', { credentials: 'include' }); if (response.ok) { const userData = await response.json(); setUser(userData); } } catch (error) { console.error('Auth check failed:', error); } finally { setLoading(false); } }; const handleLogin = () => { window.location.href = '/api/auth/google'; }; const handleLogout = async () => { try { await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }); setUser(null); } catch (error) { console.error('Logout failed:', error); } }; if (loading) { return ( <div className="app"> <div className="loading">Loading...</div> </div> ); } return ( <div className="app"> <header className="app-header"> <h1>🚀 ${data.config.projectName}</h1> <p>Google OAuth Authentication Demo</p> </header> <main className="app-main"> {user ? ( <UserProfile user={user} onLogout={handleLogout} /> ) : ( <LoginButton onLogin={handleLogin} /> )} </main> </div> ) }`; await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'src', 'app', 'page.tsx'), pageTsx); // Generate components/LoginButton.tsx (same as React version) const loginButtonTsx = `interface LoginButtonProps { onLogin: () => void; } export default function LoginButton({ onLogin }: LoginButtonProps) { return ( <div className="login-container"> <h2>Welcome! Please sign in</h2> <button className="google-login-btn" onClick={onLogin} > <svg className="google-icon" viewBox="0 0 24 24"> <path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/> <path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/> <path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/> <path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/> </svg> Sign in with Google </button> </div> ); }`; await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'src', 'components', 'LoginButton.tsx'), loginButtonTsx); // Generate components/UserProfile.tsx (same as React version) const userProfileTsx = `interface User { id: string; name: string; email: string; picture: string; } interface UserProfileProps { user: User; onLogout: () => void; } export default function UserProfile({ user, onLogout }: UserProfileProps) { return ( <div className="profile-container"> <div className="profile-card"> <img src={user.picture} alt={user.name} className="profile-picture" /> <h2>Welcome, {user.name}!</h2> <p className="profile-email">{user.email}</p> <button className="logout-btn" onClick={onLogout} > Sign Out </button> </div> </div> ); }`; await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'src', 'components', 'UserProfile.tsx'), userProfileTsx); // Generate app/globals.css (same styles as React version) const globalsCss = `* { box-sizing: border-box; padding: 0; margin: 0; } html, body { max-width: 100vw; overflow-x: hidden; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .app { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .app-header h1 { font-size: 3rem; margin-bottom: 0.5rem; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); } .app-header p { font-size: 1.2rem; opacity: 0.9; margin-bottom: 2rem; } .loading { font-size: 1.5rem; animation: pulse 1.5s ease-in-out infinite alternate; } @keyframes pulse { from { opacity: 0.6; } to { opacity: 1; } } .login-container { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 20px; padding: 3rem; box-shadow: 0 8px 32px rgba(0,0,0,0.1); border: 1px solid rgba(255, 255, 255, 0.2); } .login-container h2 { margin-bottom: 2rem; font-size: 1.8rem; } .google-login-btn { display: flex; align-items: center; justify-content: center; gap: 12px; background: white; color: #333; border: none; border-radius: 12px; padding: 16px 32px; font-size: 16px; font-weight: 500; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 12px rgba(0,0,0,0.15); } .google-login-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0,0,0,0.2); } .google-icon { width: 20px; height: 20px; } .profile-container { display: flex; justify-content: center; align-items: center; } .profile-card { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 20px; padding: 3rem; box-shadow: 0 8px 32px rgba(0,0,0,0.1); border: 1px solid rgba(255, 255, 255, 0.2); text-align: center; } .profile-picture { width: 120px; height: 120px; border-radius: 50%; margin-bottom: 1.5rem; border: 4px solid rgba(255, 255, 255, 0.3); box-shadow: 0 4px 12px rgba(0,0,0,0.2); } .profile-card h2 { margin-bottom: 0.5rem; font-size: 2rem; } .profile-email { opacity: 0.8; margin-bottom: 2rem; font-size: 1.1rem; } .logout-btn { background: rgba(255, 255, 255, 0.2); color: white; border: 2px solid rgba(255, 255, 255, 0.3); border-radius: 12px; padding: 12px 24px; font-size: 16px; cursor: pointer; transition: all 0.3s ease; } .logout-btn:hover { background: rgba(255, 255, 255, 0.3); transform: translateY(-2px); }`; await fs_extra_1.default.writeFile(path_1.default.join(frontendPath, 'src', 'app', 'globals.css'), globalsCss); } //# sourceMappingURL=next-template.js.map