Skip to content

Commit 0194ccb

Browse files
Merge branch 'varunchanges' into conflictfix
2 parents 32486bb + 1980d48 commit 0194ccb

13 files changed

Lines changed: 528 additions & 137 deletions

File tree

lib/authentication/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ export async function setupClerk(state) {
264264
return;
265265
}
266266
if (framework === 'next') {
267-
await setupNextClerk(framework, projectName, language, styling,useTailwind);
267+
await setupNextClerk(state);
268268
return;
269269
} else if (framework === 'vue') {
270270
// Delegate Vue-specific Clerk setup to helper

lib/authentication/utils/clerknext.js

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import { newStyles, nextMiddleware, nextsignInCss, nextSignInPage, nextsignUpCss, nextSignUpPage } from "./utility.js";
1+
import { newStyles, nextMiddleware, nextsignInCss, nextSignInPage, nextsignUpCss, nextSignUpPage, clerkUserModel, clerkUserController, clerkWebhookRoute } from "./utility.js";
22
import chalk from "chalk";
33
import fs from "fs";
44
import { execa } from "execa";
55
import path from "path";
66

7-
export async function setupNextClerk(framework, projectName, language, styling,useTailwind) {
7+
export async function setupNextClerk(state) {
8+
const { projectName, language, styling, database} = state;
9+
const useTailwind = (styling === "tailwind");
810
try {
911
const targetDir = path.resolve(projectName);
1012
const currentDir = process.cwd();
@@ -61,27 +63,69 @@ export async function setupNextClerk(framework, projectName, language, styling,u
6163
fs.writeFileSync(signupCssPath, signupCssContent);
6264
}
6365

64-
const middlewareContent = nextMiddleware;
66+
let middlewareContent = nextMiddleware;
67+
if (database === 'mongodb') {
68+
middlewareContent = middlewareContent.replace("'/sign-in(.*)','/sign-up(.*)'", "'/sign-in(.*)','/sign-up(.*)', '/api/webhooks(.*)',");
69+
}
6570
const middlewareFilePath = path.join(srcDir, `middleware.${language === 'ts' ? 'ts' : 'js'}`);
6671
fs.writeFileSync(middlewareFilePath, middlewareContent);
6772

73+
if (database === 'mongodb') {
74+
try {
75+
// webhook route
76+
const webhookDir = path.join(srcDir, 'app', 'api', 'webhooks', 'clerk');
77+
fs.mkdirSync(webhookDir, { recursive: true });
78+
const webhookExt = language === 'ts' ? 'ts' : 'js';
79+
const webhookPath = path.join(webhookDir, `route.${webhookExt}`);
80+
const webhookContent = clerkWebhookRoute ? clerkWebhookRoute(language, 'next') : '';
81+
if (webhookContent) fs.writeFileSync(webhookPath, webhookContent, 'utf8');
82+
83+
// user controller (actions)
84+
const actionsDir = path.join(rootDir, 'lib', 'actions');
85+
fs.mkdirSync(actionsDir, { recursive: true });
86+
const controllerExt = language === 'ts' ? 'ts' : 'js';
87+
const controllerPath = path.join(actionsDir, `user.actions.${controllerExt}`);
88+
const controllerContent = clerkUserController ? clerkUserController(language, 'next') : '';
89+
if (controllerContent) fs.writeFileSync(controllerPath, controllerContent, 'utf8');
90+
91+
// user model
92+
const modelsDir = path.join(rootDir, 'lib', 'database', 'models');
93+
fs.mkdirSync(modelsDir, { recursive: true });
94+
const modelExt = language === 'ts' ? 'ts' : 'js';
95+
const modelPath = path.join(modelsDir, `user.model.${modelExt}`);
96+
const modelContent = clerkUserModel ? clerkUserModel(language) : '';
97+
if (modelContent) fs.writeFileSync(modelPath, modelContent, 'utf8');
98+
99+
// Append webhook signing secret to .env.local if missing
100+
const envFile = path.join(rootDir, '.env.local');
101+
let envExisting = '';
102+
if (fs.existsSync(envFile)) envExisting = fs.readFileSync(envFile, 'utf8');
103+
const secretLine = 'CLERK_WEBHOOK_SIGNING_SECRET=your_secret';
104+
if (!envExisting.includes('CLERK_WEBHOOK_SIGNING_SECRET')) {
105+
fs.appendFileSync(envFile, `\n${secretLine}\n`, 'utf8');
106+
console.log(chalk.green('Added CLERK_WEBHOOK_SIGNING_SECRET to .env.local'));
107+
}
108+
} catch (e) {
109+
console.log(chalk.yellow('Could not scaffold Clerk MongoDB helpers automatically:'), e.message);
110+
}
111+
}
112+
68113
const envPath = path.join(rootDir, ".env.local");
69114

70-
// Content you want to ensure exists
71115
const newEnvContent = `
72116
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
73117
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
74118
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/
75119
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/
120+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_publishable_key_here
121+
CLERK_SECRET_KEY=your_secret_key_here
76122
`;
77123

78-
// Read existing content if file exists
79124
let existing = "";
80125
if (fs.existsSync(envPath)) {
81126
existing = fs.readFileSync(envPath, "utf-8");
82127
}
83128

84-
// Filter out only new lines that don't already exist
85129
const linesToAdd = newEnvContent
86130
.trim()
87131
.split("\n")
@@ -91,9 +135,9 @@ NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/
91135
// Append only new lines
92136
if (linesToAdd) {
93137
fs.appendFileSync(envPath, `\n${linesToAdd}\n`, "utf-8");
94-
console.log("Added missing env variables to .env.local successfully!");
138+
console.log("Added missing env variables to .env.local successfully!");
95139
} else {
96-
console.log("ℹ️ All Clerk environment variables already exist in .env.local.");
140+
console.log("All Clerk environment variables already exist in .env.local.");
97141
}
98142
const filePath = path.join(srcDir, `app`, `page.${language === 'ts' ? 'tsx' : 'js'}`);
99143
let content = fs.readFileSync(filePath, "utf8");
@@ -164,9 +208,9 @@ NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/
164208

165209
if (!existingCss.includes(styleClerkUi)) {
166210
fs.appendFileSync(targetPath, `\n${styleClerkUi}\n`, "utf-8");
167-
console.log(`Added user auth button styles to ${path.basename(targetPath)} successfully!`);
211+
console.log(`Added user auth button styles to ${path.basename(targetPath)} successfully!`);
168212
} else {
169-
console.log(`ℹ️ User auth button styles already exist in ${path.basename(targetPath)}, skipped adding again.`);
213+
console.log(`User auth button styles already exist in ${path.basename(targetPath)}, skipped adding again.`);
170214
}
171215
}
172216

@@ -184,7 +228,7 @@ NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/
184228

185229
// Add import if missing
186230
if (!layoutcontent.includes("ClerkProvider")) {
187-
const importLine = `import { ClerkProvider } from "@clerk/nextjs";\nimport { Toaster } from "@/components/ui/toaster";\n`;
231+
const importLine = `import { ClerkProvider } from "@clerk/nextjs";\n`;
188232
// place after the last import
189233
layoutcontent = layoutcontent.replace(/(import .*?;\n)(?!import)/s, match => match + importLine);
190234
layoutchanged = true;
@@ -207,11 +251,20 @@ NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/
207251

208252
console.log(chalk.green.bold(`Clerk setup completed successfully!\nYour app is now configured with Clerk authentication.\nRemember to add your Publishable Key in the .env file:\nVITE_CLERK_PUBLISHABLE_KEY=your_key_here\n\nYou can now start your app and enjoy secure authentication! 🚀`));
209253
console.log(chalk.yellow(
210-
"🛠️ First-time setup:\n" +
254+
"First-time setup:\n" +
211255
"1. Sign in to your Clerk dashboard.\n" +
212256
"2. Create a new application.\n" +
213257
"3. Copy your 'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY' and 'CLERK_SECRET_KEY' into your .env.local file."
214258
));
259+
if(database === 'mongodb') {
260+
console.log(chalk.yellow(
261+
"4. Set up Clerk webhooks for user management:\n" +
262+
" - In the Clerk dashboard, go to Webhooks and create a new webhook with the URL: <HTTPS_URL>/api/webhooks/clerk\n" +
263+
" - Subscribe to events: user.created, user.updated, user.deleted\n" +
264+
" - Copy the webhook signing secret into your .env.local as:\n" +
265+
" CLERK_WEBHOOK_SIGNING_SECRET=your_secret_here"
266+
));
267+
}
215268

216269
} catch (error) {
217270
console.error(chalk.red("Error setting up Clerk for authentication"), error.message);

lib/authentication/utils/clerkvue.js

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import fs from 'fs';
22
import path from 'path';
33
import chalk from 'chalk';
44
import { execa } from 'execa';
5+
import { actions, clerkUserModel, webhooksRoute } from './utility';
56

67
// Component templates
78
const SIGNIN_COMPONENT = `<script setup lang="ts">
@@ -150,8 +151,8 @@ router.beforeEach(async (to) => {
150151
export default router
151152
`;
152153
export async function setupVueClerk(state) {
153-
const daisy=state.uiLibrary==="daisyui";
154-
const { projectName, language,styling,database } = state;
154+
const daisy = state.uiLibrary === "daisyui";
155+
const { projectName, language, database } = state;
155156
console.log(chalk.blue(`Setting up Clerk for Vue project: ${projectName} (lang=${language})`));
156157

157158
const rootDir = path.isAbsolute(projectName)
@@ -373,7 +374,7 @@ function generateParticleStyle(index) {
373374
'🎉 Welcome aboard! HackPack is ready to accelerate your development journey.'
374375
)
375376
"
376-
${ daisy?`class="btn btn-primary"`:`class="bg-yellow-400 hover:bg-yellow-300 text-gray-900 px-6 py-3 rounded-xl font-semibold transition-transform transform hover:scale-105 shadow-lg"`}
377+
${daisy ? `class="btn btn-primary"` : `class="bg-yellow-400 hover:bg-yellow-300 text-gray-900 px-6 py-3 rounded-xl font-semibold transition-transform transform hover:scale-105 shadow-lg"`}
377378
>
378379
Launch a Toast message
379380
</button>
@@ -571,8 +572,108 @@ export default defineConfig({
571572
}
572573
}
573574

574-
console.log(chalk.green.bold('🎉 Vue Clerk setup completed (best-effort). Please verify the main file, App.vue and .env value.'));
575-
console.log(chalk.green('ℹ️ The `ClerkHeader.vue` component created in src/components can be used as a compact auth button/chip anywhere in your app.'));
575+
console.log(chalk.green.bold('Vue Clerk setup completed (best-effort). Please verify the main file, App.vue and .env value.'));
576+
console.log(chalk.green('The `ClerkHeader.vue` component created in src/components can be used as a compact auth button/chip anywhere in your app.'));
577+
// If the user selected MongoDB, scaffold a minimal backend webhook handler
578+
if (database === 'mongodb') {
579+
try {
580+
const backendDir = path.join(rootDir, 'backend');
581+
// backend dir exists
582+
try {
583+
await execa('npm', ['install', '@clerk/express'], { cwd: backendDir, stdio: 'inherit' });
584+
} catch (e) {
585+
console.log(chalk.yellow('Could not install @clerk/express in backend:'), e.message);
586+
}
587+
const backendSrc = path.join(backendDir, 'src');
588+
fs.mkdirSync(backendSrc, { recursive: true });
589+
590+
// actions/user.actions.js/ts
591+
const actionsDir = path.join(backendSrc, 'actions');
592+
fs.mkdirSync(actionsDir, { recursive: true });
593+
const actionsExt = language === 'ts' ? 'ts' : 'js';
594+
const actionsPath = path.join(actionsDir, `user.actions.${actionsExt}`);
595+
if (!fs.existsSync(actionsPath)) fs.writeFileSync(actionsPath, actions(language), 'utf8');
596+
597+
// models/user.model.js
598+
const modelsDir = path.join(backendSrc, 'models');
599+
fs.mkdirSync(modelsDir, { recursive: true });
600+
const modelExt = language === 'ts' ? 'ts' : 'js';
601+
const modelPath = path.join(modelsDir, `user.model.${modelExt}`);
602+
if (!fs.existsSync(modelPath)) fs.writeFileSync(modelPath, clerkUserModel(language), 'utf8');
603+
604+
// routes/webhooks.route.js
605+
const routesDir = path.join(backendSrc, 'routes');
606+
fs.mkdirSync(routesDir, { recursive: true });
607+
const routeExt = language === 'ts' ? 'ts' : 'js';
608+
const routePath = path.join(routesDir, `webhooks.route.${routeExt}`);
609+
if (!fs.existsSync(routePath)) fs.writeFileSync(routePath, webhooksRoute(language), 'utf8');
610+
611+
// backend/src/index.js - create or patch
612+
const indexPath = path.join(backendSrc, `index.${language === 'ts' ? 'ts' : 'js'}`);
613+
if (fs.existsSync(indexPath)) {
614+
let indexContent = fs.readFileSync(indexPath, "utf8");
615+
const importRegex = /(import connectDB[^\n]*\n)/;
616+
617+
if (!/import\s+webhooksRoute/.test(indexContent)) {
618+
indexContent = indexContent.replace(
619+
importRegex,
620+
`$1import webhooksRoute from "./routes/webhooks.route.js";\n`
621+
);
622+
}
623+
// for js
624+
let expressRegex;
625+
if(language === 'ts'){
626+
expressRegex = /const app: express.Application = express()\(\);/;
627+
}
628+
else{
629+
expressRegex = /const app = express\(\);/;
630+
}
631+
632+
if (!/app\.use\(\s*['"]\/api\/webhooks/.test(indexContent)) {
633+
indexContent = indexContent.replace(
634+
expressRegex,
635+
`const app = express();\napp.use('/api/webhooks', webhooksRoute);`
636+
);
637+
}
638+
639+
fs.writeFileSync(indexPath, indexContent, "utf8");
640+
console.log("index.js updated successfully ✔");
641+
} else {
642+
const indexLines = [
643+
"import express from 'express';",
644+
"import dotenv from 'dotenv';",
645+
"import webhooksRoute from './routes/webhooks.route.js';",
646+
"",
647+
"dotenv.config();",
648+
"const app = express();",
649+
"app.use('/api/webhooks', webhooksRoute);",
650+
"app.use(express.json());",
651+
"",
652+
"const PORT = process.env.PORT || 5000;",
653+
"app.listen(PORT, () => console.log('Server listening on port ' + (process.env.PORT || 5000)));",
654+
""
655+
];
656+
fs.writeFileSync(indexPath, indexLines.join('\n'), 'utf8');
657+
}
658+
659+
// Append CLERK_WEBHOOK_SIGNING_SECRET and CLIENT_URL to backend/.env if missing
660+
const backendEnv = path.join(backendDir, '.env');
661+
let envExisting = '';
662+
if (fs.existsSync(backendEnv)) envExisting = fs.readFileSync(backendEnv, 'utf8');
663+
const secretLine = 'CLERK_WEBHOOK_SIGNING_SECRET=your_secret';
664+
const clientLine = 'CLIENT_URL=http://localhost:5173';
665+
if (!envExisting.includes('CLERK_WEBHOOK_SIGNING_SECRET')) {
666+
fs.appendFileSync(backendEnv, '\n' + secretLine + '\n', 'utf8');
667+
console.log(chalk.green('Added CLERK_WEBHOOK_SIGNING_SECRET to backend/.env'));
668+
}
669+
if (!envExisting.includes('CLIENT_URL')) {
670+
fs.appendFileSync(backendEnv, clientLine + '\n', 'utf8');
671+
console.log(chalk.green('Added CLIENT_URL to backend/.env'));
672+
}
673+
} catch (e) {
674+
console.log(chalk.yellow('Could not scaffold Clerk backend helpers automatically:'), e.message);
675+
}
676+
}
576677
} catch (err) {
577678
console.error(chalk.red('Error setting up Clerk for Vue:'), err && err.message ? err.message : err);
578679
}

0 commit comments

Comments
 (0)