@shakil-dev/shakil-stack 2.2.8 → 2.2.9

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 (2) hide show
  1. package/dist/index.js +96 -58
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{Command as Ve}from"commander";import qe from"fs-extra";import ne from"path";import{fileURLToPath as We}from"url";import s from"fs-extra";import o from"path";import we from"crypto";import a from"chalk";import De from"ora";import ve from"inquirer";import{execSync as Ne}from"child_process";import Xe from"fs-extra";var l=(e,r=process.cwd())=>{try{return Ne(e,{stdio:"inherit",cwd:r}),!0}catch{return!1}},E=()=>{let e=process.env.npm_config_user_agent||"";return e.includes("pnpm")?"pnpm":e.includes("yarn")?"yarn":"npm"};var ae=e=>`import { Server } from 'http';
2
+ import{Command as Ke}from"commander";import De from"fs-extra";import ne from"path";import{fileURLToPath as Ye}from"url";import s from"fs-extra";import o from"path";import je from"crypto";import a from"chalk";import Be from"ora";import Ce from"inquirer";import{execSync as He}from"child_process";import st from"fs-extra";var d=(e,r=process.cwd())=>{try{return He(e,{stdio:"inherit",cwd:r}),!0}catch{return!1}},E=()=>{let e=process.env.npm_config_user_agent||"";return e.includes("pnpm")?"pnpm":e.includes("yarn")?"yarn":"pnpm"};var ae=e=>`import { Server } from 'http';
3
3
  import app from './app.js';
4
4
  import config from './app/config/index.js';
5
5
 
@@ -178,7 +178,7 @@ const notFound = (req: Request, res: Response, next: NextFunction) => {
178
178
  };
179
179
 
180
180
  export default notFound;
181
- `,ue=`import { NextFunction, Request, RequestHandler, Response } from 'express';
181
+ `,de=`import { NextFunction, Request, RequestHandler, Response } from 'express';
182
182
 
183
183
  const catchAsync = (fn: RequestHandler) => {
184
184
  return async (req: Request, res: Response, next: NextFunction) => {
@@ -191,7 +191,7 @@ const catchAsync = (fn: RequestHandler) => {
191
191
  };
192
192
 
193
193
  export default catchAsync;
194
- `,de=`class ApiError extends Error {
194
+ `,ue=`class ApiError extends Error {
195
195
  statusCode: number;
196
196
  constructor(statusCode: number, message: string | undefined, stack = '') {
197
197
  super(message);
@@ -216,7 +216,7 @@ export const sanitize = (data: any): any => {
216
216
  }
217
217
  return data;
218
218
  };
219
- `,ge=`import { Request, Response, NextFunction } from 'express';
219
+ `,fe=`import { Request, Response, NextFunction } from 'express';
220
220
  import { sanitize } from '../utils/sanitizer.js';
221
221
 
222
222
  export const sanitizeRequest = (req: Request, res: Response, next: NextFunction) => {
@@ -225,7 +225,7 @@ export const sanitizeRequest = (req: Request, res: Response, next: NextFunction)
225
225
  if (req.params) sanitize(req.params);
226
226
  next();
227
227
  };
228
- `,fe=`import { Response } from 'express';
228
+ `,ge=`import { Response } from 'express';
229
229
 
230
230
  type IResponse<T> = {
231
231
  statusCode: number;
@@ -257,10 +257,12 @@ export default sendResponse;
257
257
  datasource db {
258
258
  provider = "postgresql"
259
259
  }
260
- `,O=`model User {
261
- id String @id @default(uuid())
260
+ `,N=`model User {
261
+ id String @id @default(cuid())
262
262
  email String @unique
263
263
  name String
264
+ emailVerified Boolean @default(false)
265
+ image String?
264
266
  createdAt DateTime @default(now())
265
267
  updatedAt DateTime @updatedAt
266
268
  accounts Account[]
@@ -268,17 +270,19 @@ datasource db {
268
270
  }
269
271
 
270
272
  model Session {
271
- id String @id @default(uuid())
273
+ id String @id @default(cuid())
272
274
  userId String
273
275
  token String @unique
274
276
  expiresAt DateTime
277
+ ipAddress String?
278
+ userAgent String?
275
279
  createdAt DateTime @default(now())
276
280
  updatedAt DateTime @updatedAt
277
281
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
278
282
  }
279
283
 
280
284
  model Account {
281
- id String @id @default(uuid())
285
+ id String @id @default(cuid())
282
286
  userId String
283
287
  accountId String
284
288
  providerId String
@@ -293,7 +297,16 @@ model Account {
293
297
  updatedAt DateTime @updatedAt
294
298
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
295
299
  }
296
- `,_=`import dotenv from "dotenv";
300
+
301
+ model Verification {
302
+ id String @id @default(cuid())
303
+ identifier String
304
+ value String
305
+ expiresAt DateTime
306
+ createdAt DateTime @default(now())
307
+ updatedAt DateTime @updatedAt
308
+ }
309
+ `,O=`import dotenv from "dotenv";
297
310
  import path from "path";
298
311
  import process from "process";
299
312
  import { defineConfig } from "prisma/config";
@@ -306,7 +319,7 @@ export default defineConfig({
306
319
  url: process.env.DATABASE_URL,
307
320
  },
308
321
  });
309
- `,q=`import jwt, { JwtPayload, SignOptions } from 'jsonwebtoken';
322
+ `,_=`import jwt, { JwtPayload, SignOptions } from 'jsonwebtoken';
310
323
 
311
324
  const createToken = (payload: Record<string, unknown>, secret: string, options: SignOptions) => {
312
325
  return jwt.sign(payload, secret, options);
@@ -322,7 +335,7 @@ const verifyToken = (token: string, secret: string) => {
322
335
  };
323
336
 
324
337
  export const jwtUtils = { createToken, verifyToken };
325
- `,N=`import { CookieOptions, Request, Response } from "express";
338
+ `,q=`import { CookieOptions, Request, Response } from "express";
326
339
 
327
340
  const setCookie = (res: Response, key: string, value: string, options: CookieOptions) => {
328
341
  res.cookie(key, value, options);
@@ -418,12 +431,7 @@ import type { AnyZodObject } from 'zod';
418
431
  const validateRequest = (schema: AnyZodObject) => {
419
432
  return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
420
433
  try {
421
- await schema.parseAsync({
422
- body: req.body,
423
- query: req.query,
424
- params: req.params,
425
- cookies: req.cookies,
426
- });
434
+ await schema.parseAsync(req.body);
427
435
  return next();
428
436
  } catch (error) {
429
437
  next(error);
@@ -453,7 +461,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
453
461
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
454
462
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
455
463
  SOFTWARE.
456
- `,z=`# Contributor Covenant Code of Conduct
464
+ `,$=`# Contributor Covenant Code of Conduct
457
465
 
458
466
  ## Our Pledge
459
467
 
@@ -527,7 +535,7 @@ version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
527
535
 
528
536
  [homepage]: http://contributor-covenant.org
529
537
  [version]: http://contributor-covenant.org/version/1/4
530
- `,$=`node_modules/
538
+ `,z=`node_modules/
531
539
  .env
532
540
  dist/
533
541
  *.log
@@ -747,25 +755,21 @@ export type ILoginUserPayload = z.infer<typeof AuthValidation.loginValidationSch
747
755
  `,J=`import { z } from "zod";
748
756
 
749
757
  const registerValidationSchema = z.object({
750
- body: z.object({
751
- name: z.string().min(1, "Name is required"),
752
- email: z.string().email("Invalid email address"),
753
- password: z.string().min(6, "Password must be at least 6 characters"),
754
- }),
758
+ name: z.string().min(1, "Name is required"),
759
+ email: z.string().email("Invalid email address"),
760
+ password: z.string().min(6, "Password must be at least 6 characters"),
755
761
  });
756
762
 
757
763
  const loginValidationSchema = z.object({
758
- body: z.object({
759
- email: z.string().email("Invalid email address"),
760
- password: z.string().min(1, "Password is required"),
761
- }),
764
+ email: z.string().email("Invalid email address"),
765
+ password: z.string().min(1, "Password is required"),
762
766
  });
763
767
 
764
768
  export const AuthValidation = {
765
769
  registerValidationSchema,
766
770
  loginValidationSchema,
767
771
  };
768
- `;var K=`import axios from "axios";
772
+ `;var Q=`import axios from "axios";
769
773
 
770
774
  export const httpClient = axios.create({
771
775
  baseURL: process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000/api/v1",
@@ -781,7 +785,7 @@ httpClient.interceptors.response.use(
781
785
  return Promise.reject(error);
782
786
  }
783
787
  );
784
- `,Q=`"use server";
788
+ `,K=`"use server";
785
789
  import { cookies } from "next/headers";
786
790
 
787
791
  export async function setTokenInCookies(name: string, token: string, maxAge?: number) {
@@ -900,7 +904,7 @@ export function LoginForm() {
900
904
  setLoading(true);
901
905
  setError(null);
902
906
  try {
903
- const response = await loginAction({ body: data });
907
+ const response = await loginAction(data);
904
908
  if (response.success) {
905
909
  queryClient.invalidateQueries({ queryKey: ["user"] });
906
910
  router.push("/dashboard");
@@ -980,7 +984,7 @@ export function RegisterForm() {
980
984
  setLoading(true);
981
985
  setError(null);
982
986
  try {
983
- const response = await registerAction({ body: data });
987
+ const response = await registerAction(data);
984
988
  if (response.success) {
985
989
  queryClient.invalidateQueries({ queryKey: ["user"] });
986
990
  router.push("/dashboard");
@@ -1040,28 +1044,62 @@ export default function ${e==="login"?"LoginPage":"RegisterPage"}() {
1040
1044
  </div>
1041
1045
  );
1042
1046
  }
1043
- `;var se=async e=>{let r=e;r||(r=(await ve.prompt([{type:"input",name:"projectName",message:"What is your project name?",default:"shakil-stack-app"}])).projectName),r||(console.log(a.red("\u274C Error: Project name is required.")),process.exit(1));let{packageManager:d,useShadcn:x,installDeps:m,setupPrisma:u,setupBetterAuth:g,setupApi:T,setupLogin:h,setupGit:oe}=await ve.prompt([{type:"list",name:"packageManager",message:"Which package manager do you want to use?",choices:["pnpm","npm","yarn"],default:E()},{type:"confirm",name:"useShadcn",message:"Would you like to use shadcn/ui?",default:!0},{type:"confirm",name:"setupPrisma",message:"Would you like to setup Prisma?",default:!0},{type:"confirm",name:"setupBetterAuth",message:"Would you like to setup Better-Auth?",default:!0},{type:"confirm",name:"setupApi",message:"Would you like to setup API modules (AuthController, etc.)?",default:!0},{type:"confirm",name:"setupLogin",message:"Would you like to setup Frontend Login/Register pages?",default:!0},{type:"confirm",name:"installDeps",message:"Do you want to install dependencies automatically?",default:!0},{type:"confirm",name:"setupGit",message:"Would you like to setup Git with automatic version control?",default:!0}]),k=r==="."||r==="./",t=k?process.cwd():o.join(process.cwd(),r),p=k?o.basename(process.cwd()):r;!k&&s.existsSync(t)&&(console.log(a.red(`\u274C Error: Directory ${r} already exists.`)),process.exit(1)),console.log(a.cyan(`
1047
+ `,be=`
1048
+ "use client";
1049
+
1050
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
1051
+ import { ReactNode, useState } from "react";
1052
+
1053
+ export function Providers({ children }: { children: ReactNode }) {
1054
+ const [queryClient] = useState(() => new QueryClient());
1055
+
1056
+ return (
1057
+ <QueryClientProvider client={queryClient}>
1058
+ {children}
1059
+ </QueryClientProvider>
1060
+ );
1061
+ }
1062
+ `,we=`
1063
+ import { Providers } from "@/components/Providers";
1064
+ import "./globals.css";
1065
+
1066
+ export default function RootLayout({
1067
+ children,
1068
+ }: {
1069
+ children: React.ReactNode;
1070
+ }) {
1071
+ return (
1072
+ <html lang="en">
1073
+ <body>
1074
+ <Providers>{children}</Providers>
1075
+ </body>
1076
+ </html>
1077
+ );
1078
+ }
1079
+ `;var se=async e=>{let r=e;r||(r=(await Ce.prompt([{type:"input",name:"projectName",message:"What is your project name?",default:"shakil-stack-app"}])).projectName),r||(console.log(a.red("\u274C Error: Project name is required.")),process.exit(1));let{packageManager:l,useShadcn:x,installDeps:m,setupPrisma:u,setupBetterAuth:f,setupApi:T,setupLogin:h,setupGit:oe}=await Ce.prompt([{type:"list",name:"packageManager",message:"Which package manager do you want to use?",choices:["pnpm","npm","yarn"],default:E()},{type:"confirm",name:"useShadcn",message:"Would you like to use shadcn/ui?",default:!0},{type:"confirm",name:"setupPrisma",message:"Would you like to setup Prisma?",default:!0},{type:"confirm",name:"setupBetterAuth",message:"Would you like to setup Better-Auth?",default:!0},{type:"confirm",name:"setupApi",message:"Would you like to setup API modules (AuthController, etc.)?",default:!0},{type:"confirm",name:"setupLogin",message:"Would you like to setup Frontend Login/Register pages?",default:!0},{type:"confirm",name:"installDeps",message:"Do you want to install dependencies automatically?",default:!0},{type:"confirm",name:"setupGit",message:"Would you like to setup Git with automatic version control?",default:!0}]),k=r==="."||r==="./",t=k?process.cwd():o.join(process.cwd(),r),p=k?o.basename(process.cwd()):r;!k&&s.existsSync(t)&&(console.log(a.red(`\u274C Error: Directory ${r} already exists.`)),process.exit(1)),console.log(a.cyan(`
1044
1080
  \u{1F680} Initializing ${a.bold(p)} in ${k?"current directory":r}...
1045
- `));let S=De("\u{1F6E0}\uFE0F Creating project structure...").start();try{await s.ensureDir(t),await s.ensureDir(o.join(t,"backend","src","app","config")),await s.ensureDir(o.join(t,"backend","src","app","lib")),await s.ensureDir(o.join(t,"backend","src","app","module")),await s.ensureDir(o.join(t,"backend","src","app","routes")),await s.ensureDir(o.join(t,"backend","src","app","middleware")),await s.ensureDir(o.join(t,"backend","src","app","utils")),await s.ensureDir(o.join(t,"backend","src","app","errorHelpers")),u&&await s.ensureDir(o.join(t,"backend","prisma","schema")),T&&await s.ensureDir(o.join(t,"backend","src","app","module","auth")),console.log(a.cyan(`
1046
- \u{1F5BC}\uFE0F Scaffolding Next.js frontend...`)),l(`npx create-next-app@latest frontend --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-${d}`,t);let b=["config","hooks","lib","services","types"];T&&b.push("lib/axios"),h&&b.push("components/auth","app/(auth)/login","app/(auth)/register");for(let y of b)await s.ensureDir(o.join(t,"frontend","src",y));if(x){console.log(a.cyan(`
1047
- \u{1F3A8} Setting up shadcn/ui...`));try{l("npx shadcn@latest init -d",o.join(t,"frontend")),console.log(a.cyan("\u{1F4E6} Adding common shadcn/ui components...")),l(`npx shadcn@latest add ${["button","card","input","label","textarea","dialog","dropdown-menu","table","tabs","checkbox"].join(" ")} -y`,o.join(t,"frontend")),console.log(a.green("\u2705 shadcn/ui and common components initialized successfully!\u2728"))}catch{console.log(a.yellow(`
1048
- \u26A0\uFE0F Warning: Failed to automate shadcn/ui init. You can run "npx shadcn@latest init" in the frontend folder.`))}}await s.outputFile(o.join(t,"backend","src","server.ts"),ae(p)),await s.outputFile(o.join(t,"backend","src","app.ts"),ie(p)),await s.outputFile(o.join(t,"backend","src","app","config","index.ts"),F),u&&await s.outputFile(o.join(t,"backend","src","app","lib","prisma.ts"),P),g&&await s.outputFile(o.join(t,"backend","src","app","lib","auth.ts"),I),await s.outputFile(o.join(t,"backend","src","app","routes","index.ts"),ce),await s.outputFile(o.join(t,"backend","src","app","middleware","globalErrorHandler.ts"),pe),await s.outputFile(o.join(t,"backend","src","app","middleware","notFound.ts"),le),await s.outputFile(o.join(t,"backend","src","app","middleware","sanitizeRequest.ts"),ge),await s.outputFile(o.join(t,"backend","src","app","middleware","validateRequest.ts"),ke),await s.outputFile(o.join(t,"backend","src","app","utils","catchAsync.ts"),ue),await s.outputFile(o.join(t,"backend","src","app","utils","sendResponse.ts"),fe),await s.outputFile(o.join(t,"backend","src","app","utils","sanitizer.ts"),me),await s.outputFile(o.join(t,"backend","src","app","errorHelpers","ApiError.ts"),de),u&&(await s.outputFile(o.join(t,"backend","prisma","schema","schema.prisma"),U),g&&await s.outputFile(o.join(t,"backend","prisma","schema","auth.prisma"),O),await s.outputFile(o.join(t,"backend","prisma.config.ts"),_)),T&&(await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.controller.ts"),M),await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.service.ts"),V),await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.route.ts"),W),await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.interface.ts"),G),await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.validation.ts"),J),await s.outputFile(o.join(t,"backend","src","app","utils","jwt.ts"),q),await s.outputFile(o.join(t,"backend","src","app","utils","cookie.ts"),N),await s.outputFile(o.join(t,"backend","src","app","utils","token.ts"),D)),T&&(await s.outputFile(o.join(t,"frontend","src","lib","axios","httpClient.ts"),K),await s.outputFile(o.join(t,"frontend","src","lib","tokenUtils.ts"),Q),await s.outputFile(o.join(t,"frontend","src","lib","cookieUtils.ts"),Y),await s.outputFile(o.join(t,"frontend","src","services","auth.actions.ts"),X)),h&&(await s.outputFile(o.join(t,"frontend","src","components","auth","login-form.tsx"),Z),await s.outputFile(o.join(t,"frontend","src","components","auth","register-form.tsx"),ee),await s.outputFile(o.join(t,"frontend","src","app","(auth)","login","page.tsx"),C("login")),await s.outputFile(o.join(t,"frontend","src","app","(auth)","register","page.tsx"),C("register"))),await s.outputFile(o.join(t,"backend","tsconfig.json"),he),await s.outputFile(o.join(t,".gitignore"),$),await s.outputFile(o.join(t,"LICENSE"),L),await s.outputFile(o.join(t,"README.md"),H(p)),await s.outputFile(o.join(t,"CODE_OF_CONDUCT.md"),z);let A=we.randomBytes(32).toString("hex"),i=we.randomBytes(32).toString("hex");await s.outputFile(o.join(t,".env"),`DATABASE_URL="postgresql://postgres:postgres@localhost:5432/${p}"
1081
+ `));let S=Be("\u{1F6E0}\uFE0F Creating project structure...").start();try{await s.ensureDir(t),await s.ensureDir(o.join(t,"backend","src","app","config")),await s.ensureDir(o.join(t,"backend","src","app","lib")),await s.ensureDir(o.join(t,"backend","src","app","module")),await s.ensureDir(o.join(t,"backend","src","app","routes")),await s.ensureDir(o.join(t,"backend","src","app","middleware")),await s.ensureDir(o.join(t,"backend","src","app","utils")),await s.ensureDir(o.join(t,"backend","src","app","errorHelpers")),u&&await s.ensureDir(o.join(t,"backend","prisma","schema")),T&&await s.ensureDir(o.join(t,"backend","src","app","module","auth")),console.log(a.cyan(`
1082
+ \u{1F5BC}\uFE0F Scaffolding Next.js frontend...`)),d(`npx create-next-app@latest frontend --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-${l}`,t);let b=["config","hooks","lib","services","types"];T&&b.push("lib/axios"),h&&b.push("components/auth","app/(auth)/login","app/(auth)/register");for(let y of b)await s.ensureDir(o.join(t,"frontend","src",y));if(x){console.log(a.cyan(`
1083
+ \u{1F3A8} Setting up shadcn/ui...`));try{d("npx shadcn@latest init -d",o.join(t,"frontend")),console.log(a.cyan("\u{1F4E6} Adding common shadcn/ui components...")),d(`npx shadcn@latest add ${["button","card","input","label","textarea","dialog","dropdown-menu","table","tabs","checkbox"].join(" ")} -y`,o.join(t,"frontend")),console.log(a.green("\u2705 shadcn/ui and common components initialized successfully!\u2728"))}catch{console.log(a.yellow(`
1084
+ \u26A0\uFE0F Warning: Failed to automate shadcn/ui init. You can run "npx shadcn@latest init" in the frontend folder.`))}}await s.outputFile(o.join(t,"backend","src","server.ts"),ae(p)),await s.outputFile(o.join(t,"backend","src","app.ts"),ie(p)),await s.outputFile(o.join(t,"backend","src","app","config","index.ts"),F),u&&await s.outputFile(o.join(t,"backend","src","app","lib","prisma.ts"),P),f&&await s.outputFile(o.join(t,"backend","src","app","lib","auth.ts"),I),await s.outputFile(o.join(t,"backend","src","app","routes","index.ts"),ce),await s.outputFile(o.join(t,"backend","src","app","middleware","globalErrorHandler.ts"),pe),await s.outputFile(o.join(t,"backend","src","app","middleware","notFound.ts"),le),await s.outputFile(o.join(t,"backend","src","app","middleware","sanitizeRequest.ts"),fe),await s.outputFile(o.join(t,"backend","src","app","middleware","validateRequest.ts"),ke),await s.outputFile(o.join(t,"backend","src","app","utils","catchAsync.ts"),de),await s.outputFile(o.join(t,"backend","src","app","utils","sendResponse.ts"),ge),await s.outputFile(o.join(t,"backend","src","app","utils","sanitizer.ts"),me),await s.outputFile(o.join(t,"backend","src","app","errorHelpers","ApiError.ts"),ue),u&&(await s.outputFile(o.join(t,"backend","prisma","schema","schema.prisma"),U),f&&await s.outputFile(o.join(t,"backend","prisma","schema","auth.prisma"),N),await s.outputFile(o.join(t,"backend","prisma.config.ts"),O)),T&&(await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.controller.ts"),M),await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.service.ts"),V),await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.route.ts"),W),await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.interface.ts"),G),await s.outputFile(o.join(t,"backend","src","app","module","auth","auth.validation.ts"),J),await s.outputFile(o.join(t,"backend","src","app","utils","jwt.ts"),_),await s.outputFile(o.join(t,"backend","src","app","utils","cookie.ts"),q),await s.outputFile(o.join(t,"backend","src","app","utils","token.ts"),D)),T&&(await s.outputFile(o.join(t,"frontend","src","lib","axios","httpClient.ts"),Q),await s.outputFile(o.join(t,"frontend","src","lib","tokenUtils.ts"),K),await s.outputFile(o.join(t,"frontend","src","lib","cookieUtils.ts"),Y),await s.outputFile(o.join(t,"frontend","src","services","auth.actions.ts"),X)),h&&(await s.outputFile(o.join(t,"frontend","src","components","auth","login-form.tsx"),Z),await s.outputFile(o.join(t,"frontend","src","components","auth","register-form.tsx"),ee),await s.outputFile(o.join(t,"frontend","src","app","(auth)","login","page.tsx"),C("login")),await s.outputFile(o.join(t,"frontend","src","app","(auth)","register","page.tsx"),C("register")),await s.outputFile(o.join(t,"frontend","src","components","Providers.tsx"),be),await s.outputFile(o.join(t,"frontend","src","app","layout.tsx"),we)),await s.outputFile(o.join(t,"backend","tsconfig.json"),he),await s.outputFile(o.join(t,".gitignore"),z),await s.outputFile(o.join(t,"LICENSE"),L),await s.outputFile(o.join(t,"README.md"),H(p)),await s.outputFile(o.join(t,"CODE_OF_CONDUCT.md"),$);let A=je.randomBytes(32).toString("hex"),i=je.randomBytes(32).toString("hex"),w=`DATABASE_URL="postgresql://postgres:postgres@localhost:5432/${p}"
1049
1085
  JWT_SECRET="${A}"
1050
1086
  BETTER_AUTH_SECRET="${i}"
1051
1087
  NODE_ENV="development"
1052
1088
  PORT=8000
1053
1089
  BETTER_AUTH_BASE_URL="http://localhost:8000"
1054
- CLIENT_URL="http://localhost:3000"
1055
- NEXT_PUBLIC_API_URL="http://localhost:8000/api/v1"`),await s.outputFile(o.join(t,"package.json"),B(p));let w={name:`${p}-backend`,version:"1.0.0",type:"module",scripts:{test:'echo "Error: no test specified" && exit 1',dev:"nodemon --exec tsx src/server.ts",build:"prisma generate && tsup src/server.ts --format esm --platform node --target node20 --outDir dist --external pg-native",postinstall:"prisma generate",start:"node dist/server.js","prisma:generate":"prisma generate","prisma:migrate":"prisma migrate dev","prisma:studio":"prisma studio",seed:"tsx prisma/seed.ts",setup:"pnpm install && pnpm add @prisma/adapter-pg pg && pnpm add -D @types/pg && pnpm prisma:generate",predev:"pnpm run prisma:generate",init:"pnpm run prisma:generate && pnpm run prisma:migrate --name init",lint:"eslint src/**/*.ts","lint:fix":"eslint src/**/*.ts --fix",format:"prettier --write .",push:"prisma db push",pull:"prisma db pull"},dependencies:{...u?{"@prisma/adapter-pg":"^7.5.0","@prisma/client":"^7.5.0",pg:"^8.20.0"}:{},...g?{"better-auth":"^1.5.6"}:{},"cookie-parser":"^1.4.7",cors:"^2.8.6",dompurify:"^3.3.3",dotenv:"^17.3.1",express:"^5.2.1","express-rate-limit":"^8.3.1",helmet:"^8.1.0","http-status":"^2.1.0",jsdom:"^29.0.1",jsonwebtoken:"^9.0.3",morgan:"^1.10.1",winston:"^3.19.0",zod:"^4.3.6"},devDependencies:{"@types/cookie-parser":"^1.4.10","@types/cors":"^2.8.19","@types/express":"^5.0.6","@types/node":"^20.19.37",...u?{"@types/pg":"^8.20.0",prisma:"^7.5.0"}:{},"@types/morgan":"^1.9.10","@types/jsdom":"^21.1.7",tsx:"^4.21.0",nodemon:"^3.1.14",tsup:"^8.5.1",typescript:"^5.9.3",eslint:"^9.21.0",prettier:"^3.5.2"}};if(await s.writeJson(o.join(t,"backend","package.json"),w,{spaces:2}),S.succeed(a.green("\u2705 Project structure created! \u2728")),m&&(console.log(a.yellow(`
1056
- \u{1F4E6} Finalizing dependencies with ${d}...
1057
- `)),l(`${d} install`,t),l(`${d} install`,o.join(t,"backend")),T||h)){console.log(a.yellow(`
1090
+ CLIENT_URL="http://localhost:3000"`,Le="NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1";await s.outputFile(o.join(t,".env"),w),await s.outputFile(o.join(t,"frontend",".env.local"),Le),await s.outputFile(o.join(t,"package.json"),B(p)),l==="pnpm"&&await s.outputFile(o.join(t,"pnpm-workspace.yaml"),`packages:
1091
+ - 'backend'
1092
+ - 'frontend'
1093
+ `);let $e={name:`${p}-backend`,version:"1.0.0",type:"module",scripts:{test:'echo "Error: no test specified" && exit 1',dev:"nodemon --exec tsx src/server.ts",build:"prisma generate && tsup src/server.ts --format esm --platform node --target node20 --outDir dist --external pg-native",postinstall:"prisma generate",start:"node dist/server.js","prisma:generate":"prisma generate","prisma:migrate":"prisma migrate dev","prisma:studio":"prisma studio",seed:"tsx prisma/seed.ts",setup:"pnpm install && pnpm add @prisma/adapter-pg pg && pnpm add -D @types/pg && pnpm prisma:generate",predev:"pnpm run prisma:generate",init:"pnpm run prisma:generate && pnpm run prisma:migrate --name init",lint:"eslint src/**/*.ts","lint:fix":"eslint src/**/*.ts --fix",format:"prettier --write .",push:"prisma db push",pull:"prisma db pull"},dependencies:{...u?{"@prisma/adapter-pg":"^7.5.0","@prisma/client":"^7.5.0",pg:"^8.20.0"}:{},...f?{"better-auth":"^1.5.6"}:{},"cookie-parser":"^1.4.7",cors:"^2.8.6",dompurify:"^3.3.3",dotenv:"^17.3.1",express:"^5.2.1","express-rate-limit":"^8.3.1",helmet:"^8.1.0","http-status":"^2.1.0",jsdom:"^29.0.1",jsonwebtoken:"^9.0.3",morgan:"^1.10.1",winston:"^3.19.0",zod:"^4.3.6"},devDependencies:{"@types/cookie-parser":"^1.4.10","@types/cors":"^2.8.19","@types/express":"^5.0.6","@types/node":"^20.19.37",...u?{"@types/pg":"^8.20.0",prisma:"^7.5.0"}:{},"@types/morgan":"^1.9.10","@types/jsdom":"^21.1.7",tsx:"^4.21.0",nodemon:"^3.1.14",tsup:"^8.5.1",typescript:"^5.9.3",eslint:"^9.21.0",prettier:"^3.5.2"}};if(await s.writeJson(o.join(t,"backend","package.json"),$e,{spaces:2}),S.succeed(a.green("\u2705 Project structure created! \u2728")),m&&(console.log(a.yellow(`
1094
+ \u{1F4E6} Finalizing dependencies with ${l}...
1095
+ `)),d(`${l} install`,t),d(`${l} install`,o.join(t,"backend")),T||h)){console.log(a.yellow(`
1058
1096
  \u{1F4E6} Adding frontend auth dependencies...
1059
- `));let y=["axios"];h&&y.push("react-hook-form","zod","@hookform/resolvers/zod","@tanstack/react-query"),l(`${d} add ${y.join(" ")}`,o.join(t,"frontend"))}if(oe){console.log(a.cyan(`
1060
- Git Initializing...`));try{let y=o.join(t,"frontend",".git");s.existsSync(y)&&await s.remove(y),l("git init",t),l("git add .",t),l('git commit -m "Initial commit from shakil-stack"',t),console.log(a.green(" Git initialized successfully!"))}catch{console.log(a.yellow("\u26A0\uFE0F Warning: Failed to initialize Git."))}}console.log(a.cyan(`
1097
+ `));let y=["axios"];h&&y.push("react-hook-form","zod","@hookform/resolvers","@tanstack/react-query");let ze=l==="pnpm"?`${l} add ${y.join(" ")} --filter ./frontend`:`${l} add ${y.join(" ")}`;d(ze,t)}if(oe){console.log(a.cyan(`
1098
+ Git Initializing...`));try{let y=o.join(t,"frontend",".git");s.existsSync(y)&&await s.remove(y),d("git init",t),d("git add .",t),d('git commit -m "Initial commit from shakil-stack"',t),console.log(a.green(" Git initialized successfully!"))}catch{console.log(a.yellow("\u26A0\uFE0F Warning: Failed to initialize Git."))}}console.log(a.cyan(`
1061
1099
  \u{1F525} Your project is ready! Follow these steps to start:
1062
1100
  `)),r!=="./"&&r!=="."&&console.log(a.white(` 1. ${a.bold(`cd ${r}`)}`)),console.log(a.white(` 2. Ensure your ${a.bold("PostgreSQL")} database is running.`)),console.log(a.white(` 3. Update ${a.bold(".env")} credentials if needed.`)),console.log(a.white(` 4. ${a.bold("pnpm dev:backend")} (Starts server & Prisma Studio)`)),console.log(a.white(` 5. ${a.bold("pnpm dev:frontend")} (Starts Next.js application)`)),console.log(a.green(`
1063
1101
  Happy coding! \u{1F680}
1064
- `))}catch(b){S.fail(a.red("\u274C Failed to initialize project.")),console.error(b),process.exit(1)}};import R from"fs-extra";import te from"path";import v from"chalk";import ze from"ora";var je=(e,r)=>`import { Request, Response } from 'express';
1102
+ `))}catch(b){S.fail(a.red("\u274C Failed to initialize project.")),console.error(b),process.exit(1)}};import R from"fs-extra";import te from"path";import v from"chalk";import Ve from"ora";var Re=(e,r)=>`import { Request, Response } from 'express';
1065
1103
  import httpStatus from 'http-status';
1066
1104
  import catchAsync from '../../utils/catchAsync.js';
1067
1105
  import sendResponse from '../../utils/sendResponse.js';
@@ -1080,7 +1118,7 @@ const create${e} = catchAsync(async (req: Request, res: Response) => {
1080
1118
  export const ${e}Controller = {
1081
1119
  create${e},
1082
1120
  };
1083
- `,Ce=(e,r)=>`import { ${e} } from '@prisma/client';
1121
+ `,Se=(e,r)=>`import { ${e} } from '@prisma/client';
1084
1122
  import prisma from '../../lib/prisma.js';
1085
1123
 
1086
1124
  const create${e}IntoDB = async (payload: any) => {
@@ -1091,7 +1129,7 @@ const create${e}IntoDB = async (payload: any) => {
1091
1129
  export const ${e}Service = {
1092
1130
  create${e}IntoDB,
1093
1131
  };
1094
- `,Re=(e,r)=>`import { Router } from 'express';
1132
+ `,Ae=(e,r)=>`import { Router } from 'express';
1095
1133
  import { ${e}Controller } from './${r}.controller.js';
1096
1134
 
1097
1135
  const router = Router();
@@ -1099,10 +1137,10 @@ const router = Router();
1099
1137
  router.post('/create-${r}', ${e}Controller.create${e});
1100
1138
 
1101
1139
  export const ${e}Routes = router;
1102
- `,Se=e=>`export type I${e} = {
1140
+ `,Ee=e=>`export type I${e} = {
1103
1141
  // Define interface
1104
1142
  };
1105
- `,Ae=e=>`import { z } from 'zod';
1143
+ `,Fe=e=>`import { z } from 'zod';
1106
1144
 
1107
1145
  const create${e}ValidationSchema = z.object({
1108
1146
  body: z.object({
@@ -1113,17 +1151,17 @@ const create${e}ValidationSchema = z.object({
1113
1151
  export const ${e}Validations = {
1114
1152
  create${e}ValidationSchema,
1115
1153
  };
1116
- `,Ee=e=>`export const ${e}SearchableFields = [];
1117
- `,Fe=e=>`model ${e} {
1154
+ `,Pe=e=>`export const ${e}SearchableFields = [];
1155
+ `,Ie=e=>`model ${e} {
1118
1156
  id String @id @default(uuid())
1119
1157
  name String
1120
1158
  createdAt DateTime @default(now())
1121
1159
  updatedAt DateTime @updatedAt
1122
1160
  }
1123
- `;var Pe=async e=>{e||(console.log(v.red("\u274C Error: Module name is required.")),process.exit(1));let r=e.charAt(0).toUpperCase()+e.slice(1),d=e.toLowerCase(),x=R.existsSync("backend")?"backend":".",m=te.join(x,"src","app","module",r);R.existsSync(te.join(x,"src","app","module"))||(console.log(v.red("\u274C Error: This command must be run inside your shakil-stack project root or backend directory.")),process.exit(1)),R.existsSync(m)&&(console.log(v.red(`\u274C Error: Module ${r} already exists.`)),process.exit(1));let u=ze(`\u{1F6E0}\uFE0F Generating module: ${v.cyan(r)}...`).start();try{await R.ensureDir(m);let g={"controller.ts":je(r,d),"service.ts":Ce(r,d),"route.ts":Re(r,d),"interface.ts":Se(r),"validation.ts":Ae(r),"constant.ts":Ee(r)};await R.outputFile(te.join(x,"prisma","schema",`${d}.prisma`),Fe(r));for(let[T,h]of Object.entries(g))await R.outputFile(te.join(m,`${d}.${T}`),h);u.succeed(v.green(`\u2705 Module ${r} generated successfully! \u2728`)),console.log(v.gray(`Created at: ${m}`))}catch(g){u.fail(v.red("\u274C Failed to generate module.")),console.error(g)}};import $e from"fs-extra";import He from"chalk";var Ie=async()=>{let e=E(),r=$e.existsSync("backend")?"backend":".";console.log(He.cyan(`\u{1F3D7}\uFE0F Building backend with ${e}...`)),l(`${e} run build`,r)};import Be from"fs-extra";import re from"chalk";var Ue=async e=>{let r=Be.existsSync("backend")?"backend":".";e==="generate"?(console.log(re.cyan("\u{1F504} Generating Prisma client...")),l("npx prisma generate",r)):e==="migrate"?(console.log(re.cyan("\u{1F680} Running Prisma migrations...")),l("npx prisma migrate dev",r)):console.log(re.red(`\u274C Error: Unknown prisma subcommand: ${e}`))};import c from"fs-extra";import n from"path";import f from"chalk";import Me from"ora";var Oe=async()=>{let e=process.cwd(),r=n.join(e,"backend"),d=n.basename(e);c.existsSync(r)||(console.log(f.red("\u274C Error: Not in a shakil-stack project root (backend folder not found).")),process.exit(1));let x=Me("\u{1F504} Updating project structure...").start();try{let m=n.join(r,".env"),u=n.join(e,".env"),g="";c.existsSync(m)?(g=await c.readFile(m,"utf-8"),c.existsSync(u)?(console.log(f.yellow(`
1124
- \u26A0\uFE0F Both backend/.env and root .env exist. Merging...`)),await c.remove(m)):(await c.move(m,u),console.log(f.yellow(`
1125
- \u{1F4DD} Moved .env from backend/ to root.`)))):c.existsSync(u)&&(g=await c.readFile(u,"utf-8"));let T=['BETTER_AUTH_BASE_URL="http://localhost:8000"','CLIENT_URL="http://localhost:3000"','JWT_ACCESS_EXPIRES_IN="1h"','JWT_REFRESH_EXPIRES_IN="7d"'],h=g;for(let i of T){let w=i.split("=")[0];h.includes(w)||(h+=`
1126
- ${i}`)}h!==g&&(await c.outputFile(u,h.trim()+`
1127
- `),console.log(f.green("\u2705 Updated root .env with missing variables.")));let oe=[{path:n.join(r,"src","app","config","index.ts"),content:F},{path:n.join(r,"src","app","lib","prisma.ts"),content:P},{path:n.join(r,"src","app","lib","auth.ts"),content:I},{path:n.join(r,"prisma","schema","schema.prisma"),content:U},{path:n.join(r,"prisma.config.ts"),content:_}];for(let i of oe)await c.outputFile(i.path,i.content);let k=n.join(r,"src","app","module","auth");await c.ensureDir(k);let t=[{path:n.join(k,"auth.controller.ts"),content:M},{path:n.join(k,"auth.service.ts"),content:V},{path:n.join(k,"auth.route.ts"),content:W},{path:n.join(k,"auth.interface.ts"),content:G},{path:n.join(k,"auth.validation.ts"),content:J},{path:n.join(r,"src","app","utils","jwt.ts"),content:q},{path:n.join(r,"src","app","utils","cookie.ts"),content:N},{path:n.join(r,"src","app","utils","token.ts"),content:D},{path:n.join(r,"prisma","schema","auth.prisma"),content:O}];for(let i of t)c.existsSync(i.path)||(await c.outputFile(i.path,i.content),console.log(f.cyan(`\u{1F195} Added ${n.basename(i.path)} to auth module.`)));let p=n.join(e,"frontend");if(c.existsSync(p)){let i=[{path:n.join(p,"src","lib","axios","httpClient.ts"),content:K},{path:n.join(p,"src","lib","tokenUtils.ts"),content:Q},{path:n.join(p,"src","lib","cookieUtils.ts"),content:Y},{path:n.join(p,"src","services","auth.actions.ts"),content:X},{path:n.join(p,"src","components","auth","login-form.tsx"),content:Z},{path:n.join(p,"src","components","auth","register-form.tsx"),content:ee},{path:n.join(p,"src","app","(auth)","login","page.tsx"),content:C("login")},{path:n.join(p,"src","app","(auth)","register","page.tsx"),content:C("register")}];for(let w of i)c.existsSync(w.path)||(await c.outputFile(w.path,w.content),console.log(f.cyan(`\u{1F195} Added ${n.basename(w.path)} to frontend.`)))}let S=n.basename(e),b=[{path:n.join(e,".gitignore"),content:$},{path:n.join(e,"LICENSE"),content:L},{path:n.join(e,"README.md"),content:H(S)},{path:n.join(e,"CODE_OF_CONDUCT.md"),content:z},{path:n.join(e,"package.json"),content:B(S)}];for(let i of b)c.existsSync(i.path)||(await c.outputFile(i.path,i.content),console.log(f.cyan(`\u{1F4C4} Added ${n.basename(i.path)} to root.`)));let A=n.join(r,".gitignore");if(c.existsSync(A)){let i=await c.readFile(A,"utf-8");i.includes(".env")&&(i=i.replace(/\.env\n?/,"").trim(),await c.outputFile(A,i+`
1128
- `))}x.succeed(f.green("\u2705 Project updated successfully! \u2728")),console.log(f.cyan(`
1129
- Next Steps:`)),console.log(f.white("1. Check your root .env file and update credentials if needed.")),console.log(f.white("2. Run 'shakil-stack prisma generate' to update the Prisma client."))}catch(m){x.fail(f.red("\u274C Failed to update project.")),console.error(m),process.exit(1)}};var Ge=We(import.meta.url),_e=ne.dirname(Ge),Je=ne.resolve(_e,qe.existsSync(ne.resolve(_e,"../../package.json"))?"../../package.json":"../package.json"),Ke=qe.readJsonSync(Je),j=new Ve;j.name("shakil-stack").description("Full-stack EchoNet-style project generator CLI").version(Ke.version);j.command("init").description("Initialize a new full-stack project").argument("[projectName]","Name of the project").action(e=>{se(e)});j.command("update").description("Update an existing project to the latest shakil-stack version").action(()=>{Oe()});j.command("generate").alias("g").description("Generate a new module").argument("<type>","Type of generation (module)").argument("<name>","Name of the module").action((e,r)=>{e==="module"?Pe(r):console.log(`\u274C Error: Unknown generation type: ${e}`)});j.command("build").description("Build the backend for production").action(()=>{Ie()});j.command("prisma").description("Prisma utilities").argument("<subcommand>","generate | migrate").action(e=>{Ue(e)});process.argv.slice(2).length?j.parse(process.argv):se();
1161
+ `;var Ue=async e=>{e||(console.log(v.red("\u274C Error: Module name is required.")),process.exit(1));let r=e.charAt(0).toUpperCase()+e.slice(1),l=e.toLowerCase(),x=R.existsSync("backend")?"backend":".",m=te.join(x,"src","app","module",r);R.existsSync(te.join(x,"src","app","module"))||(console.log(v.red("\u274C Error: This command must be run inside your shakil-stack project root or backend directory.")),process.exit(1)),R.existsSync(m)&&(console.log(v.red(`\u274C Error: Module ${r} already exists.`)),process.exit(1));let u=Ve(`\u{1F6E0}\uFE0F Generating module: ${v.cyan(r)}...`).start();try{await R.ensureDir(m);let f={"controller.ts":Re(r,l),"service.ts":Se(r,l),"route.ts":Ae(r,l),"interface.ts":Ee(r),"validation.ts":Fe(r),"constant.ts":Pe(r)};await R.outputFile(te.join(x,"prisma","schema",`${l}.prisma`),Ie(r));for(let[T,h]of Object.entries(f))await R.outputFile(te.join(m,`${l}.${T}`),h);u.succeed(v.green(`\u2705 Module ${r} generated successfully! \u2728`)),console.log(v.gray(`Created at: ${m}`))}catch(f){u.fail(v.red("\u274C Failed to generate module.")),console.error(f)}};import We from"fs-extra";import Ge from"chalk";var Ne=async()=>{let e=E(),r=We.existsSync("backend")?"backend":".";console.log(Ge.cyan(`\u{1F3D7}\uFE0F Building backend with ${e}...`)),d(`${e} run build`,r)};import Je from"fs-extra";import re from"chalk";var Oe=async e=>{let r=Je.existsSync("backend")?"backend":".";e==="generate"?(console.log(re.cyan("\u{1F504} Generating Prisma client...")),d("npx prisma generate",r)):e==="migrate"?(console.log(re.cyan("\u{1F680} Running Prisma migrations...")),d("npx prisma migrate dev",r)):console.log(re.red(`\u274C Error: Unknown prisma subcommand: ${e}`))};import c from"fs-extra";import n from"path";import g from"chalk";import Qe from"ora";var _e=async()=>{let e=process.cwd(),r=n.join(e,"backend"),l=n.basename(e);c.existsSync(r)||(console.log(g.red("\u274C Error: Not in a shakil-stack project root (backend folder not found).")),process.exit(1));let x=Qe("\u{1F504} Updating project structure...").start();try{let m=n.join(r,".env"),u=n.join(e,".env"),f="";c.existsSync(m)?(f=await c.readFile(m,"utf-8"),c.existsSync(u)?(console.log(g.yellow(`
1162
+ \u26A0\uFE0F Both backend/.env and root .env exist. Merging...`)),await c.remove(m)):(await c.move(m,u),console.log(g.yellow(`
1163
+ \u{1F4DD} Moved .env from backend/ to root.`)))):c.existsSync(u)&&(f=await c.readFile(u,"utf-8"));let T=['BETTER_AUTH_BASE_URL="http://localhost:8000"','CLIENT_URL="http://localhost:3000"','JWT_ACCESS_EXPIRES_IN="1h"','JWT_REFRESH_EXPIRES_IN="7d"'],h=f;for(let i of T){let w=i.split("=")[0];h.includes(w)||(h+=`
1164
+ ${i}`)}h!==f&&(await c.outputFile(u,h.trim()+`
1165
+ `),console.log(g.green("\u2705 Updated root .env with missing variables.")));let oe=[{path:n.join(r,"src","app","config","index.ts"),content:F},{path:n.join(r,"src","app","lib","prisma.ts"),content:P},{path:n.join(r,"src","app","lib","auth.ts"),content:I},{path:n.join(r,"prisma","schema","schema.prisma"),content:U},{path:n.join(r,"prisma.config.ts"),content:O}];for(let i of oe)await c.outputFile(i.path,i.content);let k=n.join(r,"src","app","module","auth");await c.ensureDir(k);let t=[{path:n.join(k,"auth.controller.ts"),content:M},{path:n.join(k,"auth.service.ts"),content:V},{path:n.join(k,"auth.route.ts"),content:W},{path:n.join(k,"auth.interface.ts"),content:G},{path:n.join(k,"auth.validation.ts"),content:J},{path:n.join(r,"src","app","utils","jwt.ts"),content:_},{path:n.join(r,"src","app","utils","cookie.ts"),content:q},{path:n.join(r,"src","app","utils","token.ts"),content:D},{path:n.join(r,"prisma","schema","auth.prisma"),content:N}];for(let i of t)c.existsSync(i.path)||(await c.outputFile(i.path,i.content),console.log(g.cyan(`\u{1F195} Added ${n.basename(i.path)} to auth module.`)));let p=n.join(e,"frontend");if(c.existsSync(p)){let i=[{path:n.join(p,"src","lib","axios","httpClient.ts"),content:Q},{path:n.join(p,"src","lib","tokenUtils.ts"),content:K},{path:n.join(p,"src","lib","cookieUtils.ts"),content:Y},{path:n.join(p,"src","services","auth.actions.ts"),content:X},{path:n.join(p,"src","components","auth","login-form.tsx"),content:Z},{path:n.join(p,"src","components","auth","register-form.tsx"),content:ee},{path:n.join(p,"src","app","(auth)","login","page.tsx"),content:C("login")},{path:n.join(p,"src","app","(auth)","register","page.tsx"),content:C("register")}];for(let w of i)c.existsSync(w.path)||(await c.outputFile(w.path,w.content),console.log(g.cyan(`\u{1F195} Added ${n.basename(w.path)} to frontend.`)))}let S=n.basename(e),b=[{path:n.join(e,".gitignore"),content:z},{path:n.join(e,"LICENSE"),content:L},{path:n.join(e,"README.md"),content:H(S)},{path:n.join(e,"CODE_OF_CONDUCT.md"),content:$},{path:n.join(e,"package.json"),content:B(S)}];for(let i of b)c.existsSync(i.path)||(await c.outputFile(i.path,i.content),console.log(g.cyan(`\u{1F4C4} Added ${n.basename(i.path)} to root.`)));let A=n.join(r,".gitignore");if(c.existsSync(A)){let i=await c.readFile(A,"utf-8");i.includes(".env")&&(i=i.replace(/\.env\n?/,"").trim(),await c.outputFile(A,i+`
1166
+ `))}x.succeed(g.green("\u2705 Project updated successfully! \u2728")),console.log(g.cyan(`
1167
+ Next Steps:`)),console.log(g.white("1. Check your root .env file and update credentials if needed.")),console.log(g.white("2. Run 'shakil-stack prisma generate' to update the Prisma client."))}catch(m){x.fail(g.red("\u274C Failed to update project.")),console.error(m),process.exit(1)}};var Xe=Ye(import.meta.url),qe=ne.dirname(Xe),Ze=ne.resolve(qe,De.existsSync(ne.resolve(qe,"../../package.json"))?"../../package.json":"../package.json"),et=De.readJsonSync(Ze),j=new Ke;j.name("shakil-stack").description("Full-stack EchoNet-style project generator CLI").version(et.version);j.command("init").description("Initialize a new full-stack project").argument("[projectName]","Name of the project").action(e=>{se(e)});j.command("update").description("Update an existing project to the latest shakil-stack version").action(()=>{_e()});j.command("generate").alias("g").description("Generate a new module").argument("<type>","Type of generation (module)").argument("<name>","Name of the module").action((e,r)=>{e==="module"?Ue(r):console.log(`\u274C Error: Unknown generation type: ${e}`)});j.command("build").description("Build the backend for production").action(()=>{Ne()});j.command("prisma").description("Prisma utilities").argument("<subcommand>","generate | migrate").action(e=>{Oe(e)});process.argv.slice(2).length?j.parse(process.argv):se();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shakil-dev/shakil-stack",
3
- "version": "2.2.8",
3
+ "version": "2.2.9",
4
4
  "description": "Full-stack EchoNet-style project generator CLI",
5
5
  "keywords": [
6
6
  "shakil-stack",