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
JavaScript
"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