@shakil-dev/shakil-stack 2.2.5 → 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 -46
  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 ue}from"url";import s from"fs-extra";import o from"path";import n from"chalk";import ae from"ora";import _ from"inquirer";import{execSync as oe}from"child_process";import xe from"fs-extra";var i=(e,r=process.cwd())=>{try{return oe(e,{stdio:"inherit",cwd:r}),!0}catch{return!1}},h=()=>{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,16 +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
- previewFeatures = ["prismaSchemaFolder"]
209
211
  output = "../../generated/prisma"
210
212
  }
211
213
 
212
214
  datasource db {
213
215
  provider = "postgresql"
216
+ url = env("DATABASE_URL")
214
217
  }
215
- `,N=`model User {
218
+ `,G=`model User {
216
219
  id String @id @default(uuid())
217
220
  email String @unique
218
221
  name String
@@ -248,7 +251,7 @@ model Account {
248
251
  updatedAt DateTime @updatedAt
249
252
  user User @relation(fields: [userId], references: [id], onDelete: Cascade)
250
253
  }
251
- `,q=`import "dotenv/config";
254
+ `,R=`import "dotenv/config";
252
255
  import { defineConfig } from "prisma/config";
253
256
  import process from "process";
254
257
 
@@ -258,7 +261,7 @@ export default defineConfig({
258
261
  url: process.env.DATABASE_URL,
259
262
  },
260
263
  });
261
- `,H=`{
264
+ `,V=`{
262
265
  "compilerOptions": {
263
266
  "target": "ES2022",
264
267
  "module": "NodeNext",
@@ -277,7 +280,7 @@ export default defineConfig({
277
280
  "include": ["src/**/*"],
278
281
  "exclude": ["node_modules", "dist"]
279
282
  }
280
- `;var L=`MIT License
283
+ `;var S=`MIT License
281
284
 
282
285
  Copyright (c) 2026 Shakil Ahmed Billal
283
286
 
@@ -298,7 +301,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
298
301
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
299
302
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
300
303
  SOFTWARE.
301
- `,z=`# Contributor Covenant Code of Conduct
304
+ `,A=`# Contributor Covenant Code of Conduct
302
305
 
303
306
  ## Our Pledge
304
307
 
@@ -372,12 +375,12 @@ version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
372
375
 
373
376
  [homepage]: http://contributor-covenant.org
374
377
  [version]: http://contributor-covenant.org/version/1/4
375
- `,M=`node_modules/
378
+ `,C=`node_modules/
376
379
  .env
377
380
  dist/
378
381
  *.log
379
382
  .DS_Store
380
- `,U=e=>`# \u{1F680} ${e}
383
+ `,F=e=>`# \u{1F680} ${e}
381
384
 
382
385
  This project was generated using [Shakil-Stack](https://github.com/shakil-ahmed-billal/shakil-stack-cli).
383
386
 
@@ -407,23 +410,25 @@ ${e}/
407
410
 
408
411
  ---
409
412
  Built with \u26A1 by **Shakil Ahmed Billal**
410
- `;var x=async e=>{let r=e;r||(r=(await _.prompt([{type:"input",name:"projectName",message:"What is your project name?",default:"shakil-stack-app"}])).projectName),r||(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:h()},{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=o.join(process.cwd(),r);s.existsSync(t)&&(console.log(n.red(`\u274C Error: Directory ${r} already exists.`)),process.exit(1)),console.log(n.cyan(`
411
- \u{1F680} Initializing ${n.bold(r)}...
412
- `));let d=ae("\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")),await s.ensureDir(o.join(t,"backend","prisma","schema")),console.log(n.cyan(`
413
- \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 m=["config","hooks","lib","services","types"];for(let f of m)await s.ensureDir(o.join(t,"frontend","src",f));if(g){console.log(n.cyan(`
414
- \u{1F3A8} Setting up shadcn/ui...`));try{i("npx shadcn@latest init -d",o.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`,o.join(t,"frontend")),console.log(n.green("\u2705 shadcn/ui and common components initialized successfully!\u2728"))}catch{console.log(n.yellow(`
415
- \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"),k(r)),await s.outputFile(o.join(t,"backend","src","app.ts"),j(r)),await s.outputFile(o.join(t,"backend","src","app","config","index.ts"),v),await s.outputFile(o.join(t,"backend","src","app","lib","prisma.ts"),R),await s.outputFile(o.join(t,"backend","src","app","lib","auth.ts"),S),await s.outputFile(o.join(t,"backend","src","app","routes","index.ts"),E),await s.outputFile(o.join(t,"backend","src","app","middleware","globalErrorHandler.ts"),A),await s.outputFile(o.join(t,"backend","src","app","middleware","notFound.ts"),C),await s.outputFile(o.join(t,"backend","src","app","middleware","sanitizeRequest.ts"),P),await s.outputFile(o.join(t,"backend","src","app","utils","catchAsync.ts"),D),await s.outputFile(o.join(t,"backend","src","app","utils","sendResponse.ts"),I),await s.outputFile(o.join(t,"backend","src","app","utils","sanitizer.ts"),O),await s.outputFile(o.join(t,"backend","src","app","errorHelpers","ApiError.ts"),F),await s.outputFile(o.join(t,"backend","prisma","schema","schema.prisma"),$),await s.outputFile(o.join(t,"backend","prisma","schema","auth.prisma"),N);let y=["meal.prisma","order.prisma","provider.prisma","review.prisma"];for(let f of y)await s.outputFile(o.join(t,"backend","prisma","schema",f),"// ${schema.split('.')[0].charAt(0).toUpperCase() + schema.split('.')[0].slice(1)} model\n");await s.outputFile(o.join(t,"backend","prisma.config.ts"),q),await s.outputFile(o.join(t,"backend","tsconfig.json"),H),await s.outputFile(o.join(t,".gitignore"),M),await s.outputFile(o.join(t,"LICENSE"),L),await s.outputFile(o.join(t,"README.md"),U(r)),await s.outputFile(o.join(t,"CODE_OF_CONDUCT.md"),z),await s.outputFile(o.join(t,".env"),`DATABASE_URL="postgresql://postgres:postgres@localhost:5432/${r}"
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}"
416
419
  JWT_SECRET="your-secret-key"
417
420
  NODE_ENV="development"
418
- PORT=8000`);let re={name:`${r}-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(o.join(t,"backend","package.json"),re,{spaces:2}),d.succeed(n.green("\u2705 Project structure created! \u2728")),c&&(console.log(n.yellow(`
419
- \u{1F4E6} Finalizing dependencies with ${a}...
420
- `)),i(`${a} install`,o.join(t,"backend"))),console.log(n.cyan("To get started:")),console.log(n.white(` cd ${r}`)),console.log(n.white(` cd backend && ${a} dev
421
- `)),console.log(n.white(` cd frontend && ${a} dev
422
- `))}catch(m){d.fail(n.red("\u274C Failed to initialize project.")),console.error(m),process.exit(1)}};import l from"fs-extra";import b from"path";import p from"chalk";import pe from"ora";var B=(e,r)=>`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';
423
428
  import httpStatus from 'http-status';
424
429
  import catchAsync from '../../utils/catchAsync.js';
425
430
  import sendResponse from '../../utils/sendResponse.js';
426
- import { ${e}Service } from './${r}.service.js';
431
+ import { ${e}Service } from './${t}.service.js';
427
432
 
428
433
  const create${e} = catchAsync(async (req: Request, res: Response) => {
429
434
  const result = await ${e}Service.create${e}IntoDB(req.body);
@@ -438,7 +443,7 @@ const create${e} = catchAsync(async (req: Request, res: Response) => {
438
443
  export const ${e}Controller = {
439
444
  create${e},
440
445
  };
441
- `,W=(e,r)=>`import { ${e} } from '@prisma/client';
446
+ `,Q=(e,t)=>`import { ${e} } from '@prisma/client';
442
447
  import prisma from '../../lib/prisma.js';
443
448
 
444
449
  const create${e}IntoDB = async (payload: any) => {
@@ -449,18 +454,18 @@ const create${e}IntoDB = async (payload: any) => {
449
454
  export const ${e}Service = {
450
455
  create${e}IntoDB,
451
456
  };
452
- `,G=(e,r)=>`import { Router } from 'express';
453
- import { ${e}Controller } from './${r}.controller.js';
457
+ `,Z=(e,t)=>`import { Router } from 'express';
458
+ import { ${e}Controller } from './${t}.controller.js';
454
459
 
455
460
  const router = Router();
456
461
 
457
- router.post('/create-${r}', ${e}Controller.create${e});
462
+ router.post('/create-${t}', ${e}Controller.create${e});
458
463
 
459
464
  export const ${e}Routes = router;
460
- `,V=e=>`export type I${e} = {
465
+ `,ee=e=>`export type I${e} = {
461
466
  // Define interface
462
467
  };
463
- `,J=e=>`import { z } from 'zod';
468
+ `,te=e=>`import { z } from 'zod';
464
469
 
465
470
  const create${e}ValidationSchema = z.object({
466
471
  body: z.object({
@@ -471,11 +476,17 @@ const create${e}ValidationSchema = z.object({
471
476
  export const ${e}Validations = {
472
477
  create${e}ValidationSchema,
473
478
  };
474
- `,Y=e=>`export const ${e}SearchableFields = [];
475
- `,K=e=>`model ${e} {
479
+ `,oe=e=>`export const ${e}SearchableFields = [];
480
+ `,re=e=>`model ${e} {
476
481
  id String @id @default(uuid())
477
482
  name String
478
483
  createdAt DateTime @default(now())
479
484
  updatedAt DateTime @updatedAt
480
485
  }
481
- `;var X=async e=>{e||(console.log(p.red("\u274C Error: Module name is required.")),process.exit(1));let r=e.charAt(0).toUpperCase()+e.slice(1),a=e.toLowerCase(),g=l.existsSync("backend")?"backend":".",c=b.join(g,"src","app","module",r);l.existsSync(b.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)),l.existsSync(c)&&(console.log(p.red(`\u274C Error: Module ${r} already exists.`)),process.exit(1));let t=pe(`\u{1F6E0}\uFE0F Generating module: ${p.cyan(r)}...`).start();try{await l.ensureDir(c);let d={"controller.ts":B(r,a),"service.ts":W(r,a),"route.ts":G(r,a),"interface.ts":V(r),"validation.ts":J(r),"constant.ts":Y(r)};await l.outputFile(b.join(g,"prisma","schema",`${a}.prisma`),K(r));for(let[m,y]of Object.entries(d))await l.outputFile(b.join(c,`${a}.${m}`),y);t.succeed(p.green(`\u2705 Module ${r} 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 ce from"fs-extra";import de from"chalk";var Q=async()=>{let e=h(),r=ce.existsSync("backend")?"backend":".";console.log(de.cyan(`\u{1F3D7}\uFE0F Building backend with ${e}...`)),i(`${e} run build`,r)};import me from"fs-extra";import w from"chalk";var Z=async e=>{let r=me.existsSync("backend")?"backend":".";e==="generate"?(console.log(w.cyan("\u{1F504} Generating Prisma client...")),i("npx prisma generate",r)):e==="migrate"?(console.log(w.cyan("\u{1F680} Running Prisma migrations...")),i("npx prisma migrate dev",r)):console.log(w.red(`\u274C Error: Unknown prisma subcommand: ${e}`))};var ge=ue(import.meta.url),ee=T.dirname(ge),fe=T.resolve(ee,te.existsSync(T.resolve(ee,"../../package.json"))?"../../package.json":"../package.json"),he=te.readJsonSync(fe),u=new le;u.name("shakil-stack").description("Full-stack EchoNet-style project generator CLI").version(he.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,r)=>{e==="module"?X(r):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.5",
3
+ "version": "2.2.7",
4
4
  "description": "Full-stack EchoNet-style project generator CLI",
5
5
  "keywords": [
6
6
  "shakil-stack",