@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.
- package/dist/index.js +57 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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:
|
|
104
|
-
trustedOrigins: [
|
|
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
|
-
`,
|
|
112
|
+
`,q=`import { Router } from 'express';
|
|
110
113
|
const router = Router();
|
|
111
114
|
export default router;
|
|
112
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
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
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
378
|
+
`,C=`node_modules/
|
|
375
379
|
.env
|
|
376
380
|
dist/
|
|
377
381
|
*.log
|
|
378
382
|
.DS_Store
|
|
379
|
-
`,
|
|
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
|
|
410
|
-
\u{1F680} Initializing ${n.bold(
|
|
411
|
-
`));let d=
|
|
412
|
-
\u{1F5BC}\uFE0F Scaffolding Next.js frontend...`)),
|
|
413
|
-
\u{1F3A8} Setting up shadcn/ui...`));try{
|
|
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(
|
|
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
|
|
418
|
-
|
|
419
|
-
`)
|
|
420
|
-
|
|
421
|
-
`))}
|
|
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 './${
|
|
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
|
-
`,
|
|
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
|
-
`,
|
|
452
|
-
import { ${e}Controller } from './${
|
|
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-${
|
|
462
|
+
router.post('/create-${t}', ${e}Controller.create${e});
|
|
457
463
|
|
|
458
464
|
export const ${e}Routes = router;
|
|
459
|
-
`,
|
|
465
|
+
`,ee=e=>`export type I${e} = {
|
|
460
466
|
// Define interface
|
|
461
467
|
};
|
|
462
|
-
`,
|
|
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
|
-
`,
|
|
474
|
-
`,
|
|
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
|
|
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();
|