@shakil-dev/shakil-stack 2.2.6 → 2.2.7

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 +57 -45
  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 le}from"commander";import te from"fs-extra";import T from"path";import{fileURLToPath as me}from"url";import s from"fs-extra";import r from"path";import n from"chalk";import ne from"ora";import _ from"inquirer";import{execSync as oe}from"child_process";import ye from"fs-extra";var i=(e,o=process.cwd())=>{try{return oe(e,{stdio:"inherit",cwd:o}),!0}catch{return!1}},f=()=>{let e=process.env.npm_config_user_agent||"";return e.includes("pnpm")?"pnpm":e.includes("yarn")?"yarn":"npm"};var k=e=>`import { Server } from 'http';
2
+ import{Command as Te}from"commander";import pe from"fs-extra";import N from"path";import{fileURLToPath as we}from"url";import s from"fs-extra";import r from"path";import n from"chalk";import ue from"ora";import K from"inquirer";import{execSync as me}from"child_process";import Se from"fs-extra";var m=(e,t=process.cwd())=>{try{return me(e,{stdio:"inherit",cwd:t}),!0}catch{return!1}},w=()=>{let e=process.env.npm_config_user_agent||"";return e.includes("pnpm")?"pnpm":e.includes("yarn")?"yarn":"npm"};var $=e=>`import { Server } from 'http';
3
3
  import app from './app.js';
4
4
  import config from './app/config/index.js';
5
5
 
@@ -14,7 +14,7 @@ async function bootstrap() {
14
14
  }
15
15
 
16
16
  bootstrap();
17
- `,j=e=>`import cors from 'cors';
17
+ `,_=e=>`import cors from 'cors';
18
18
  import express, { Application, Request, Response } from 'express';
19
19
  import httpStatus from 'http-status';
20
20
  import globalErrorHandler from './app/middleware/globalErrorHandler.js';
@@ -25,12 +25,13 @@ import morgan from 'morgan';
25
25
  import helmet from 'helmet';
26
26
  import { rateLimit } from 'express-rate-limit';
27
27
  import { sanitizeRequest } from './app/middleware/sanitizeRequest.js';
28
+ import config from './app/config/index.js';
28
29
 
29
30
  const app: Application = express();
30
31
 
31
32
  app.use(helmet());
32
33
  app.use(cors({
33
- origin: ["http://localhost:3000", "http://127.0.0.1:3000"],
34
+ origin: [config.client_url as string, "http://localhost:3000", "http://127.0.0.1:3000"],
34
35
  credentials: true,
35
36
  methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
36
37
  allowedHeaders: ["Content-Type", "Authorization", "Cookie"]
@@ -65,7 +66,7 @@ app.use(globalErrorHandler);
65
66
  app.use(notFound);
66
67
 
67
68
  export default app;
68
- `,v=`import dotenv from 'dotenv';
69
+ `,j=`import dotenv from 'dotenv';
69
70
  import path from 'path';
70
71
 
71
72
  dotenv.config({ path: path.join(process.cwd(), "..", ".env") });
@@ -75,8 +76,10 @@ export default {
75
76
  port: process.env.PORT || 8000,
76
77
  database_url: process.env.DATABASE_URL,
77
78
  jwt_secret: process.env.JWT_SECRET,
79
+ better_auth_base_url: process.env.BETTER_AUTH_BASE_URL,
80
+ client_url: process.env.CLIENT_URL,
78
81
  };
79
- `,R=`import "dotenv/config";
82
+ `,v=`import "dotenv/config";
80
83
  import { PrismaClient } from "@prisma/client";
81
84
  import pkg from 'pg';
82
85
  import { PrismaPg } from '@prisma/adapter-pg';
@@ -90,7 +93,7 @@ const prisma = new PrismaClient({ adapter });
90
93
 
91
94
  export default prisma;
92
95
  export { prisma };
93
- `,S=`import { betterAuth } from "better-auth";
96
+ `,k=`import { betterAuth } from "better-auth";
94
97
  import { prismaAdapter } from "better-auth/adapters/prisma";
95
98
  import config from "../config/index.js";
96
99
  import { prisma } from "./prisma.js";
@@ -100,16 +103,16 @@ export const auth = betterAuth({
100
103
  provider: "postgresql",
101
104
  }),
102
105
  secret: config.jwt_secret,
103
- baseURL: "http://localhost:8000",
104
- trustedOrigins: ["http://localhost:3000"],
106
+ baseURL: config.better_auth_base_url,
107
+ trustedOrigins: [config.client_url as string],
105
108
  emailAndPassword: {
106
109
  enabled: true,
107
110
  },
108
111
  });
109
- `,E=`import { Router } from 'express';
112
+ `,q=`import { Router } from 'express';
110
113
  const router = Router();
111
114
  export default router;
112
- `,A=`import { ErrorRequestHandler } from 'express';
115
+ `,L=`import { ErrorRequestHandler } from 'express';
113
116
  import config from '../config/index.js';
114
117
 
115
118
  const globalErrorHandler: ErrorRequestHandler = (error, req, res, next) => {
@@ -121,7 +124,7 @@ const globalErrorHandler: ErrorRequestHandler = (error, req, res, next) => {
121
124
  };
122
125
 
123
126
  export default globalErrorHandler;
124
- `,C=`import { Request, Response, NextFunction } from 'express';
127
+ `,U=`import { Request, Response, NextFunction } from 'express';
125
128
  import httpStatus from 'http-status';
126
129
 
127
130
  const notFound = (req: Request, res: Response, next: NextFunction) => {
@@ -132,7 +135,7 @@ const notFound = (req: Request, res: Response, next: NextFunction) => {
132
135
  };
133
136
 
134
137
  export default notFound;
135
- `,D=`import { NextFunction, Request, RequestHandler, Response } from 'express';
138
+ `,H=`import { NextFunction, Request, RequestHandler, Response } from 'express';
136
139
 
137
140
  const catchAsync = (fn: RequestHandler) => {
138
141
  return async (req: Request, res: Response, next: NextFunction) => {
@@ -145,7 +148,7 @@ const catchAsync = (fn: RequestHandler) => {
145
148
  };
146
149
 
147
150
  export default catchAsync;
148
- `,F=`class ApiError extends Error {
151
+ `,M=`class ApiError extends Error {
149
152
  statusCode: number;
150
153
  constructor(statusCode: number, message: string | undefined, stack = '') {
151
154
  super(message);
@@ -155,7 +158,7 @@ export default catchAsync;
155
158
  }
156
159
  }
157
160
  export default ApiError;
158
- `,O=`import { JSDOM } from 'jsdom';
161
+ `,z=`import { JSDOM } from 'jsdom';
159
162
  import createDOMPurify from 'dompurify';
160
163
 
161
164
  const window = new JSDOM('').window;
@@ -170,7 +173,7 @@ export const sanitize = (data: any): any => {
170
173
  }
171
174
  return data;
172
175
  };
173
- `,P=`import { Request, Response, NextFunction } from 'express';
176
+ `,B=`import { Request, Response, NextFunction } from 'express';
174
177
  import { sanitize } from '../utils/sanitizer.js';
175
178
 
176
179
  export const sanitizeRequest = (req: Request, res: Response, next: NextFunction) => {
@@ -179,7 +182,7 @@ export const sanitizeRequest = (req: Request, res: Response, next: NextFunction)
179
182
  if (req.params) sanitize(req.params);
180
183
  next();
181
184
  };
182
- `,I=`import { Response } from 'express';
185
+ `,W=`import { Response } from 'express';
183
186
 
184
187
  type IResponse<T> = {
185
188
  statusCode: number;
@@ -203,15 +206,16 @@ const sendResponse = <T>(res: Response, data: IResponse<T>) => {
203
206
  };
204
207
 
205
208
  export default sendResponse;
206
- `,$=`generator client {
209
+ `,E=`generator client {
207
210
  provider = "prisma-client-js"
208
211
  output = "../../generated/prisma"
209
212
  }
210
213
 
211
214
  datasource db {
212
215
  provider = "postgresql"
216
+ url = env("DATABASE_URL")
213
217
  }
214
- `,N=`model User {
218
+ `,G=`model User {
215
219
  id String @id @default(uuid())
216
220
  email String @unique
217
221
  name String
@@ -247,7 +251,7 @@ model Account {
247
251
  updatedAt DateTime @updatedAt
248
252
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
249
253
  }
250
- `,q=`import "dotenv/config";
254
+ `,R=`import "dotenv/config";
251
255
  import { defineConfig } from "prisma/config";
252
256
  import process from "process";
253
257
 
@@ -257,7 +261,7 @@ export default defineConfig({
257
261
  url: process.env.DATABASE_URL,
258
262
  },
259
263
  });
260
- `,H=`{
264
+ `,V=`{
261
265
  "compilerOptions": {
262
266
  "target": "ES2022",
263
267
  "module": "NodeNext",
@@ -276,7 +280,7 @@ export default defineConfig({
276
280
  "include": ["src/**/*"],
277
281
  "exclude": ["node_modules", "dist"]
278
282
  }
279
- `;var L=`MIT License
283
+ `;var S=`MIT License
280
284
 
281
285
  Copyright (c) 2026 Shakil Ahmed Billal
282
286
 
@@ -297,7 +301,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
297
301
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
298
302
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
299
303
  SOFTWARE.
300
- `,z=`# Contributor Covenant Code of Conduct
304
+ `,A=`# Contributor Covenant Code of Conduct
301
305
 
302
306
  ## Our Pledge
303
307
 
@@ -371,12 +375,12 @@ version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
371
375
 
372
376
  [homepage]: http://contributor-covenant.org
373
377
  [version]: http://contributor-covenant.org/version/1/4
374
- `,M=`node_modules/
378
+ `,C=`node_modules/
375
379
  .env
376
380
  dist/
377
381
  *.log
378
382
  .DS_Store
379
- `,U=e=>`# \u{1F680} ${e}
383
+ `,F=e=>`# \u{1F680} ${e}
380
384
 
381
385
  This project was generated using [Shakil-Stack](https://github.com/shakil-ahmed-billal/shakil-stack-cli).
382
386
 
@@ -406,23 +410,25 @@ ${e}/
406
410
 
407
411
  ---
408
412
  Built with \u26A1 by **Shakil Ahmed Billal**
409
- `;var x=async e=>{let o=e;o||(o=(await _.prompt([{type:"input",name:"projectName",message:"What is your project name?",default:"shakil-stack-app"}])).projectName),o||(console.log(n.red("\u274C Error: Project name is required.")),process.exit(1));let{packageManager:a,useShadcn:g,installDeps:c}=await _.prompt([{type:"list",name:"packageManager",message:"Which package manager do you want to use?",choices:["pnpm","npm","yarn"],default:f()},{type:"confirm",name:"useShadcn",message:"Would you like to use shadcn/ui?",default:!0},{type:"confirm",name:"installDeps",message:"Do you want to install dependencies automatically?",default:!0}]),t=r.join(process.cwd(),o);s.existsSync(t)&&(console.log(n.red(`\u274C Error: Directory ${o} already exists.`)),process.exit(1)),console.log(n.cyan(`
410
- \u{1F680} Initializing ${n.bold(o)}...
411
- `));let d=ne("\u{1F6E0}\uFE0F Creating project structure...").start();try{await s.ensureDir(t),await s.ensureDir(r.join(t,"backend","src","app","config")),await s.ensureDir(r.join(t,"backend","src","app","lib")),await s.ensureDir(r.join(t,"backend","src","app","module")),await s.ensureDir(r.join(t,"backend","src","app","routes")),await s.ensureDir(r.join(t,"backend","src","app","middleware")),await s.ensureDir(r.join(t,"backend","src","app","utils")),await s.ensureDir(r.join(t,"backend","src","app","errorHelpers")),await s.ensureDir(r.join(t,"backend","prisma","schema")),console.log(n.cyan(`
412
- \u{1F5BC}\uFE0F Scaffolding Next.js frontend...`)),i(`npx create-next-app@latest frontend --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-${a}`,t);let l=["config","hooks","lib","services","types"];for(let y of l)await s.ensureDir(r.join(t,"frontend","src",y));if(g){console.log(n.cyan(`
413
- \u{1F3A8} Setting up shadcn/ui...`));try{i("npx shadcn@latest init -d",r.join(t,"frontend")),console.log(n.cyan("\u{1F4E6} Adding common shadcn/ui components...")),i(`npx shadcn@latest add ${["button","card","input","label","textarea","dialog","dropdown-menu","table","tabs","checkbox"].join(" ")} -y`,r.join(t,"frontend")),console.log(n.green("\u2705 shadcn/ui and common components initialized successfully!\u2728"))}catch{console.log(n.yellow(`
414
- \u26A0\uFE0F Warning: Failed to automate shadcn/ui init. You can run "npx shadcn@latest init" in the frontend folder.`))}}await s.outputFile(r.join(t,"backend","src","server.ts"),k(o)),await s.outputFile(r.join(t,"backend","src","app.ts"),j(o)),await s.outputFile(r.join(t,"backend","src","app","config","index.ts"),v),await s.outputFile(r.join(t,"backend","src","app","lib","prisma.ts"),R),await s.outputFile(r.join(t,"backend","src","app","lib","auth.ts"),S),await s.outputFile(r.join(t,"backend","src","app","routes","index.ts"),E),await s.outputFile(r.join(t,"backend","src","app","middleware","globalErrorHandler.ts"),A),await s.outputFile(r.join(t,"backend","src","app","middleware","notFound.ts"),C),await s.outputFile(r.join(t,"backend","src","app","middleware","sanitizeRequest.ts"),P),await s.outputFile(r.join(t,"backend","src","app","utils","catchAsync.ts"),D),await s.outputFile(r.join(t,"backend","src","app","utils","sendResponse.ts"),I),await s.outputFile(r.join(t,"backend","src","app","utils","sanitizer.ts"),O),await s.outputFile(r.join(t,"backend","src","app","errorHelpers","ApiError.ts"),F),await s.outputFile(r.join(t,"backend","prisma","schema","schema.prisma"),$),await s.outputFile(r.join(t,"backend","prisma","schema","auth.prisma"),N),await s.outputFile(r.join(t,"backend","prisma.config.ts"),q),await s.outputFile(r.join(t,"backend","tsconfig.json"),H),await s.outputFile(r.join(t,".gitignore"),M),await s.outputFile(r.join(t,"LICENSE"),L),await s.outputFile(r.join(t,"README.md"),U(o)),await s.outputFile(r.join(t,"CODE_OF_CONDUCT.md"),z),await s.outputFile(r.join(t,".env"),`DATABASE_URL="postgresql://postgres:postgres@localhost:5432/${o}"
413
+ `;var O=async e=>{let t=e;t||(t=(await K.prompt([{type:"input",name:"projectName",message:"What is your project name?",default:"shakil-stack-app"}])).projectName),t||(console.log(n.red("\u274C Error: Project name is required.")),process.exit(1));let{packageManager:p,useShadcn:f,installDeps:l}=await K.prompt([{type:"list",name:"packageManager",message:"Which package manager do you want to use?",choices:["pnpm","npm","yarn"],default:w()},{type:"confirm",name:"useShadcn",message:"Would you like to use shadcn/ui?",default:!0},{type:"confirm",name:"installDeps",message:"Do you want to install dependencies automatically?",default:!0}]),o=r.join(process.cwd(),t);s.existsSync(o)&&(console.log(n.red(`\u274C Error: Directory ${t} already exists.`)),process.exit(1)),console.log(n.cyan(`
414
+ \u{1F680} Initializing ${n.bold(t)}...
415
+ `));let d=ue("\u{1F6E0}\uFE0F Creating project structure...").start();try{await s.ensureDir(o),await s.ensureDir(r.join(o,"backend","src","app","config")),await s.ensureDir(r.join(o,"backend","src","app","lib")),await s.ensureDir(r.join(o,"backend","src","app","module")),await s.ensureDir(r.join(o,"backend","src","app","routes")),await s.ensureDir(r.join(o,"backend","src","app","middleware")),await s.ensureDir(r.join(o,"backend","src","app","utils")),await s.ensureDir(r.join(o,"backend","src","app","errorHelpers")),await s.ensureDir(r.join(o,"backend","prisma","schema")),console.log(n.cyan(`
416
+ \u{1F5BC}\uFE0F Scaffolding Next.js frontend...`)),m(`npx create-next-app@latest frontend --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-${p}`,o);let g=["config","hooks","lib","services","types"];for(let T of g)await s.ensureDir(r.join(o,"frontend","src",T));if(f){console.log(n.cyan(`
417
+ \u{1F3A8} Setting up shadcn/ui...`));try{m("npx shadcn@latest init -d",r.join(o,"frontend")),console.log(n.cyan("\u{1F4E6} Adding common shadcn/ui components...")),m(`npx shadcn@latest add ${["button","card","input","label","textarea","dialog","dropdown-menu","table","tabs","checkbox"].join(" ")} -y`,r.join(o,"frontend")),console.log(n.green("\u2705 shadcn/ui and common components initialized successfully!\u2728"))}catch{console.log(n.yellow(`
418
+ \u26A0\uFE0F Warning: Failed to automate shadcn/ui init. You can run "npx shadcn@latest init" in the frontend folder.`))}}await s.outputFile(r.join(o,"backend","src","server.ts"),$(t)),await s.outputFile(r.join(o,"backend","src","app.ts"),_(t)),await s.outputFile(r.join(o,"backend","src","app","config","index.ts"),j),await s.outputFile(r.join(o,"backend","src","app","lib","prisma.ts"),v),await s.outputFile(r.join(o,"backend","src","app","lib","auth.ts"),k),await s.outputFile(r.join(o,"backend","src","app","routes","index.ts"),q),await s.outputFile(r.join(o,"backend","src","app","middleware","globalErrorHandler.ts"),L),await s.outputFile(r.join(o,"backend","src","app","middleware","notFound.ts"),U),await s.outputFile(r.join(o,"backend","src","app","middleware","sanitizeRequest.ts"),B),await s.outputFile(r.join(o,"backend","src","app","utils","catchAsync.ts"),H),await s.outputFile(r.join(o,"backend","src","app","utils","sendResponse.ts"),W),await s.outputFile(r.join(o,"backend","src","app","utils","sanitizer.ts"),z),await s.outputFile(r.join(o,"backend","src","app","errorHelpers","ApiError.ts"),M),await s.outputFile(r.join(o,"backend","prisma","schema","schema.prisma"),E),await s.outputFile(r.join(o,"backend","prisma","schema","auth.prisma"),G),await s.outputFile(r.join(o,"backend","prisma.config.ts"),R),await s.outputFile(r.join(o,"backend","tsconfig.json"),V),await s.outputFile(r.join(o,".gitignore"),C),await s.outputFile(r.join(o,"LICENSE"),S),await s.outputFile(r.join(o,"README.md"),F(t)),await s.outputFile(r.join(o,"CODE_OF_CONDUCT.md"),A),await s.outputFile(r.join(o,".env"),`DATABASE_URL="postgresql://postgres:postgres@localhost:5432/${t}"
415
419
  JWT_SECRET="your-secret-key"
416
420
  NODE_ENV="development"
417
- PORT=8000`);let b={name:`${o}-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:{"@prisma/adapter-pg":"^7.5.0","@prisma/client":"^7.5.0","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",pg:"^8.20.0",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","@types/pg":"^8.20.0","@types/morgan":"^1.9.10","@types/jsdom":"^21.1.7",prisma:"^7.5.0",tsx:"^4.21.0",nodemon:"^3.1.14",tsup:"^8.5.1",typescript:"^5.9.3",eslint:"^9.21.0",prettier:"^3.5.2"}};await s.writeJson(r.join(t,"backend","package.json"),b,{spaces:2}),d.succeed(n.green("\u2705 Project structure created! \u2728")),c&&(console.log(n.yellow(`
418
- \u{1F4E6} Finalizing dependencies with ${a}...
419
- `)),i(`${a} install`,r.join(t,"backend"))),console.log(n.cyan("To get started:")),console.log(n.white(` cd ${o}`)),console.log(n.white(` cd backend && ${a} dev
420
- `)),console.log(n.white(` cd frontend && ${a} dev
421
- `))}catch(l){d.fail(n.red("\u274C Failed to initialize project.")),console.error(l),process.exit(1)}};import m from"fs-extra";import h from"path";import p from"chalk";import ie from"ora";var B=(e,o)=>`import { Request, Response } from 'express';
421
+ PORT=8000
422
+ BETTER_AUTH_BASE_URL="http://localhost:8000"
423
+ CLIENT_URL="http://localhost:3000"`);let h={name:`${t}-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:{"@prisma/adapter-pg":"^7.5.0","@prisma/client":"^7.5.0","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",pg:"^8.20.0",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","@types/pg":"^8.20.0","@types/morgan":"^1.9.10","@types/jsdom":"^21.1.7",prisma:"^7.5.0",tsx:"^4.21.0",nodemon:"^3.1.14",tsup:"^8.5.1",typescript:"^5.9.3",eslint:"^9.21.0",prettier:"^3.5.2"}};await s.writeJson(r.join(o,"backend","package.json"),h,{spaces:2}),d.succeed(n.green("\u2705 Project structure created! \u2728")),l&&(console.log(n.yellow(`
424
+ \u{1F4E6} Finalizing dependencies with ${p}...
425
+ `)),m(`${p} install`,r.join(o,"backend"))),console.log(n.cyan("To get started:")),console.log(n.white(` cd ${t}`)),console.log(n.white(` cd backend && ${p} dev
426
+ `)),console.log(n.white(` cd frontend && ${p} dev
427
+ `))}catch(g){d.fail(n.red("\u274C Failed to initialize project.")),console.error(g),process.exit(1)}};import x from"fs-extra";import P from"path";import b from"chalk";import ge from"ora";var X=(e,t)=>`import { Request, Response } from 'express';
422
428
  import httpStatus from 'http-status';
423
429
  import catchAsync from '../../utils/catchAsync.js';
424
430
  import sendResponse from '../../utils/sendResponse.js';
425
- import { ${e}Service } from './${o}.service.js';
431
+ import { ${e}Service } from './${t}.service.js';
426
432
 
427
433
  const create${e} = catchAsync(async (req: Request, res: Response) => {
428
434
  const result = await ${e}Service.create${e}IntoDB(req.body);
@@ -437,7 +443,7 @@ const create${e} = catchAsync(async (req: Request, res: Response) => {
437
443
  export const ${e}Controller = {
438
444
  create${e},
439
445
  };
440
- `,W=(e,o)=>`import { ${e} } from '@prisma/client';
446
+ `,Q=(e,t)=>`import { ${e} } from '@prisma/client';
441
447
  import prisma from '../../lib/prisma.js';
442
448
 
443
449
  const create${e}IntoDB = async (payload: any) => {
@@ -448,18 +454,18 @@ const create${e}IntoDB = async (payload: any) => {
448
454
  export const ${e}Service = {
449
455
  create${e}IntoDB,
450
456
  };
451
- `,G=(e,o)=>`import { Router } from 'express';
452
- import { ${e}Controller } from './${o}.controller.js';
457
+ `,Z=(e,t)=>`import { Router } from 'express';
458
+ import { ${e}Controller } from './${t}.controller.js';
453
459
 
454
460
  const router = Router();
455
461
 
456
- router.post('/create-${o}', ${e}Controller.create${e});
462
+ router.post('/create-${t}', ${e}Controller.create${e});
457
463
 
458
464
  export const ${e}Routes = router;
459
- `,V=e=>`export type I${e} = {
465
+ `,ee=e=>`export type I${e} = {
460
466
  // Define interface
461
467
  };
462
- `,J=e=>`import { z } from 'zod';
468
+ `,te=e=>`import { z } from 'zod';
463
469
 
464
470
  const create${e}ValidationSchema = z.object({
465
471
  body: z.object({
@@ -470,11 +476,17 @@ const create${e}ValidationSchema = z.object({
470
476
  export const ${e}Validations = {
471
477
  create${e}ValidationSchema,
472
478
  };
473
- `,Y=e=>`export const ${e}SearchableFields = [];
474
- `,K=e=>`model ${e} {
479
+ `,oe=e=>`export const ${e}SearchableFields = [];
480
+ `,re=e=>`model ${e} {
475
481
  id String @id @default(uuid())
476
482
  name String
477
483
  createdAt DateTime @default(now())
478
484
  updatedAt DateTime @updatedAt
479
485
  }
480
- `;var X=async e=>{e||(console.log(p.red("\u274C Error: Module name is required.")),process.exit(1));let o=e.charAt(0).toUpperCase()+e.slice(1),a=e.toLowerCase(),g=m.existsSync("backend")?"backend":".",c=h.join(g,"src","app","module",o);m.existsSync(h.join(g,"src","app","module"))||(console.log(p.red("\u274C Error: This command must be run inside your shakil-stack project root or backend directory.")),process.exit(1)),m.existsSync(c)&&(console.log(p.red(`\u274C Error: Module ${o} already exists.`)),process.exit(1));let t=ie(`\u{1F6E0}\uFE0F Generating module: ${p.cyan(o)}...`).start();try{await m.ensureDir(c);let d={"controller.ts":B(o,a),"service.ts":W(o,a),"route.ts":G(o,a),"interface.ts":V(o),"validation.ts":J(o),"constant.ts":Y(o)};await m.outputFile(h.join(g,"prisma","schema",`${a}.prisma`),K(o));for(let[l,b]of Object.entries(d))await m.outputFile(h.join(c,`${a}.${l}`),b);t.succeed(p.green(`\u2705 Module ${o} generated successfully! \u2728`)),console.log(p.gray(`Created at: ${c}`))}catch(d){t.fail(p.red("\u274C Failed to generate module.")),console.error(d)}};import pe from"fs-extra";import ce from"chalk";var Q=async()=>{let e=f(),o=pe.existsSync("backend")?"backend":".";console.log(ce.cyan(`\u{1F3D7}\uFE0F Building backend with ${e}...`)),i(`${e} run build`,o)};import de from"fs-extra";import w from"chalk";var Z=async e=>{let o=de.existsSync("backend")?"backend":".";e==="generate"?(console.log(w.cyan("\u{1F504} Generating Prisma client...")),i("npx prisma generate",o)):e==="migrate"?(console.log(w.cyan("\u{1F680} Running Prisma migrations...")),i("npx prisma migrate dev",o)):console.log(w.red(`\u274C Error: Unknown prisma subcommand: ${e}`))};var ue=me(import.meta.url),ee=T.dirname(ue),ge=T.resolve(ee,te.existsSync(T.resolve(ee,"../../package.json"))?"../../package.json":"../package.json"),fe=te.readJsonSync(ge),u=new le;u.name("shakil-stack").description("Full-stack EchoNet-style project generator CLI").version(fe.version);u.command("init").description("Initialize a new full-stack project").argument("[projectName]","Name of the project").action(e=>{x(e)});u.command("generate").alias("g").description("Generate a new module").argument("<type>","Type of generation (module)").argument("<name>","Name of the module").action((e,o)=>{e==="module"?X(o):console.log(`\u274C Error: Unknown generation type: ${e}`)});u.command("build").description("Build the backend for production").action(()=>{Q()});u.command("prisma").description("Prisma utilities").argument("<subcommand>","generate | migrate").action(e=>{Z(e)});process.argv.slice(2).length?u.parse(process.argv):x();
486
+ `;var se=async e=>{e||(console.log(b.red("\u274C Error: Module name is required.")),process.exit(1));let t=e.charAt(0).toUpperCase()+e.slice(1),p=e.toLowerCase(),f=x.existsSync("backend")?"backend":".",l=P.join(f,"src","app","module",t);x.existsSync(P.join(f,"src","app","module"))||(console.log(b.red("\u274C Error: This command must be run inside your shakil-stack project root or backend directory.")),process.exit(1)),x.existsSync(l)&&(console.log(b.red(`\u274C Error: Module ${t} already exists.`)),process.exit(1));let o=ge(`\u{1F6E0}\uFE0F Generating module: ${b.cyan(t)}...`).start();try{await x.ensureDir(l);let d={"controller.ts":X(t,p),"service.ts":Q(t,p),"route.ts":Z(t,p),"interface.ts":ee(t),"validation.ts":te(t),"constant.ts":oe(t)};await x.outputFile(P.join(f,"prisma","schema",`${p}.prisma`),re(t));for(let[g,h]of Object.entries(d))await x.outputFile(P.join(l,`${p}.${g}`),h);o.succeed(b.green(`\u2705 Module ${t} generated successfully! \u2728`)),console.log(b.gray(`Created at: ${l}`))}catch(d){o.fail(b.red("\u274C Failed to generate module.")),console.error(d)}};import he from"fs-extra";import be from"chalk";var ne=async()=>{let e=w(),t=he.existsSync("backend")?"backend":".";console.log(be.cyan(`\u{1F3D7}\uFE0F Building backend with ${e}...`)),m(`${e} run build`,t)};import ye from"fs-extra";import I from"chalk";var ae=async e=>{let t=ye.existsSync("backend")?"backend":".";e==="generate"?(console.log(I.cyan("\u{1F504} Generating Prisma client...")),m("npx prisma generate --schema prisma/schema",t)):e==="migrate"?(console.log(I.cyan("\u{1F680} Running Prisma migrations...")),m("npx prisma migrate dev --schema prisma/schema",t)):console.log(I.red(`\u274C Error: Unknown prisma subcommand: ${e}`))};import i from"fs-extra";import c from"path";import u from"chalk";import xe from"ora";var ie=async()=>{let e=process.cwd(),t=c.join(e,"backend"),p=c.basename(e);i.existsSync(t)||(console.log(u.red("\u274C Error: Not in a shakil-stack project root (backend folder not found).")),process.exit(1));let f=xe("\u{1F504} Updating project structure...").start();try{let l=c.join(t,".env"),o=c.join(e,".env"),d="";i.existsSync(l)?(d=await i.readFile(l,"utf-8"),i.existsSync(o)?(console.log(u.yellow(`
487
+ \u26A0\uFE0F Both backend/.env and root .env exist. Merging...`)),await i.remove(l)):(await i.move(l,o),console.log(u.yellow(`
488
+ \u{1F4DD} Moved .env from backend/ to root.`)))):i.existsSync(o)&&(d=await i.readFile(o,"utf-8"));let g=['BETTER_AUTH_BASE_URL="http://localhost:8000"','CLIENT_URL="http://localhost:3000"'],h=d;for(let a of g){let de=a.split("=")[0];h.includes(de)||(h+=`
489
+ ${a}`)}h!==d&&(await i.outputFile(o,h.trim()+`
490
+ `),console.log(u.green("\u2705 Updated root .env with missing variables.")));let T=[{path:c.join(t,"src","app","config","index.ts"),content:j},{path:c.join(t,"src","app","lib","prisma.ts"),content:v},{path:c.join(t,"src","app","lib","auth.ts"),content:k},{path:c.join(t,"prisma","schema","schema.prisma"),content:E},{path:c.join(t,"prisma.config.ts"),content:R}];for(let a of T)await i.outputFile(a.path,a.content);let le=[{path:c.join(e,".gitignore"),content:C},{path:c.join(e,"LICENSE"),content:S},{path:c.join(e,"README.md"),content:F(p)},{path:c.join(e,"CODE_OF_CONDUCT.md"),content:A}];for(let a of le)i.existsSync(a.path)||(await i.outputFile(a.path,a.content),console.log(u.cyan(`\u{1F4C4} Added ${c.basename(a.path)} to root.`)));let D=c.join(t,".gitignore");if(i.existsSync(D)){let a=await i.readFile(D,"utf-8");a.includes(".env")&&(a=a.replace(/\.env\n?/,"").trim(),await i.outputFile(D,a+`
491
+ `))}f.succeed(u.green("\u2705 Project updated successfully! \u2728")),console.log(u.cyan(`
492
+ Next Steps:`)),console.log(u.white("1. Check your root .env file and update credentials if needed.")),console.log(u.white("2. Run 'shakil-stack prisma generate' to update the Prisma client."))}catch(l){f.fail(u.red("\u274C Failed to update project.")),console.error(l),process.exit(1)}};var je=we(import.meta.url),ce=N.dirname(je),ve=N.resolve(ce,pe.existsSync(N.resolve(ce,"../../package.json"))?"../../package.json":"../package.json"),ke=pe.readJsonSync(ve),y=new Te;y.name("shakil-stack").description("Full-stack EchoNet-style project generator CLI").version(ke.version);y.command("init").description("Initialize a new full-stack project").argument("[projectName]","Name of the project").action(e=>{O(e)});y.command("update").description("Update an existing project to the latest shakil-stack version").action(()=>{ie()});y.command("generate").alias("g").description("Generate a new module").argument("<type>","Type of generation (module)").argument("<name>","Name of the module").action((e,t)=>{e==="module"?se(t):console.log(`\u274C Error: Unknown generation type: ${e}`)});y.command("build").description("Build the backend for production").action(()=>{ne()});y.command("prisma").description("Prisma utilities").argument("<subcommand>","generate | migrate").action(e=>{ae(e)});process.argv.slice(2).length?y.parse(process.argv):O();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shakil-dev/shakil-stack",
3
- "version": "2.2.6",
3
+ "version": "2.2.7",
4
4
  "description": "Full-stack EchoNet-style project generator CLI",
5
5
  "keywords": [
6
6
  "shakil-stack",