@shivasankaran18/stackd 2.0.1 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +12 -7
  2. package/apps/cli/src/cli.ts +2 -28
  3. package/apps/cli/src/commands/create.ts +0 -30
  4. package/apps/cli/src/generators/auth/jwt.js +83 -0
  5. package/apps/cli/src/generators/auth/nextAuth.js +146 -0
  6. package/apps/cli/src/generators/auth/passport.js +234 -0
  7. package/apps/cli/src/generators/backend/django.js +30 -0
  8. package/apps/cli/src/generators/backend/expressjs.js +72 -0
  9. package/apps/cli/src/generators/backend/expressts.js +95 -0
  10. package/apps/cli/src/generators/frontend/angularts.js +29 -0
  11. package/apps/cli/src/generators/frontend/reactjs.js +42 -0
  12. package/apps/cli/src/generators/frontend/reactts.d.ts +13 -0
  13. package/apps/cli/src/generators/frontend/reactts.js +40 -0
  14. package/apps/cli/src/generators/frontend/vuejs.js +43 -0
  15. package/apps/cli/src/generators/frontend/vuets.js +53 -0
  16. package/apps/cli/src/generators/orm/drizzleSetup.js +102 -0
  17. package/apps/cli/src/generators/orm/mongoSetup.js +68 -0
  18. package/apps/cli/src/generators/orm/prismaSetup.js +14 -0
  19. package/apps/cli/src/generators/ui/shadcn.js +228 -0
  20. package/apps/cli/src/generators/ui/tailwindcss.js +126 -0
  21. package/apps/cli/src/scripts/backend/expressts.ts +1 -1
  22. package/apps/cli/src/scripts/frontend/angularts.ts +4 -2
  23. package/apps/cli/src/scripts/frontend/reactjs.ts +3 -2
  24. package/apps/cli/src/scripts/frontend/reactts.ts +3 -2
  25. package/apps/cli/src/scripts/orms/prismaSetup.ts +2 -2
  26. package/apps/cli/src/scripts/ui/shadcn.ts +10 -4
  27. package/apps/web/app/api/scaffold/route.ts +7 -7
  28. package/apps/web/app/scaffold/page.tsx +1 -1
  29. package/apps/web/package.json +2 -1
  30. package/apps/web/tsconfig.json +20 -108
  31. package/package.json +3 -33
  32. package/packages/typescript-config/base.json +19 -0
  33. package/packages/typescript-config/nextjs.json +12 -0
  34. package/packages/typescript-config/package.json +9 -0
  35. package/packages/typescript-config/react-library.json +7 -0
  36. package/packages/ui/eslint.config.mjs +4 -0
  37. package/packages/ui/package.json +27 -0
  38. package/packages/ui/src/button.tsx +20 -0
  39. package/packages/ui/src/card.tsx +27 -0
  40. package/packages/ui/src/code.tsx +11 -0
  41. package/packages/ui/tsconfig.json +8 -0
  42. package/packages/ui/turbo/generators/config.ts +30 -0
  43. package/packages/ui/turbo/generators/templates/component.hbs +8 -0
  44. package/stackd.ts +17 -7
  45. package/apps/cli/src/scripts/ui/tailwind.ts +0 -39
package/README.md CHANGED
@@ -14,7 +14,7 @@ STACKD (Abbreviation TBD) is an open-source scaffolding tool that simplifies the
14
14
 
15
15
  ## 💡 Motivation
16
16
 
17
- Every time my team and I participated in a hackathon, we found ourselves spending a significant amount of time setting up the project’s basic structure—configuring the frontend, backend, database, authentication, and other essential components. The same challenge extends to professionals in the industry, where initial setup can be tedious and time-consuming. To solve this, we created STACKD—a tool that eliminates repetitive setup tasks, allowing developers to focus on building their applications right away.
17
+ We got the motive to build this application because every time me and my team went for a hackathon, it used to take a lot of time to set up the project with basic things like frontend, UI setup, backend, ORM connection, authentication, and other configurations. People in the work environment also struggle with this, so we came up with this idea. STACKD allows programmers to jump directly into coding instead of spending time on tedious setup tasks.
18
18
 
19
19
  ## 🚀 Features
20
20
 
@@ -74,7 +74,7 @@ https://github.com/user-attachments/assets/465451f2-1e1a-48b6-a99e-253ef4f28e2d
74
74
  - NextAuth
75
75
  - Passport
76
76
 
77
- ### 🛆 Installation
77
+ ## 📦 Installation
78
78
 
79
79
  ### Prerequisites
80
80
 
@@ -83,17 +83,22 @@ Make sure you have the following installed on your system:
83
83
  - Node.js
84
84
  - Git
85
85
 
86
- ### Using `npm`
86
+ ### CLI Tool
87
+
88
+ To scaffold a new full-stack project, run:
87
89
 
88
90
  ```sh
89
- npm i @shivasankaran18/stackd
90
- npx stackd create
91
+ npm create @shivasankaran18/stackd new proj-name
91
92
  ```
92
93
 
93
- ### Using `npx`
94
+ This will prompt you with setup questions and generate the project with the selected configurations.
95
+
96
+ ### Web Tool
97
+
98
+ To launch the web-based setup tool locally, use:
94
99
 
95
100
  ```sh
96
- npx @shivasankaran18/stackd create
101
+ npx @shivasankaran18/create-stackd setup
97
102
  ```
98
103
 
99
104
  ## ⚡ Usage
@@ -15,7 +15,6 @@ export interface ProjectConfig {
15
15
  orm: string;
16
16
  auth: string;
17
17
  dbUrl: string;
18
- ui: string;
19
18
  }
20
19
 
21
20
  interface Answers {
@@ -28,8 +27,7 @@ interface Answers {
28
27
  orm: string;
29
28
  auth: string;
30
29
  dbUrl: string;
31
- projectName: string;
32
- ui: string;
30
+ projectName:string;
33
31
  }
34
32
 
35
33
  const showBanner = () => {
@@ -69,9 +67,7 @@ const CHOICES = {
69
67
  MONGOOSE: 'Mongoose',
70
68
  JWT: 'JWT',
71
69
  NEXTAUTH: 'NextAuth',
72
- PASSPORT: 'Passport',
73
- TAILWIND: 'Tailwind CSS',
74
- SHADCN: 'shadcn/ui + Tailwind'
70
+ PASSPORT: 'Passport'
75
71
  };
76
72
 
77
73
  program
@@ -128,27 +124,6 @@ program
128
124
  }
129
125
  ]);
130
126
 
131
- // Add UI framework selection after frontend
132
- let uiChoice = { ui: CHOICES.NONE };
133
- if (frontendChoice.frontend !== chalk.green(CHOICES.DJANGO_TEMPLATES) &&
134
- frontendChoice.frontend !== CHOICES.SKIP) {
135
- uiChoice = await inquirer.prompt([
136
- {
137
- type: 'list',
138
- name: 'ui',
139
- message: chalk.magenta.bold('🎨 Choose a UI framework:'),
140
- choices: (answers) => {
141
- const isReact = frontendChoice.frontend.includes('React');
142
- return [
143
- chalk.blue(CHOICES.TAILWIND),
144
- ...(isReact ? [chalk.cyan(CHOICES.SHADCN)] : []),
145
- CHOICES.NONE
146
- ];
147
- },
148
- default: CHOICES.NONE,
149
- }
150
- ]);
151
- }
152
127
 
153
128
  const backendChoice = await inquirer.prompt([
154
129
  {
@@ -235,7 +210,6 @@ program
235
210
  const answers = {
236
211
  ...projectSettings,
237
212
  ...frontendChoice,
238
- ...uiChoice,
239
213
  ...backendChoice,
240
214
  ...databaseChoice,
241
215
  ...ormChoice,
@@ -16,8 +16,6 @@ import chalk from 'chalk';
16
16
  import ora from 'ora';
17
17
  import { mkdir } from 'fs/promises';
18
18
  import { ProjectConfig } from '../cli.js';
19
- import { setupShadcn } from '../scripts/ui/shadcn.js';
20
- import { setupTailwindCSS } from '../scripts/ui/tailwindcss.js';
21
19
 
22
20
  const emitLog = (message: string): void => {
23
21
  console.log(`[Emit Logs]: ${message}`);
@@ -66,24 +64,6 @@ export async function createProject(projectName: string, options: ProjectConfig)
66
64
  break;
67
65
  }
68
66
 
69
- // UI Framework setup
70
- if (options.ui !== 'None' && options.frontend !== 'Django Templates' && options.frontend !== 'Skip') {
71
- spinner.text = 'Setting up UI framework...';
72
- switch(options.ui) {
73
- case 'Tailwind CSS':
74
- await setupTailwindCSS(config, projectDir, emitLog);
75
- break;
76
- case 'shadcn/ui + Tailwind':
77
- await setupTailwindCSS(config, projectDir, emitLog);
78
- // @ts-ignore
79
- await setupShadcn(config, projectDir, emitLog);
80
- break;
81
- default:
82
- emitLog('Unknown UI framework choice');
83
- break;
84
- }
85
- }
86
-
87
67
  // Backend setup
88
68
  spinner.text = 'Setting up backend...';
89
69
  switch(options.backend) {
@@ -163,16 +143,6 @@ export async function createProject(projectName: string, options: ProjectConfig)
163
143
  }
164
144
  }
165
145
 
166
- // Add UI-specific instructions
167
- if (options.ui !== 'None') {
168
- console.log(chalk.yellow('\nUI Framework Setup:'));
169
- if (options.ui === 'Tailwind CSS') {
170
- console.log(chalk.cyan(' Tailwind CSS is ready to use'));
171
- } else if (options.ui === 'shadcn/ui + Tailwind') {
172
- console.log(chalk.cyan(' Run `npx shadcn-ui@latest init` to complete shadcn/ui setup'));
173
- }
174
- }
175
-
176
146
  // Add database specific instructions
177
147
  if (options.database !== 'Skip') {
178
148
  console.log(chalk.yellow('\nDatabase Setup:'));
@@ -0,0 +1,83 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import fs from 'fs';
4
+
5
+ export async function jwtAuthts(config, projectDir,emitLog) {
6
+ emitLog('Installing jsonwebtoken...');
7
+ const packageJsonPath = join(projectDir, 'backend','package.json');
8
+ const jsonData = await JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
9
+ emitLog('Updating package.json...');
10
+ jsonData.dependencies = jsonData.dependencies || {};
11
+ jsonData.dependencies["jsonwebtoken"] = "^9.0.2";
12
+
13
+ fs.writeFileSync(packageJsonPath, JSON.stringify(jsonData, null, 2), 'utf8');
14
+ emitLog('Writing jwt.ts...');
15
+ const jwtAuthFile = `
16
+ const jwt = require('jsonwebtoken');
17
+ export const authenticateToken = (req:any, res:any, next:any) => {
18
+ const token = req.header('Authorization')?.split(' ')[1];
19
+ if (!token) return res.status(401).json({ error: 'Access Denied' });
20
+
21
+ jwt.verify(token, process.env.JWT_SECRET, (err:any, user:any) => {
22
+ if (err) return res.status(403).json({ error: 'Invalid Token' });
23
+ req.user = user;
24
+ next();
25
+ });
26
+ };
27
+ `;
28
+ emitLog('Writing middleware.ts...');
29
+ const middlewareDir = join(projectDir, 'backend', 'src', 'middleware');
30
+ await mkdir(middlewareDir, { recursive: true });
31
+ emitLog('Writing middleware.ts...');
32
+ await writeFile(join(middlewareDir, 'middleware.ts'), jwtAuthFile, 'utf8');
33
+ emitLog('✅ JWT authentication setup completed successfully!');
34
+ }
35
+
36
+ export async function jwtAuthdjango(config , projectDir ,emitLog) {
37
+ emitLog('Installing jsonwebtoken...');
38
+ const settingsPath = join(projectDir, 'backend', 'core', 'settings.py');
39
+ emitLog('Updating settings.py...');
40
+ try {
41
+ let settingsContent = fs.readFileSync(settingsPath, 'utf8');
42
+ const restFrameworkSettings = `
43
+
44
+ REST_FRAMEWORK = {
45
+ 'DEFAULT_AUTHENTICATION_CLASSES': [
46
+ 'rest_framework_simplejwt.authentication.JWTAuthentication',
47
+ ],
48
+ }
49
+ `;
50
+
51
+ const installedAppsIndex = settingsContent.indexOf('INSTALLED_APPS');
52
+ const insertPosition = settingsContent.indexOf(']', installedAppsIndex) + 1;
53
+
54
+ settingsContent =
55
+ settingsContent.slice(0, insertPosition) +
56
+ restFrameworkSettings +
57
+ settingsContent.slice(insertPosition);
58
+
59
+ fs.writeFileSync(settingsPath, settingsContent, 'utf8');
60
+ emitLog('Writing urls.py...');
61
+ let urlsContent = fs.readFileSync(`${projectDir}/backend/core/urls.py`, 'utf8');
62
+ const newUrlsContent = `from django.contrib import admin
63
+ from django.urls import path, include
64
+ from rest_framework_simplejwt import views as jwt_views
65
+
66
+ urlpatterns = [
67
+ path('admin/', admin.site.urls),
68
+ path('api/token/',
69
+ jwt_views.TokenObtainPairView.as_view(),
70
+ name='token_obtain_pair'),
71
+ path('api/token/refresh/',
72
+ jwt_views.TokenRefreshView.as_view(),
73
+ name='token_refresh'),
74
+ path('', include('main.urls')),
75
+ ]
76
+ `;
77
+ fs.writeFileSync(`${projectDir}/backend/core/urls.py`, newUrlsContent, 'utf8');
78
+ emitLog('✅ JWT authentication setup completed successfully!');
79
+ } catch (error) {
80
+ console.error('Error configuring Django settings:', error);
81
+ throw error;
82
+ }
83
+ }
@@ -0,0 +1,146 @@
1
+ import { join } from 'node:path'
2
+ import { mkdir, writeFile } from 'node:fs/promises'
3
+ import 'dotenv/config'
4
+
5
+ export async function setupNextAuth(config, projectDir,emitLog) {
6
+ try {
7
+ const authDir = join(projectDir, 'frontend', 'src', 'app', 'api', 'auth');
8
+ await mkdir(authDir, { recursive: true });
9
+ emitLog('Creating auth directory...');
10
+ const routeCode = `
11
+ import NextAuth from "next-auth";
12
+ import { AuthOptions } from "next-auth";
13
+ import GithubProvider from "next-auth/providers/github";
14
+ import GoogleProvider from "next-auth/providers/google";
15
+ import CredentialsProvider from "next-auth/providers/credentials";
16
+ export const authOptions: AuthOptions = {
17
+ providers: [
18
+ GithubProvider({
19
+ clientId: process.env.GITHUB_ID!,
20
+ clientSecret: process.env.GITHUB_SECRET!,
21
+ }),
22
+ GoogleProvider({
23
+ clientId: process.env.GOOGLE_CLIENT_ID!,
24
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
25
+ }),
26
+ CredentialsProvider({
27
+ name: 'Credentials',
28
+ credentials: {
29
+ email: { label: "Email", type: "email" },
30
+ password: { label: "Password", type: "password" }
31
+ },
32
+ async authorize(credentials) {
33
+ // Add your credentials logic here
34
+ if (!credentials?.email || !credentials?.password) return null;
35
+
36
+ try {
37
+ // Example user verification
38
+ const user = { id: "1", email: credentials.email, name: "User" };
39
+ return user;
40
+ } catch (error) {
41
+ return null;
42
+ }
43
+ }
44
+ }),
45
+ ],
46
+ pages: {
47
+ signIn: '/auth/signin',
48
+ signOut: '/auth/signout',
49
+ error: '/auth/error',
50
+ },
51
+ callbacks: {
52
+ async jwt({ token, user }) {
53
+ if (user) {
54
+ token.id = user.id;
55
+ }
56
+ return token;
57
+ },
58
+ async session({ session, token }) {
59
+ if (session.user) {
60
+ (session.user as any).id = token.id;
61
+ }
62
+ return session;
63
+ },
64
+ },
65
+ session: {
66
+ strategy: "jwt",
67
+ },
68
+ secret: process.env.NEXTAUTH_SECRET,
69
+ };
70
+
71
+ const handler = NextAuth(authOptions);
72
+ export { handler as GET, handler as POST };
73
+ `;
74
+
75
+ await writeFile(
76
+ join(authDir, 'route.ts'),
77
+ routeCode.trim() + '\n'
78
+ );
79
+
80
+ const utilsDir = join(projectDir, 'frontend', 'src', 'utils');
81
+ await mkdir(utilsDir, { recursive: true });
82
+ emitLog('Creating utils directory...');
83
+ const utilsCode = `
84
+ import { getServerSession } from "next-auth/next";
85
+ import { authOptions } from "@/app/api/auth/route";
86
+
87
+ export async function getSession() {
88
+ return await getServerSession(authOptions);
89
+ }
90
+
91
+ export async function getCurrentUser() {
92
+ const session = await getSession();
93
+ return session?.user;
94
+ }
95
+
96
+ export async function isAuthenticated() {
97
+ const session = await getSession();
98
+ return !!session;
99
+ }
100
+ `;
101
+ emitLog('Writing utils.ts...');
102
+ await writeFile(
103
+ join(utilsDir, 'auth.ts'),
104
+ utilsCode.trim() + '\n'
105
+ );
106
+
107
+ const envContent = `
108
+ # NextAuth Configuration
109
+ NEXTAUTH_SECRET=your-secret-key-here
110
+ NEXTAUTH_URL=http://localhost:${config.frontendPort}
111
+
112
+ # OAuth Providers
113
+ GITHUB_ID=your-github-id
114
+ GITHUB_SECRET=your-github-secret
115
+
116
+ GOOGLE_CLIENT_ID=your-google-client-id
117
+ GOOGLE_CLIENT_SECRET=your-google-client-secret
118
+ `;
119
+ emitLog('Writing .env file...');
120
+ await writeFile(
121
+ join(projectDir, 'frontend', '.env'),
122
+ envContent.trim() + '\n'
123
+ );
124
+ emitLog('Writing AuthProvider.tsx...');
125
+ const providerCode = `
126
+ 'use client';
127
+
128
+ import { SessionProvider } from "next-auth/react";
129
+
130
+ export function AuthProvider({ children }: { children: React.ReactNode }) {
131
+ return <SessionProvider>{children}</SessionProvider>;
132
+ }
133
+ `;
134
+ emitLog('Creating components directory...');
135
+ const providersDir = join(projectDir, 'frontend', 'src', 'components', 'auth');
136
+ await mkdir(providersDir, { recursive: true });
137
+ await writeFile(
138
+ join(providersDir, 'AuthProvider.tsx'),
139
+ providerCode.trim() + '\n'
140
+ );
141
+ emitLog('✅ NextAuth setup completed successfully!');
142
+ } catch (error) {
143
+ emitLog(`❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
144
+ throw error;
145
+ }
146
+ }
@@ -0,0 +1,234 @@
1
+ import { join } from 'node:path'
2
+ import { mkdir, writeFile } from 'node:fs/promises'
3
+
4
+ export async function setupPassport(config, projectDir,emitLog) {
5
+ emitLog('Setting up Passport...');
6
+ try {
7
+ const backendDir = join(projectDir, 'backend');
8
+ const authDir = join(backendDir, 'src', 'auth');
9
+ const configDir = join(backendDir, 'src', 'config');
10
+ emitLog('Creating auth and config directories...');
11
+ await mkdir(authDir, { recursive: true });
12
+ await mkdir(configDir, { recursive: true });
13
+
14
+ const passportConfigCode = `
15
+ import passport from 'passport';
16
+ import { Strategy as LocalStrategy } from 'passport-local';
17
+ import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt';
18
+ import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
19
+ import { User } from '../models/user.model';
20
+ import { config } from '../config';
21
+
22
+ // Local Strategy
23
+ passport.use(new LocalStrategy(
24
+ { usernameField: 'email' },
25
+ async (email, password, done) => {
26
+ try {
27
+ const user = await User.findOne({ email });
28
+ if (!user) {
29
+ return done(null, false, { message: 'Incorrect email.' });
30
+ }
31
+
32
+ const isValid = await user.comparePassword(password);
33
+ if (!isValid) {
34
+ return done(null, false, { message: 'Incorrect password.' });
35
+ }
36
+
37
+ return done(null, user);
38
+ } catch (error) {
39
+ return done(error);
40
+ }
41
+ }
42
+ ));
43
+
44
+ // JWT Strategy
45
+ passport.use(new JwtStrategy(
46
+ {
47
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
48
+ secretOrKey: config.jwt.secret,
49
+ },
50
+ async (payload, done) => {
51
+ try {
52
+ const user = await User.findById(payload.sub);
53
+ if (!user) {
54
+ return done(null, false);
55
+ }
56
+ return done(null, user);
57
+ } catch (error) {
58
+ return done(error, false);
59
+ }
60
+ }
61
+ ));
62
+
63
+ // Google OAuth Strategy
64
+ passport.use(new GoogleStrategy(
65
+ {
66
+ clientID: config.google.clientId,
67
+ clientSecret: config.google.clientSecret,
68
+ callbackURL: '/auth/google/callback',
69
+ },
70
+ async (accessToken, refreshToken, profile, done) => {
71
+ try {
72
+ let user = await User.findOne({ googleId: profile.id });
73
+
74
+ if (!user) {
75
+ user = await User.create({
76
+ googleId: profile.id,
77
+ email: profile.emails?.[0]?.value,
78
+ name: profile.displayName,
79
+ });
80
+ }
81
+
82
+ return done(null, user);
83
+ } catch (error) {
84
+ return done(error, false);
85
+ }
86
+ }
87
+ ));
88
+
89
+ // Serialization
90
+ passport.serializeUser((user: any, done) => {
91
+ done(null, user.id);
92
+ });
93
+
94
+ passport.deserializeUser(async (id: string, done) => {
95
+ try {
96
+ const user = await User.findById(id);
97
+ done(null, user);
98
+ } catch (error) {
99
+ done(error);
100
+ }
101
+ });
102
+
103
+ export default passport;
104
+ `;
105
+ emitLog('Writing passport.config.ts...');
106
+ await writeFile(
107
+ join(authDir, 'passport.config.ts'),
108
+ passportConfigCode.trim() + '\n'
109
+ );
110
+ emitLog('Creating authentication middleware...');
111
+ const authMiddlewareCode = `
112
+ import { Request, Response, NextFunction } from 'express';
113
+ import passport from 'passport';
114
+ import jwt from 'jsonwebtoken';
115
+ import { config } from '../config';
116
+
117
+ export const authenticateJWT = passport.authenticate('jwt', { session: false });
118
+
119
+ export const authenticateLocal = (req: Request, res: Response, next: NextFunction) => {
120
+ passport.authenticate('local', { session: false }, (err, user, info) => {
121
+ if (err) {
122
+ return next(err);
123
+ }
124
+ if (!user) {
125
+ return res.status(401).json({ message: info?.message || 'Authentication failed' });
126
+ }
127
+
128
+ const token = jwt.sign({ sub: user.id }, config.jwt.secret, {
129
+ expiresIn: config.jwt.expiresIn,
130
+ });
131
+
132
+ req.user = user;
133
+ res.locals.token = token;
134
+ next();
135
+ })(req, res, next);
136
+ };
137
+
138
+ export const isAuthenticated = (req: Request, res: Response, next: NextFunction) => {
139
+ if (req.isAuthenticated()) {
140
+ return next();
141
+ }
142
+ res.status(401).json({ message: 'Unauthorized' });
143
+ };
144
+ `;
145
+ emitLog('Writing middleware.ts...');
146
+ await writeFile(
147
+ join(authDir, 'middleware.ts'),
148
+ authMiddlewareCode.trim() + '\n'
149
+ );
150
+ emitLog('Creating authentication routes...');
151
+ const authRoutesCode = `
152
+ import { Router } from 'express';
153
+ import passport from 'passport';
154
+ import { authenticateLocal } from './middleware';
155
+
156
+ const router = Router();
157
+
158
+ router.post('/login', authenticateLocal, (req, res) => {
159
+ res.json({
160
+ user: req.user,
161
+ token: res.locals.token,
162
+ });
163
+ });
164
+
165
+ router.post('/register', async (req, res) => {
166
+ // Add your registration logic here
167
+ });
168
+
169
+ router.get('/google',
170
+ passport.authenticate('google', { scope: ['profile', 'email'] })
171
+ );
172
+
173
+ router.get('/google/callback',
174
+ passport.authenticate('google', { session: false }),
175
+ (req, res) => {
176
+ // Handle successful authentication
177
+ res.redirect('/');
178
+ }
179
+ );
180
+
181
+ router.post('/logout', (req, res) => {
182
+ req.logout();
183
+ res.json({ message: 'Logged out successfully' });
184
+ });
185
+
186
+ export default router;
187
+ `;
188
+ emitLog('Writing routes.ts...');
189
+ await writeFile(
190
+ join(authDir, 'routes.ts'),
191
+ authRoutesCode.trim() + '\n'
192
+ );
193
+ emitLog('Creating configuration file...');
194
+ const configCode = `
195
+ export const config = {
196
+ jwt: {
197
+ secret: process.env.JWT_SECRET || 'your-secret-key',
198
+ expiresIn: '1d',
199
+ },
200
+ google: {
201
+ clientId: process.env.GOOGLE_CLIENT_ID,
202
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
203
+ },
204
+ session: {
205
+ secret: process.env.SESSION_SECRET || 'session-secret',
206
+ },
207
+ };
208
+ `;
209
+ emitLog('Writing index.ts...');
210
+ await writeFile(
211
+ join(configDir, 'index.ts'),
212
+ configCode.trim() + '\n'
213
+ );
214
+ emitLog('Adding environment variables...');
215
+ const envContent = `
216
+ # Authentication
217
+ JWT_SECRET=your-jwt-secret-key
218
+ SESSION_SECRET=your-session-secret
219
+
220
+ # Google OAuth
221
+ GOOGLE_CLIENT_ID=your-google-client-id
222
+ GOOGLE_CLIENT_SECRET=your-google-client-secret
223
+ `;
224
+ emitLog('Writing .env file...');
225
+ await writeFile(
226
+ join(backendDir, '.env'),
227
+ envContent.trim() + '\n'
228
+ );
229
+ emitLog('✅ Passport.js setup completed successfully!');
230
+ } catch (error) {
231
+ emitLog(`❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
232
+ throw error;
233
+ }
234
+ }
@@ -0,0 +1,30 @@
1
+ import { exec } from 'child_process';
2
+ import { mkdirSync } from 'fs';
3
+ import util from 'util';
4
+
5
+ const execAsync = util.promisify(exec);
6
+
7
+ export async function installDjangoDependencies(projectPath) {
8
+ try {
9
+
10
+ mkdirSync(`${projectPath}/backend`, { recursive: true });
11
+
12
+ await execAsync('python -m venv venv', { cwd: `${projectPath}/backend` });
13
+
14
+ const pythonCmd = process.platform === 'win32' ? 'venv\\Scripts\\python.exe' : 'venv/bin/python';
15
+
16
+ await execAsync(`${pythonCmd} -m pip install django djangorestframework django-cors-headers djangorestframework_simplejwt`, { cwd: `${projectPath}/backend` });
17
+
18
+ await execAsync(`${pythonCmd} -m django startproject core .`, { cwd: `${projectPath}/backend` });
19
+
20
+ await execAsync(`${pythonCmd} manage.py startapp main`, { cwd: `${projectPath}/backend` });
21
+
22
+ console.log("Django project setup completed!");
23
+
24
+ } catch (error) {
25
+ console.error('Error installing Django dependencies:', error);
26
+ throw error;
27
+ }
28
+ }
29
+
30
+ export default installDjangoDependencies;