lapeeh 1.0.5 → 1.0.6

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/bin/index.js CHANGED
@@ -1,17 +1,17 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { execSync, spawn } = require('child_process');
6
- const readline = require('readline');
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { execSync, spawn } = require("child_process");
6
+ const readline = require("readline");
7
7
 
8
8
  // --- Helper Functions for Animation ---
9
9
 
10
10
  async function spin(text, fn) {
11
- const frames = ['', '', '', '', '', '', '', '', '', ''];
11
+ const frames = ["", "", "", "", "", "", "", "", "", ""];
12
12
  let i = 0;
13
13
  process.stdout.write(`\x1b[?25l`); // Hide cursor
14
-
14
+
15
15
  const interval = setInterval(() => {
16
16
  process.stdout.write(`\r\x1b[36m${frames[i]} ${text}\x1b[0m`);
17
17
  i = (i + 1) % frames.length;
@@ -35,13 +35,17 @@ function runCommand(cmd, cwd) {
35
35
  return new Promise((resolve, reject) => {
36
36
  // Use spawn to capture output or run silently
37
37
  // Using shell: true to handle cross-platform command execution
38
- const child = spawn(cmd, { cwd, shell: true, stdio: 'pipe' });
39
- let output = '';
40
-
41
- child.stdout.on('data', (data) => { output += data.toString(); });
42
- child.stderr.on('data', (data) => { output += data.toString(); });
43
-
44
- child.on('close', (code) => {
38
+ const child = spawn(cmd, { cwd, shell: true, stdio: "pipe" });
39
+ let output = "";
40
+
41
+ child.stdout.on("data", (data) => {
42
+ output += data.toString();
43
+ });
44
+ child.stderr.on("data", (data) => {
45
+ output += data.toString();
46
+ });
47
+
48
+ child.on("close", (code) => {
45
49
  if (code === 0) resolve(output);
46
50
  else reject(new Error(`Command failed with code ${code}\n${output}`));
47
51
  });
@@ -54,54 +58,55 @@ const command = args[0];
54
58
  // Telemetry Logic
55
59
  async function sendTelemetry(cmd, errorInfo = null) {
56
60
  try {
57
- const os = require('os');
58
-
61
+ const os = require("os");
62
+
59
63
  const payload = {
60
64
  command: cmd,
61
65
  nodeVersion: process.version,
62
66
  osPlatform: os.platform(),
63
67
  osRelease: os.release(),
64
- timestamp: new Date().toISOString()
68
+ timestamp: new Date().toISOString(),
65
69
  };
66
70
 
67
71
  if (errorInfo) {
68
- payload.error = errorInfo.message;
69
- payload.stack = errorInfo.stack;
72
+ payload.error = errorInfo.message;
73
+ payload.stack = errorInfo.stack;
70
74
  }
71
75
 
72
76
  // Add version to payload
73
77
  try {
74
- const pkg = require(path.join(__dirname, '../package.json'));
75
- payload.cliVersion = pkg.version;
78
+ const pkg = require(path.join(__dirname, "../package.json"));
79
+ payload.cliVersion = pkg.version;
76
80
  } catch (e) {
77
- payload.cliVersion = 'unknown';
81
+ payload.cliVersion = "unknown";
78
82
  }
79
83
 
80
84
  const data = JSON.stringify(payload);
81
85
 
82
86
  // Parse URL from env or use default
83
- const apiUrl = process.env.lapeeh_API_URL || 'https://lapeeh.vercel.app/api/telemetry';
87
+ const apiUrl =
88
+ process.env.lapeeh_API_URL || "https://lapeeh.vercel.app/api/telemetry";
84
89
  const url = new URL(apiUrl);
85
- const isHttps = url.protocol === 'https:';
86
- const client = isHttps ? require('https') : require('http');
90
+ const isHttps = url.protocol === "https:";
91
+ const client = isHttps ? require("https") : require("http");
87
92
 
88
93
  const options = {
89
94
  hostname: url.hostname,
90
95
  port: url.port || (isHttps ? 443 : 80),
91
96
  path: url.pathname,
92
- method: 'POST',
97
+ method: "POST",
93
98
  headers: {
94
- 'Content-Type': 'application/json',
95
- 'Content-Length': Buffer.byteLength(data)
99
+ "Content-Type": "application/json",
100
+ "Content-Length": Buffer.byteLength(data),
96
101
  },
97
- timeout: 2000 // Slightly longer for crash reports
102
+ timeout: 2000, // Slightly longer for crash reports
98
103
  };
99
104
 
100
105
  const req = client.request(options, (res) => {
101
106
  res.resume();
102
107
  });
103
-
104
- req.on('error', (e) => {
108
+
109
+ req.on("error", (e) => {
105
110
  // Silent fail
106
111
  });
107
112
 
@@ -113,80 +118,92 @@ async function sendTelemetry(cmd, errorInfo = null) {
113
118
  }
114
119
 
115
120
  // Global Error Handler for Crash Reporting
116
- process.on('uncaughtException', async (err) => {
117
- console.error('❌ Unexpected Error:', err);
118
- console.log('📝 Sending crash report...');
121
+ process.on("uncaughtException", async (err) => {
122
+ console.error("❌ Unexpected Error:", err);
123
+ console.log("📝 Sending crash report...");
119
124
  try {
120
- sendTelemetry(command || 'unknown', err);
121
-
122
- // Give it a moment to send
123
- setTimeout(() => {
124
- process.exit(1);
125
- }, 1000);
126
- } catch (e) {
125
+ sendTelemetry(command || "unknown", err);
126
+
127
+ // Give it a moment to send
128
+ setTimeout(() => {
127
129
  process.exit(1);
130
+ }, 1000);
131
+ } catch (e) {
132
+ process.exit(1);
128
133
  }
129
134
  });
130
135
 
131
136
  function showHelp() {
132
- console.log('\n\x1b[36m L A P E H F R A M E W O R K C L I\x1b[0m\n');
133
- console.log('Usage: npx lapeeh <command> [options]\n');
134
- console.log('Commands:');
135
- console.log(' create <name> Create a new lapeeh project');
136
- console.log(' dev Start development server (with update check)');
137
- console.log(' start Start production server');
138
- console.log(' build Build the project for production');
139
- console.log(' upgrade Upgrade project files to match framework version');
140
- console.log(' module <name> Create a new module (controller, routes, etc.)');
141
- console.log(' help Show this help message');
142
- console.log('\nOptions:');
143
- console.log(' --full Create project with full example (auth, users, etc)');
144
- console.log(' -y, --defaults Skip prompts and use defaults');
145
- console.log(' -h, --help Show this help message');
146
- console.log('\nExamples:');
147
- console.log(' npx lapeeh my-app');
148
- console.log(' npx lapeeh create my-app --full');
149
- console.log(' npx lapeeh dev');
150
- console.log('\n');
137
+ console.log("\n\x1b[36m L A P E H F R A M E W O R K C L I\x1b[0m\n");
138
+ console.log("Usage: npx lapeeh <command> [options]\n");
139
+ console.log("Commands:");
140
+ console.log(" create <name> Create a new lapeeh project");
141
+ console.log(" dev Start development server (with update check)");
142
+ console.log(" start Start production server");
143
+ console.log(" build Build the project for production");
144
+ console.log(
145
+ " upgrade Upgrade project files to match framework version"
146
+ );
147
+ console.log(
148
+ " module <name> Create a new module (controller, routes, etc.)"
149
+ );
150
+ console.log(" help Show this help message");
151
+ console.log("\nOptions:");
152
+ console.log(
153
+ " --full Create project with full example (auth, users, etc)"
154
+ );
155
+ console.log(" -y, --defaults Skip prompts and use defaults");
156
+ console.log(" -h, --help Show this help message");
157
+ console.log("\nExamples:");
158
+ console.log(" npx lapeeh my-app");
159
+ console.log(" npx lapeeh create my-app --full");
160
+ console.log(" npx lapeeh dev");
161
+ console.log("\n");
151
162
  }
152
163
 
153
164
  // Handle Help or No Args
154
- if (!command || ['help', '--help', '-h'].includes(command)) {
155
- showHelp();
156
- sendTelemetry('help');
157
- process.exit(0);
165
+ if (!command || ["help", "--help", "-h"].includes(command)) {
166
+ showHelp();
167
+ sendTelemetry("help");
168
+ process.exit(0);
158
169
  }
159
170
 
160
171
  // Send telemetry for every command (only if not crashing immediately)
161
172
  sendTelemetry(command);
162
173
 
163
174
  switch (command) {
164
- case 'dev':
165
- (async () => { await runDev(); })();
175
+ case "dev":
176
+ (async () => {
177
+ await runDev();
178
+ })();
166
179
  break;
167
- case 'start':
168
- (async () => { await runStart(); })();
180
+ case "start":
181
+ (async () => {
182
+ await runStart();
183
+ })();
169
184
  break;
170
- case 'build':
171
- (async () => { await runBuild(); })();
185
+ case "build":
186
+ (async () => {
187
+ await runBuild();
188
+ })();
172
189
  break;
173
- case 'upgrade':
190
+ case "upgrade":
174
191
  (async () => {
175
192
  await upgradeProject();
176
193
  })();
177
194
  break;
178
- case 'make:module':
179
- case 'module':
195
+ case "make:module":
196
+ case "module":
180
197
  const moduleName = args[1];
181
198
  if (!moduleName) {
182
- console.error('❌ Please specify the module name.');
183
- console.error(' Usage: npx lapeeh module <ModuleName>');
184
- process.exit(1);
199
+ console.error("❌ Please specify the module name.");
200
+ console.error(" Usage: npx lapeeh module <ModuleName>");
201
+ process.exit(1);
185
202
  }
186
203
  createModule(moduleName);
187
204
  break;
188
- case 'init':
189
- case 'create':
205
+ case "init":
206
+ case "create":
190
207
  createProject(true);
191
208
  break;
192
209
  default:
@@ -196,58 +213,72 @@ switch (command) {
196
213
 
197
214
  async function checkUpdate() {
198
215
  try {
199
- const pkg = require(path.join(__dirname, '../package.json'));
216
+ const pkg = require(path.join(__dirname, "../package.json"));
200
217
  const currentVersion = pkg.version;
201
-
218
+
202
219
  // Fetch latest version from npm registry
203
220
  const latestVersion = await new Promise((resolve) => {
204
- const https = require('https');
205
- const req = https.get('https://registry.npmjs.org/lapeeh/latest', {
206
- headers: { 'User-Agent': 'lapeeh-CLI' },
207
- timeout: 1500 // 1.5s timeout
208
- }, (res) => {
209
- let data = '';
210
- res.on('data', chunk => data += chunk);
211
- res.on('end', () => {
212
- try {
213
- const json = JSON.parse(data);
214
- resolve(json.version);
215
- } catch (e) {
216
- resolve(null);
217
- }
218
- });
219
- });
220
-
221
- req.on('error', () => resolve(null));
222
- req.on('timeout', () => {
223
- req.destroy();
224
- resolve(null);
225
- });
221
+ const https = require("https");
222
+ const req = https.get(
223
+ "https://registry.npmjs.org/lapeeh/latest",
224
+ {
225
+ headers: { "User-Agent": "lapeeh-CLI" },
226
+ timeout: 1500, // 1.5s timeout
227
+ },
228
+ (res) => {
229
+ let data = "";
230
+ res.on("data", (chunk) => (data += chunk));
231
+ res.on("end", () => {
232
+ try {
233
+ const json = JSON.parse(data);
234
+ resolve(json.version);
235
+ } catch (e) {
236
+ resolve(null);
237
+ }
238
+ });
239
+ }
240
+ );
241
+
242
+ req.on("error", () => resolve(null));
243
+ req.on("timeout", () => {
244
+ req.destroy();
245
+ resolve(null);
246
+ });
226
247
  });
227
248
 
228
249
  if (latestVersion && latestVersion !== currentVersion) {
229
- const currentParts = currentVersion.split('.').map(Number);
230
- const latestParts = latestVersion.split('.').map(Number);
231
-
232
- let isOutdated = false;
233
- for(let i=0; i<3; i++) {
234
- if (latestParts[i] > currentParts[i]) {
235
- isOutdated = true;
236
- break;
237
- } else if (latestParts[i] < currentParts[i]) {
238
- break;
239
- }
240
- }
241
-
242
- if (isOutdated) {
243
- console.log('\n');
244
- console.log('\x1b[33m┌────────────────────────────────────────────────────────────┐\x1b[0m');
245
- console.log(`\x1b[33m│\x1b[0m \x1b[1mUpdate available!\x1b[0m \x1b[31m${currentVersion}\x1b[0m → \x1b[32m${latestVersion}\x1b[0m \x1b[33m│\x1b[0m`);
246
- console.log(`\x1b[33m│\x1b[0m Run \x1b[36mnpm install lapeeh@latest\x1b[0m to update \x1b[33m│\x1b[0m`);
247
- console.log(`\x1b[33m│\x1b[0m Then run \x1b[36mnpx lapeeh upgrade\x1b[0m to sync files \x1b[33m│\x1b[0m`);
248
- console.log('\x1b[33m└────────────────────────────────────────────────────────────┘\x1b[0m');
249
- console.log('\n');
250
+ const currentParts = currentVersion.split(".").map(Number);
251
+ const latestParts = latestVersion.split(".").map(Number);
252
+
253
+ let isOutdated = false;
254
+ for (let i = 0; i < 3; i++) {
255
+ if (latestParts[i] > currentParts[i]) {
256
+ isOutdated = true;
257
+ break;
258
+ } else if (latestParts[i] < currentParts[i]) {
259
+ break;
250
260
  }
261
+ }
262
+
263
+ if (isOutdated) {
264
+ console.log("\n");
265
+ console.log(
266
+ "\x1b[33m┌────────────────────────────────────────────────────────────┐\x1b[0m"
267
+ );
268
+ console.log(
269
+ `\x1b[33m│\x1b[0m \x1b[1mUpdate available!\x1b[0m \x1b[31m${currentVersion}\x1b[0m → \x1b[32m${latestVersion}\x1b[0m \x1b[33m│\x1b[0m`
270
+ );
271
+ console.log(
272
+ `\x1b[33m│\x1b[0m Run \x1b[36mnpm install lapeeh@latest\x1b[0m to update \x1b[33m│\x1b[0m`
273
+ );
274
+ console.log(
275
+ `\x1b[33m│\x1b[0m Then run \x1b[36mnpx lapeeh upgrade\x1b[0m to sync files \x1b[33m│\x1b[0m`
276
+ );
277
+ console.log(
278
+ "\x1b[33m└────────────────────────────────────────────────────────────┘\x1b[0m"
279
+ );
280
+ console.log("\n");
281
+ }
251
282
  }
252
283
  } catch (e) {
253
284
  // Ignore errors during update check
@@ -255,26 +286,36 @@ async function checkUpdate() {
255
286
  }
256
287
 
257
288
  async function runDev() {
258
- console.log('🚀 Starting lapeeh in development mode...');
289
+ console.log("🚀 Starting lapeeh in development mode...");
259
290
  await checkUpdate();
260
291
  try {
261
- const tsNodePath = require.resolve('ts-node/register');
262
- const tsConfigPathsPath = require.resolve('tsconfig-paths/register');
263
-
292
+ const tsNodePath = require.resolve("ts-node/register");
293
+ const tsConfigPathsPath = require.resolve("tsconfig-paths/register");
294
+
264
295
  // Resolve bootstrap file
265
296
  // 1. Try to find it in the current project's node_modules (preferred)
266
- const localBootstrapPath = path.join(process.cwd(), 'node_modules/lapeeh/lib/bootstrap.ts');
267
-
297
+ const localBootstrapPath = path.join(
298
+ process.cwd(),
299
+ "node_modules/lapeeh/lib/bootstrap.ts"
300
+ );
301
+
268
302
  // 2. Fallback to relative to this script (if running from source or global cache without local install)
269
- const fallbackBootstrapPath = path.resolve(__dirname, '../lib/bootstrap.ts');
270
-
271
- const bootstrapPath = fs.existsSync(localBootstrapPath) ? localBootstrapPath : fallbackBootstrapPath;
303
+ const fallbackBootstrapPath = path.resolve(
304
+ __dirname,
305
+ "../lib/bootstrap.ts"
306
+ );
307
+
308
+ const bootstrapPath = fs.existsSync(localBootstrapPath)
309
+ ? localBootstrapPath
310
+ : fallbackBootstrapPath;
272
311
 
273
312
  // We execute a script that requires ts-node to run lib/bootstrap.ts
274
313
  // Use JSON.stringify to properly escape paths for the shell command
275
- const nodeArgs = `-r ${JSON.stringify(tsNodePath)} -r ${JSON.stringify(tsConfigPathsPath)} ${JSON.stringify(bootstrapPath)}`;
276
- const isWin = process.platform === 'win32';
277
-
314
+ const nodeArgs = `-r ${JSON.stringify(tsNodePath)} -r ${JSON.stringify(
315
+ tsConfigPathsPath
316
+ )} ${JSON.stringify(bootstrapPath)}`;
317
+ const isWin = process.platform === "win32";
318
+
278
319
  let cmd;
279
320
  if (isWin) {
280
321
  // On Windows, escape inner quotes
@@ -284,136 +325,158 @@ async function runDev() {
284
325
  // On Linux/Mac, use single quotes for the outer wrapper
285
326
  cmd = `npx nodemon --watch src --watch lib --ext ts,json --exec 'node ${nodeArgs}'`;
286
327
  }
287
-
288
- execSync(cmd, { stdio: 'inherit' });
328
+
329
+ execSync(cmd, { stdio: "inherit" });
289
330
  } catch (error) {
290
331
  // Ignore error
291
332
  }
292
333
  }
293
334
 
294
335
  async function runStart() {
295
- await spin('Starting lapeeh production server...', async () => {
296
- await new Promise(r => setTimeout(r, 1500)); // Simulate startup checks animation
336
+ await spin("Starting lapeeh production server...", async () => {
337
+ await new Promise((r) => setTimeout(r, 1500)); // Simulate startup checks animation
297
338
  });
298
-
339
+
299
340
  let bootstrapPath;
300
341
  try {
301
- const projectNodeModules = path.join(process.cwd(), 'node_modules');
302
- const lapeehDist = path.join(projectNodeModules, 'lapeeh', 'dist', 'lib', 'bootstrap.js');
303
- const lapeehLib = path.join(projectNodeModules, 'lapeeh', 'lib', 'bootstrap.js');
304
-
305
- if (fs.existsSync(lapeehDist)) {
306
- bootstrapPath = lapeehDist;
307
- } else if (fs.existsSync(lapeehLib)) {
308
- bootstrapPath = path.resolve(__dirname, '../lib/bootstrap.js');
309
- if (!fs.existsSync(bootstrapPath)) {
310
- bootstrapPath = path.resolve(__dirname, '../dist/lib/bootstrap.js');
311
- }
312
- }
313
-
314
- const frameworkBootstrap = require('../lib/bootstrap');
315
- frameworkBootstrap.bootstrap();
316
- return;
317
-
318
- } catch (e) {
319
- }
342
+ const projectNodeModules = path.join(process.cwd(), "node_modules");
343
+ const lapeehDist = path.join(
344
+ projectNodeModules,
345
+ "lapeeh",
346
+ "dist",
347
+ "lib",
348
+ "bootstrap.js"
349
+ );
350
+ const lapeehLib = path.join(
351
+ projectNodeModules,
352
+ "lapeeh",
353
+ "lib",
354
+ "bootstrap.js"
355
+ );
356
+
357
+ if (fs.existsSync(lapeehDist)) {
358
+ bootstrapPath = lapeehDist;
359
+ } else if (fs.existsSync(lapeehLib)) {
360
+ bootstrapPath = path.resolve(__dirname, "../lib/bootstrap.js");
361
+ if (!fs.existsSync(bootstrapPath)) {
362
+ bootstrapPath = path.resolve(__dirname, "../dist/lib/bootstrap.js");
363
+ }
364
+ }
365
+
366
+ const frameworkBootstrap = require("../lib/bootstrap");
367
+ frameworkBootstrap.bootstrap();
368
+ return;
369
+ } catch (e) {}
320
370
 
321
371
  const possiblePaths = [
322
- path.join(__dirname, '../lib/bootstrap.js'),
323
- path.join(__dirname, '../dist/lib/bootstrap.js'),
324
- path.join(process.cwd(), 'node_modules/lapeeh/lib/bootstrap.js')
372
+ path.join(__dirname, "../lib/bootstrap.js"),
373
+ path.join(__dirname, "../dist/lib/bootstrap.js"),
374
+ path.join(process.cwd(), "node_modules/lapeeh/lib/bootstrap.js"),
325
375
  ];
326
-
327
- bootstrapPath = possiblePaths.find(p => fs.existsSync(p));
376
+
377
+ bootstrapPath = possiblePaths.find((p) => fs.existsSync(p));
328
378
 
329
379
  if (!bootstrapPath) {
330
- console.error('❌ Could not find lapeeh bootstrap file.');
331
- console.error(' Searched in:', possiblePaths);
332
- process.exit(1);
380
+ console.error("❌ Could not find lapeeh bootstrap file.");
381
+ console.error(" Searched in:", possiblePaths);
382
+ process.exit(1);
333
383
  }
334
384
 
335
385
  let cmd;
336
- if (bootstrapPath.endsWith('.ts')) {
337
- let tsNodePath;
338
- let tsConfigPathsPath;
339
-
386
+ if (bootstrapPath.endsWith(".ts")) {
387
+ let tsNodePath;
388
+ let tsConfigPathsPath;
389
+
390
+ try {
391
+ const projectNodeModules = path.join(process.cwd(), "node_modules");
392
+ tsNodePath = require.resolve("ts-node/register", {
393
+ paths: [projectNodeModules, __dirname],
394
+ });
395
+ tsConfigPathsPath = require.resolve("tsconfig-paths/register", {
396
+ paths: [projectNodeModules, __dirname],
397
+ });
398
+ } catch (e) {
340
399
  try {
341
- const projectNodeModules = path.join(process.cwd(), 'node_modules');
342
- tsNodePath = require.resolve('ts-node/register', { paths: [projectNodeModules, __dirname] });
343
- tsConfigPathsPath = require.resolve('tsconfig-paths/register', { paths: [projectNodeModules, __dirname] });
344
- } catch (e) {
345
- try {
346
- tsNodePath = require.resolve('ts-node/register');
347
- tsConfigPathsPath = require.resolve('tsconfig-paths/register');
348
- } catch (e2) {
349
- console.warn('⚠️ Could not resolve ts-node/register. Trying npx...');
350
- }
351
- }
352
-
353
- if (tsNodePath && tsConfigPathsPath) {
354
- const script = `require(${JSON.stringify(bootstrapPath)}).bootstrap()`;
355
- cmd = `node -r ${JSON.stringify(tsNodePath)} -r ${JSON.stringify(tsConfigPathsPath)} -e ${JSON.stringify(script)}`;
356
- } else {
357
- const script = `require(${JSON.stringify(bootstrapPath)}).bootstrap()`;
358
- cmd = `npx ts-node -r tsconfig-paths/register -e ${JSON.stringify(script)}`;
400
+ tsNodePath = require.resolve("ts-node/register");
401
+ tsConfigPathsPath = require.resolve("tsconfig-paths/register");
402
+ } catch (e2) {
403
+ console.warn("⚠️ Could not resolve ts-node/register. Trying npx...");
359
404
  }
360
- } else {
405
+ }
406
+
407
+ if (tsNodePath && tsConfigPathsPath) {
408
+ const script = `require(${JSON.stringify(bootstrapPath)}).bootstrap()`;
409
+ cmd = `node -r ${JSON.stringify(tsNodePath)} -r ${JSON.stringify(
410
+ tsConfigPathsPath
411
+ )} -e ${JSON.stringify(script)}`;
412
+ } else {
361
413
  const script = `require(${JSON.stringify(bootstrapPath)}).bootstrap()`;
362
- cmd = `node -e ${JSON.stringify(script)}`;
414
+ cmd = `npx ts-node -r tsconfig-paths/register -e ${JSON.stringify(
415
+ script
416
+ )}`;
417
+ }
418
+ } else {
419
+ const script = `require(${JSON.stringify(bootstrapPath)}).bootstrap()`;
420
+ cmd = `node -e ${JSON.stringify(script)}`;
363
421
  }
364
422
 
365
- execSync(cmd, {
366
- stdio: 'inherit',
367
- env: { ...process.env, NODE_ENV: 'production' }
423
+ execSync(cmd, {
424
+ stdio: "inherit",
425
+ env: { ...process.env, NODE_ENV: "production" },
368
426
  });
369
427
  }
370
428
 
371
429
  function runBuild() {
372
- console.log('🛠️ Building lapeeh project...');
373
-
430
+ console.log("🛠️ Building lapeeh project...");
431
+
374
432
  try {
375
- execSync('npx tsc -p tsconfig.build.json && npx tsc-alias -p tsconfig.build.json', { stdio: 'inherit' });
433
+ execSync(
434
+ "npx tsc -p tsconfig.build.json && npx tsc-alias -p tsconfig.build.json",
435
+ { stdio: "inherit" }
436
+ );
376
437
  } catch (e) {
377
- console.error('❌ Build failed.');
378
- process.exit(1);
438
+ console.error("❌ Build failed.");
439
+ process.exit(1);
379
440
  }
380
-
381
- console.log('✅ Build complete.');
441
+
442
+ console.log("✅ Build complete.");
382
443
  }
383
444
 
384
445
  async function upgradeProject() {
385
446
  const currentDir = process.cwd();
386
- const templateDir = path.join(__dirname, '..');
387
-
447
+ const templateDir = path.join(__dirname, "..");
448
+
388
449
  console.log(`🚀 Upgrading lapeeh project in ${currentDir}...`);
389
450
 
390
- const packageJsonPath = path.join(currentDir, 'package.json');
451
+ const packageJsonPath = path.join(currentDir, "package.json");
391
452
  if (!fs.existsSync(packageJsonPath)) {
392
- console.error('❌ No package.json found. Are you in the root of a lapeeh project?');
453
+ console.error(
454
+ "❌ No package.json found. Are you in the root of a lapeeh project?"
455
+ );
393
456
  process.exit(1);
394
457
  }
395
458
 
396
459
  const filesToSync = [
397
- 'lib',
398
- 'docker-compose.yml',
399
- '.env.example',
400
- '.vscode',
401
- 'tsconfig.json',
402
- 'README.md',
403
- 'ecosystem.config.js',
404
- 'src/redis.ts'
460
+ "lib",
461
+ "docker-compose.yml",
462
+ ".env.example",
463
+ ".vscode",
464
+ "tsconfig.json",
465
+ "README.md",
466
+ "ecosystem.config.js",
467
+ "src/redis.ts",
405
468
  ];
406
469
 
407
- const scriptsDir = path.join(currentDir, 'scripts');
470
+ const scriptsDir = path.join(currentDir, "scripts");
408
471
  if (fs.existsSync(scriptsDir)) {
409
- console.log(`🗑️ Removing obsolete directory: ${scriptsDir}`);
410
- fs.rmSync(scriptsDir, { recursive: true, force: true });
472
+ console.log(`🗑️ Removing obsolete directory: ${scriptsDir}`);
473
+ fs.rmSync(scriptsDir, { recursive: true, force: true });
411
474
  }
412
475
 
413
476
  const updateStats = {
414
- updated: [],
415
- created: [],
416
- removed: []
477
+ updated: [],
478
+ created: [],
479
+ removed: [],
417
480
  };
418
481
 
419
482
  function syncDirectory(src, dest, clean = false) {
@@ -433,21 +496,21 @@ async function upgradeProject() {
433
496
  syncDirectory(srcPath, destPath, clean);
434
497
  } else {
435
498
  let shouldCopy = true;
436
-
499
+
437
500
  if (fs.existsSync(destPath)) {
438
- const srcContent = fs.readFileSync(srcPath);
439
- const destContent = fs.readFileSync(destPath);
440
- if (srcContent.equals(destContent)) {
441
- shouldCopy = false;
442
- } else {
443
- updateStats.updated.push(relativePath);
444
- }
501
+ const srcContent = fs.readFileSync(srcPath);
502
+ const destContent = fs.readFileSync(destPath);
503
+ if (srcContent.equals(destContent)) {
504
+ shouldCopy = false;
505
+ } else {
506
+ updateStats.updated.push(relativePath);
507
+ }
445
508
  } else {
446
- updateStats.created.push(relativePath);
509
+ updateStats.created.push(relativePath);
447
510
  }
448
511
 
449
512
  if (shouldCopy) {
450
- fs.copyFileSync(srcPath, destPath);
513
+ fs.copyFileSync(srcPath, destPath);
451
514
  }
452
515
  }
453
516
  }
@@ -456,17 +519,17 @@ async function upgradeProject() {
456
519
  const destEntries = fs.readdirSync(dest, { withFileTypes: true });
457
520
  for (const entry of destEntries) {
458
521
  if (!srcEntryNames.has(entry.name)) {
459
- const destPath = path.join(dest, entry.name);
460
- const relativePath = path.relative(currentDir, destPath);
461
-
462
- console.log(`🗑️ Removing obsolete file/directory: ${destPath}`);
463
- updateStats.removed.push(relativePath);
464
-
465
- if (entry.isDirectory()) {
466
- fs.rmSync(destPath, { recursive: true, force: true });
467
- } else {
468
- fs.unlinkSync(destPath);
469
- }
522
+ const destPath = path.join(dest, entry.name);
523
+ const relativePath = path.relative(currentDir, destPath);
524
+
525
+ console.log(`🗑️ Removing obsolete file/directory: ${destPath}`);
526
+ updateStats.removed.push(relativePath);
527
+
528
+ if (entry.isDirectory()) {
529
+ fs.rmSync(destPath, { recursive: true, force: true });
530
+ } else {
531
+ fs.unlinkSync(destPath);
532
+ }
470
533
  }
471
534
  }
472
535
  }
@@ -476,51 +539,60 @@ async function upgradeProject() {
476
539
  const srcPath = path.join(templateDir, item);
477
540
  const destPath = path.join(currentDir, item);
478
541
  const relativePath = item; // Since item is relative to templateDir/currentDir
479
-
542
+
480
543
  if (fs.existsSync(srcPath)) {
481
544
  const stats = fs.statSync(srcPath);
482
545
  if (stats.isDirectory()) {
483
- console.log(`🔄 Syncing directory ${item}...`);
484
- syncDirectory(srcPath, destPath, item === 'lib');
546
+ console.log(`🔄 Syncing directory ${item}...`);
547
+ syncDirectory(srcPath, destPath, item === "lib");
485
548
  } else {
486
- console.log(`🔄 Checking file ${item}...`);
487
- const destDir = path.dirname(destPath);
488
- if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
489
-
490
- let shouldCopy = true;
491
- if (fs.existsSync(destPath)) {
492
- const srcContent = fs.readFileSync(srcPath);
493
- const destContent = fs.readFileSync(destPath);
494
- if (srcContent.equals(destContent)) {
495
- shouldCopy = false;
496
- } else {
497
- updateStats.updated.push(relativePath);
498
- }
549
+ console.log(`🔄 Checking file ${item}...`);
550
+ const destDir = path.dirname(destPath);
551
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
552
+
553
+ let shouldCopy = true;
554
+ if (fs.existsSync(destPath)) {
555
+ const srcContent = fs.readFileSync(srcPath);
556
+ const destContent = fs.readFileSync(destPath);
557
+ if (srcContent.equals(destContent)) {
558
+ shouldCopy = false;
499
559
  } else {
500
- updateStats.created.push(relativePath);
560
+ updateStats.updated.push(relativePath);
501
561
  }
562
+ } else {
563
+ updateStats.created.push(relativePath);
564
+ }
502
565
 
503
- if (shouldCopy) {
504
- fs.copyFileSync(srcPath, destPath);
505
- }
566
+ if (shouldCopy) {
567
+ fs.copyFileSync(srcPath, destPath);
568
+ }
506
569
  }
507
570
  }
508
571
  }
509
572
 
510
- console.log('📝 Updating package.json...');
573
+ console.log("📝 Updating package.json...");
511
574
  const currentPackageJson = require(packageJsonPath);
512
-
575
+
513
576
  // Capture original dependency before merging
514
- const originallapeehDep = currentPackageJson.dependencies && currentPackageJson.dependencies["lapeeh"];
577
+ const originallapeehDep =
578
+ currentPackageJson.dependencies &&
579
+ currentPackageJson.dependencies["lapeeh"];
515
580
 
516
- const templatePackageJson = require(path.join(templateDir, 'package.json'));
581
+ const templatePackageJson = require(path.join(templateDir, "package.json"));
517
582
 
518
583
  // Define scripts to remove (those that depend on the scripts folder)
519
- const scriptsToRemove = ['first', 'generate:jwt', 'make:module', 'make:modul', 'config:clear', 'release'];
584
+ const scriptsToRemove = [
585
+ "first",
586
+ "generate:jwt",
587
+ "make:module",
588
+ "make:modul",
589
+ "config:clear",
590
+ "release",
591
+ ];
520
592
 
521
593
  // Filter template scripts
522
594
  const filteredTemplateScripts = Object.keys(templatePackageJson.scripts)
523
- .filter(key => !scriptsToRemove.includes(key))
595
+ .filter((key) => !scriptsToRemove.includes(key))
524
596
  .reduce((obj, key) => {
525
597
  obj[key] = templatePackageJson.scripts[key];
526
598
  return obj;
@@ -529,69 +601,78 @@ async function upgradeProject() {
529
601
  currentPackageJson.scripts = {
530
602
  ...currentPackageJson.scripts,
531
603
  ...filteredTemplateScripts,
532
- "dev": "lapeeh dev",
533
- "start": "lapeeh start",
534
- "build": "lapeeh build",
535
- "start:prod": "lapeeh start"
604
+ dev: "lapeeh dev",
605
+ start: "lapeeh start",
606
+ build: "lapeeh build",
607
+ "start:prod": "lapeeh start",
536
608
  };
537
609
 
538
610
  // Clean up existing scripts that we want to remove
539
- scriptsToRemove.forEach(script => {
540
- if (currentPackageJson.scripts[script]) {
541
- delete currentPackageJson.scripts[script];
542
- }
611
+ scriptsToRemove.forEach((script) => {
612
+ if (currentPackageJson.scripts[script]) {
613
+ delete currentPackageJson.scripts[script];
614
+ }
543
615
  });
544
616
 
545
617
  currentPackageJson.dependencies = {
546
618
  ...currentPackageJson.dependencies,
547
- ...templatePackageJson.dependencies
619
+ ...templatePackageJson.dependencies,
548
620
  };
549
-
621
+
550
622
  currentPackageJson.devDependencies = {
551
623
  ...currentPackageJson.devDependencies,
552
- ...templatePackageJson.devDependencies
624
+ ...templatePackageJson.devDependencies,
553
625
  };
554
626
 
555
- const frameworkPackageJson = require(path.join(templateDir, 'package.json'));
556
-
557
- if (originallapeehDep && originallapeehDep.startsWith('file:')) {
558
- console.log(`ℹ️ Preserving local 'lapeeh' dependency: ${originallapeehDep}`);
559
- currentPackageJson.dependencies["lapeeh"] = originallapeehDep;
627
+ const frameworkPackageJson = require(path.join(templateDir, "package.json"));
628
+
629
+ if (originallapeehDep && originallapeehDep.startsWith("file:")) {
630
+ console.log(
631
+ `ℹ️ Preserving local 'lapeeh' dependency: ${originallapeehDep}`
632
+ );
633
+ currentPackageJson.dependencies["lapeeh"] = originallapeehDep;
560
634
  } else {
561
- if (__dirname.includes('node_modules')) {
562
- currentPackageJson.dependencies["lapeeh"] = `^${frameworkPackageJson.version}`;
563
- } else {
564
- const lapeehPath = path.resolve(__dirname, '..').replace(/\\/g, '/');
565
- currentPackageJson.dependencies["lapeeh"] = `file:${lapeehPath}`;
566
- }
635
+ if (__dirname.includes("node_modules")) {
636
+ currentPackageJson.dependencies[
637
+ "lapeeh"
638
+ ] = `^${frameworkPackageJson.version}`;
639
+ } else {
640
+ const lapeehPath = path.resolve(__dirname, "..").replace(/\\/g, "/");
641
+ currentPackageJson.dependencies["lapeeh"] = `file:${lapeehPath}`;
642
+ }
567
643
  }
568
644
 
569
645
  // Ensure prisma config exists for seed
570
646
  if (!currentPackageJson.prisma) {
571
- currentPackageJson.prisma = {
572
- seed: "npx ts-node -r tsconfig-paths/register prisma/seed.ts"
573
- };
647
+ currentPackageJson.prisma = {
648
+ seed: "npx ts-node -r tsconfig-paths/register prisma/seed.ts",
649
+ };
574
650
  }
575
651
 
576
- fs.writeFileSync(packageJsonPath, JSON.stringify(currentPackageJson, null, 2));
652
+ fs.writeFileSync(
653
+ packageJsonPath,
654
+ JSON.stringify(currentPackageJson, null, 2)
655
+ );
577
656
 
578
- console.log('🔧 Configuring tsconfig.json...');
579
- const tsconfigPath = path.join(currentDir, 'tsconfig.json');
657
+ console.log("🔧 Configuring tsconfig.json...");
658
+ const tsconfigPath = path.join(currentDir, "tsconfig.json");
580
659
  if (fs.existsSync(tsconfigPath)) {
581
660
  const tsconfig = require(tsconfigPath);
582
661
  if (tsconfig.compilerOptions && tsconfig.compilerOptions.paths) {
583
- tsconfig.compilerOptions.paths["lapeeh/*"] = ["./node_modules/lapeeh/dist/lib/*"];
662
+ tsconfig.compilerOptions.paths["lapeeh/*"] = [
663
+ "./node_modules/lapeeh/dist/lib/*",
664
+ ];
584
665
  }
585
666
  tsconfig["ts-node"] = {
586
- "ignore": ["node_modules/(?!lapeeh)"]
667
+ ignore: ["node_modules/(?!lapeeh)"],
587
668
  };
588
669
  fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
589
670
  }
590
671
 
591
- console.log('� Configuring jest.config.js...');
592
- const jestConfigPath = path.join(currentDir, 'jest.config.js');
672
+ console.log("� Configuring jest.config.js...");
673
+ const jestConfigPath = path.join(currentDir, "jest.config.js");
593
674
  if (fs.existsSync(jestConfigPath)) {
594
- let jestConfig = fs.readFileSync(jestConfigPath, 'utf8');
675
+ let jestConfig = fs.readFileSync(jestConfigPath, "utf8");
595
676
  jestConfig = jestConfig.replace(
596
677
  /'\^lapeeh\/\(\.\*\)\$': '<rootDir>\/lib\/\$1',/g,
597
678
  `'^lapeeh/(.*)$$': '<rootDir>/node_modules/lapeeh/lib/$$1',`
@@ -603,51 +684,64 @@ async function upgradeProject() {
603
684
  fs.writeFileSync(jestConfigPath, jestConfig);
604
685
  }
605
686
 
606
- console.log('� Installing updated dependencies...');
687
+ console.log("� Installing updated dependencies...");
607
688
  try {
608
- execSync('npm install', { cwd: currentDir, stdio: 'inherit' });
689
+ execSync("npm install", { cwd: currentDir, stdio: "inherit" });
609
690
  } catch (error) {
610
- console.error('❌ Error installing dependencies.');
691
+ console.error("❌ Error installing dependencies.");
611
692
  process.exit(1);
612
693
  }
613
694
 
614
- console.log('\n✅ Upgrade completed successfully!');
615
-
695
+ console.log("\n✅ Upgrade completed successfully!");
696
+
616
697
  if (updateStats.created.length > 0) {
617
- console.log('\n✨ Created files:');
618
- updateStats.created.forEach(f => console.log(` \x1b[32m+ ${f}\x1b[0m`));
698
+ console.log("\n✨ Created files:");
699
+ updateStats.created.forEach((f) => console.log(` \x1b[32m+ ${f}\x1b[0m`));
619
700
  }
620
-
701
+
621
702
  if (updateStats.updated.length > 0) {
622
- console.log('\n📝 Updated files:');
623
- updateStats.updated.forEach(f => console.log(` \x1b[33m~ ${f}\x1b[0m`));
703
+ console.log("\n📝 Updated files:");
704
+ updateStats.updated.forEach((f) => console.log(` \x1b[33m~ ${f}\x1b[0m`));
624
705
  }
625
706
 
626
707
  if (updateStats.removed.length > 0) {
627
- console.log('\n🗑️ Removed files:');
628
- updateStats.removed.forEach(f => console.log(` \x1b[31m- ${f}\x1b[0m`));
708
+ console.log("\n🗑️ Removed files:");
709
+ updateStats.removed.forEach((f) => console.log(` \x1b[31m- ${f}\x1b[0m`));
629
710
  }
630
711
 
631
- if (updateStats.created.length === 0 && updateStats.updated.length === 0 && updateStats.removed.length === 0) {
632
- console.log(' No files were changed.');
712
+ if (
713
+ updateStats.created.length === 0 &&
714
+ updateStats.updated.length === 0 &&
715
+ updateStats.removed.length === 0
716
+ ) {
717
+ console.log(" No files were changed.");
633
718
  }
634
719
 
635
- console.log('\n Please check your .env file against .env.example for any new required variables.');
720
+ console.log(
721
+ "\n Please check your .env file against .env.example for any new required variables."
722
+ );
636
723
  }
637
724
 
638
725
  function createModule(moduleName) {
639
726
  // Capitalize first letter
640
727
  const name = moduleName.charAt(0).toUpperCase() + moduleName.slice(1);
641
728
  const lowerName = moduleName.toLowerCase();
642
-
729
+
643
730
  const currentDir = process.cwd();
644
731
  // Support both src/modules (default) and just modules if user changed structure
645
- const srcModulesDir = path.join(currentDir, 'src', 'modules');
646
- const modulesDir = fs.existsSync(srcModulesDir) ? srcModulesDir : path.join(currentDir, 'modules');
647
-
648
- if (!fs.existsSync(path.join(currentDir, 'src')) && !fs.existsSync(modulesDir)) {
649
- console.error('❌ Could not find src directory. Are you in a lapeeh project root?');
650
- process.exit(1);
732
+ const srcModulesDir = path.join(currentDir, "src", "modules");
733
+ const modulesDir = fs.existsSync(srcModulesDir)
734
+ ? srcModulesDir
735
+ : path.join(currentDir, "modules");
736
+
737
+ if (
738
+ !fs.existsSync(path.join(currentDir, "src")) &&
739
+ !fs.existsSync(modulesDir)
740
+ ) {
741
+ console.error(
742
+ "❌ Could not find src directory. Are you in a lapeeh project root?"
743
+ );
744
+ process.exit(1);
651
745
  }
652
746
 
653
747
  const targetDir = path.join(modulesDir, name);
@@ -661,7 +755,7 @@ function createModule(moduleName) {
661
755
 
662
756
  // Controller
663
757
  const controllerContent = `import { Request, Response } from "express";
664
- import { sendSuccess } from "@lapeeh/utils/response";
758
+ import { sendSuccess } from "lapeeh/utils/response";
665
759
  // import * as ${name}Service from "./${lowerName}.service";
666
760
 
667
761
  export async function index(_req: Request, res: Response) {
@@ -688,7 +782,10 @@ export async function destroy(req: Request, res: Response) {
688
782
  }
689
783
  `;
690
784
 
691
- fs.writeFileSync(path.join(targetDir, `${lowerName}.controller.ts`), controllerContent);
785
+ fs.writeFileSync(
786
+ path.join(targetDir, `${lowerName}.controller.ts`),
787
+ controllerContent
788
+ );
692
789
 
693
790
  // Service
694
791
  const serviceContent = `
@@ -700,7 +797,10 @@ export async function findOne(_id: number) {
700
797
  return null;
701
798
  }
702
799
  `;
703
- fs.writeFileSync(path.join(targetDir, `${lowerName}.service.ts`), serviceContent);
800
+ fs.writeFileSync(
801
+ path.join(targetDir, `${lowerName}.service.ts`),
802
+ serviceContent
803
+ );
704
804
 
705
805
  // Route Stub
706
806
  const routeContent = `import { Router } from "express";
@@ -716,30 +816,38 @@ router.delete("/:id", ${name}Controller.destroy);
716
816
 
717
817
  export default router;
718
818
  `;
719
- fs.writeFileSync(path.join(targetDir, `${lowerName}.routes.ts`), routeContent);
819
+ fs.writeFileSync(
820
+ path.join(targetDir, `${lowerName}.routes.ts`),
821
+ routeContent
822
+ );
720
823
 
721
824
  console.log(`✅ Module ${name} created successfully at src/modules/${name}`);
722
825
  console.log(` - ${lowerName}.controller.ts`);
723
826
  console.log(` - ${lowerName}.service.ts`);
724
827
  console.log(` - ${lowerName}.routes.ts`);
725
- console.log(`\n👉 Don't forget to register the route in src/routes/index.ts!`);
828
+ console.log(
829
+ `\n👉 Don't forget to register the route in src/routes/index.ts!`
830
+ );
726
831
  }
727
832
 
728
833
  function createProject(skipFirstArg = false) {
729
834
  const searchArgs = skipFirstArg ? args.slice(1) : args;
730
- const projectName = searchArgs.find(arg => !arg.startsWith('-'));
731
- const isFull = args.includes('--full');
732
- const useDefaults = args.includes('--defaults') || args.includes('--default') || args.includes('-y');
835
+ const projectName = searchArgs.find((arg) => !arg.startsWith("-"));
836
+ const isFull = args.includes("--full");
837
+ const useDefaults =
838
+ args.includes("--defaults") ||
839
+ args.includes("--default") ||
840
+ args.includes("-y");
733
841
 
734
842
  if (!projectName) {
735
- console.error('❌ Please specify the project name:');
736
- console.error(' npx lapeeh-cli <project-name> [--full] [--defaults|-y]');
843
+ console.error("❌ Please specify the project name:");
844
+ console.error(" npx lapeeh-cli <project-name> [--full] [--defaults|-y]");
737
845
  process.exit(1);
738
846
  }
739
847
 
740
848
  const currentDir = process.cwd();
741
849
  const projectDir = path.join(currentDir, projectName);
742
- const templateDir = path.join(__dirname, '..');
850
+ const templateDir = path.join(__dirname, "..");
743
851
 
744
852
  if (fs.existsSync(projectDir)) {
745
853
  console.error(`❌ Directory ${projectName} already exists.`);
@@ -753,9 +861,12 @@ function createProject(skipFirstArg = false) {
753
861
 
754
862
  const ask = (query, defaultVal) => {
755
863
  return new Promise((resolve) => {
756
- rl.question(`${query} ${defaultVal ? `[${defaultVal}]` : ""}: `, (answer) => {
757
- resolve(answer.trim() || defaultVal);
758
- });
864
+ rl.question(
865
+ `${query} ${defaultVal ? `[${defaultVal}]` : ""}: `,
866
+ (answer) => {
867
+ resolve(answer.trim() || defaultVal);
868
+ }
869
+ );
759
870
  });
760
871
  };
761
872
 
@@ -764,13 +875,17 @@ function createProject(skipFirstArg = false) {
764
875
  options.forEach((opt, idx) => {
765
876
  console.log(` [${opt.key}] ${opt.label}`);
766
877
  });
767
-
878
+
768
879
  while (true) {
769
880
  const answer = await ask(">", options[0].key);
770
- const selected = options.find(o => o.key.toLowerCase() === answer.toLowerCase());
881
+ const selected = options.find(
882
+ (o) => o.key.toLowerCase() === answer.toLowerCase()
883
+ );
771
884
  if (selected) return selected;
772
-
773
- const byLabel = options.find(o => o.label.toLowerCase().includes(answer.toLowerCase()));
885
+
886
+ const byLabel = options.find((o) =>
887
+ o.label.toLowerCase().includes(answer.toLowerCase())
888
+ );
774
889
  if (byLabel) return byLabel;
775
890
 
776
891
  console.log("Pilihan tidak valid. Silakan coba lagi.");
@@ -785,25 +900,39 @@ function createProject(skipFirstArg = false) {
785
900
  "██║ ███████║██████╔╝█████╗ █████╗ ███████║",
786
901
  "██║ ██╔══██║██╔═══╝ ██╔══╝ ██╔══╝ ██╔══██║",
787
902
  "███████╗██║ ██║██║ ███████╗███████╗██║ ██║",
788
- "╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝"
903
+ "╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝",
789
904
  ];
790
905
 
791
906
  console.clear();
792
- console.log('\n');
907
+ console.log("\n");
793
908
  for (let i = 0; i < frames.length; i++) {
794
- await new Promise(r => setTimeout(r, 100));
795
- console.log(`\x1b[36m ${frames[i]}\x1b[0m`);
909
+ await new Promise((r) => setTimeout(r, 100));
910
+ console.log(`\x1b[36m ${frames[i]}\x1b[0m`);
796
911
  }
797
- console.log('\n\x1b[36m L A P E E H F R A M E W O R K\x1b[0m\n');
798
- await new Promise(r => setTimeout(r, 800));
912
+ console.log("\n\x1b[36m L A P E E H F R A M E W O R K\x1b[0m\n");
913
+ await new Promise((r) => setTimeout(r, 800));
799
914
 
800
915
  console.log(`🚀 Creating a new API lapeeh project in ${projectDir}...`);
801
916
  fs.mkdirSync(projectDir);
802
917
 
803
918
  const ignoreList = [
804
- 'node_modules', 'dist', '.git', '.env', 'bin', 'scripts', 'lib',
805
- 'package-lock.json', '.DS_Store', 'prisma', 'website',
806
- 'init', 'test-local-run', 'coverage', 'doc', projectName, 'testing_playground'
919
+ "node_modules",
920
+ "dist",
921
+ ".git",
922
+ ".env",
923
+ "bin",
924
+ "scripts",
925
+ "lib",
926
+ "package-lock.json",
927
+ ".DS_Store",
928
+ "prisma",
929
+ "website",
930
+ "init",
931
+ "test-local-run",
932
+ "coverage",
933
+ "doc",
934
+ projectName,
935
+ "testing_playground",
807
936
  ];
808
937
 
809
938
  function copyDir(src, dest) {
@@ -812,14 +941,17 @@ function createProject(skipFirstArg = false) {
812
941
  if (ignoreList.includes(entry.name)) continue;
813
942
  const srcPath = path.join(src, entry.name);
814
943
  const destPath = path.join(dest, entry.name);
815
-
944
+
816
945
  // Clean storage/logs: skip everything except .gitkeep
817
946
  // Check if we are inside storage/logs
818
947
  const relPath = path.relative(templateDir, srcPath);
819
- const isInLogs = relPath.includes(path.join('storage', 'logs')) || relPath.includes('storage/logs') || relPath.includes('storage\\logs');
820
-
821
- if (isInLogs && !entry.isDirectory() && entry.name !== '.gitkeep') {
822
- continue;
948
+ const isInLogs =
949
+ relPath.includes(path.join("storage", "logs")) ||
950
+ relPath.includes("storage/logs") ||
951
+ relPath.includes("storage\\logs");
952
+
953
+ if (isInLogs && !entry.isDirectory() && entry.name !== ".gitkeep") {
954
+ continue;
823
955
  }
824
956
 
825
957
  if (entry.isDirectory()) {
@@ -831,84 +963,96 @@ function createProject(skipFirstArg = false) {
831
963
  }
832
964
  }
833
965
 
834
- console.log('\n📂 Copying template files...');
966
+ console.log("\n📂 Copying template files...");
835
967
  copyDir(templateDir, projectDir);
836
968
 
837
- const gitignoreTemplate = path.join(projectDir, 'gitignore.template');
969
+ const gitignoreTemplate = path.join(projectDir, "gitignore.template");
838
970
  if (fs.existsSync(gitignoreTemplate)) {
839
- fs.renameSync(gitignoreTemplate, path.join(projectDir, '.gitignore'));
971
+ fs.renameSync(gitignoreTemplate, path.join(projectDir, ".gitignore"));
840
972
  }
841
973
 
842
- console.log('⚙️ Configuring environment...');
843
- const envExamplePath = path.join(projectDir, '.env.example');
844
- const envPath = path.join(projectDir, '.env');
845
-
974
+ console.log("⚙️ Configuring environment...");
975
+ const envExamplePath = path.join(projectDir, ".env.example");
976
+ const envPath = path.join(projectDir, ".env");
977
+
846
978
  if (fs.existsSync(envExamplePath)) {
847
- let envContent = fs.readFileSync(envExamplePath, 'utf8');
979
+ let envContent = fs.readFileSync(envExamplePath, "utf8");
848
980
  fs.writeFileSync(envPath, envContent);
849
981
  }
850
982
 
851
- console.log('📝 Updating package.json...');
852
- const packageJsonPath = path.join(projectDir, 'package.json');
983
+ console.log("📝 Updating package.json...");
984
+ const packageJsonPath = path.join(projectDir, "package.json");
853
985
  const packageJson = require(packageJsonPath);
854
986
  packageJson.name = projectName;
855
-
856
- const frameworkPackageJson = require(path.join(__dirname, '../package.json'));
857
- if (__dirname.includes('node_modules')) {
858
- packageJson.dependencies["lapeeh"] = `^${frameworkPackageJson.version}`;
987
+
988
+ const frameworkPackageJson = require(path.join(
989
+ __dirname,
990
+ "../package.json"
991
+ ));
992
+ if (__dirname.includes("node_modules")) {
993
+ packageJson.dependencies["lapeeh"] = `^${frameworkPackageJson.version}`;
859
994
  } else {
860
- const lapeehPath = path.resolve(__dirname, '..').replace(/\\/g, '/');
861
- packageJson.dependencies["lapeeh"] = `file:${lapeehPath}`;
995
+ const lapeehPath = path.resolve(__dirname, "..").replace(/\\/g, "/");
996
+ packageJson.dependencies["lapeeh"] = `file:${lapeehPath}`;
862
997
  }
863
998
 
864
-
865
- packageJson.version = '1.0.0';
999
+ packageJson.version = "1.0.0";
866
1000
  delete packageJson.bin;
867
1001
  delete packageJson.peerDependencies;
868
-
1002
+
869
1003
  packageJson.scripts = {
870
1004
  ...packageJson.scripts,
871
- "dev": "lapeeh dev",
872
- "start": "lapeeh start",
873
- "build": "lapeeh build",
874
- "start:prod": "lapeeh start"
1005
+ dev: "lapeeh dev",
1006
+ start: "lapeeh start",
1007
+ build: "lapeeh build",
1008
+ "start:prod": "lapeeh start",
875
1009
  };
876
1010
 
877
1011
  // Remove scripts that depend on the scripts folder
878
- const scriptsToRemove = ['first', 'generate:jwt', 'make:module', 'make:modul', 'config:clear', 'release'];
879
- scriptsToRemove.forEach(script => {
880
- delete packageJson.scripts[script];
1012
+ const scriptsToRemove = [
1013
+ "first",
1014
+ "generate:jwt",
1015
+ "make:module",
1016
+ "make:modul",
1017
+ "config:clear",
1018
+ "release",
1019
+ ];
1020
+ scriptsToRemove.forEach((script) => {
1021
+ delete packageJson.scripts[script];
881
1022
  });
882
-
1023
+
883
1024
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
884
1025
 
885
1026
  // Update tsconfig.json for aliases
886
- const tsconfigPath = path.join(projectDir, 'tsconfig.json');
1027
+ const tsconfigPath = path.join(projectDir, "tsconfig.json");
887
1028
  if (fs.existsSync(tsconfigPath)) {
888
1029
  try {
889
1030
  const tsconfig = require(tsconfigPath);
890
1031
  if (!tsconfig.compilerOptions) tsconfig.compilerOptions = {};
891
- if (!tsconfig.compilerOptions.paths) tsconfig.compilerOptions.paths = {};
892
-
1032
+ if (!tsconfig.compilerOptions.paths)
1033
+ tsconfig.compilerOptions.paths = {};
1034
+
893
1035
  // Ensure lapeeh/* points to the installed package
894
- tsconfig.compilerOptions.paths["lapeeh/*"] = ["./node_modules/lapeeh/dist/lib/*"];
895
-
1036
+ tsconfig.compilerOptions.paths["lapeeh/*"] = [
1037
+ "./node_modules/lapeeh/dist/lib/*",
1038
+ ];
1039
+
896
1040
  // Add ts-node configuration to allow compiling lapeeh in node_modules
897
1041
  tsconfig["ts-node"] = {
898
- "ignore": ["node_modules/(?!lapeeh)"]
1042
+ ignore: ["node_modules/(?!lapeeh)"],
899
1043
  };
900
-
1044
+
901
1045
  fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
902
1046
  } catch (e) {
903
- console.warn('⚠️ Failed to update tsconfig.json aliases.');
1047
+ console.warn("⚠️ Failed to update tsconfig.json aliases.");
904
1048
  }
905
1049
  }
906
1050
 
907
1051
  // Update jest.config.js
908
- const jestConfigPath = path.join(projectDir, 'jest.config.js');
1052
+ const jestConfigPath = path.join(projectDir, "jest.config.js");
909
1053
  if (fs.existsSync(jestConfigPath)) {
910
1054
  try {
911
- let jestConfig = fs.readFileSync(jestConfigPath, 'utf8');
1055
+ let jestConfig = fs.readFileSync(jestConfigPath, "utf8");
912
1056
  jestConfig = jestConfig.replace(
913
1057
  /'\^lapeeh\/\(\.\*\)\$': '<rootDir>\/lib\/\$1',/g,
914
1058
  `'^lapeeh/(.*)$$': '<rootDir>/node_modules/lapeeh/lib/$$1',`
@@ -919,45 +1063,48 @@ function createProject(skipFirstArg = false) {
919
1063
  );
920
1064
  fs.writeFileSync(jestConfigPath, jestConfig);
921
1065
  } catch (e) {
922
- console.warn('⚠️ Failed to update jest.config.js.');
1066
+ console.warn("⚠️ Failed to update jest.config.js.");
923
1067
  }
924
1068
  }
925
1069
 
926
1070
  // Removed Prisma base file handling
927
1071
 
928
1072
  try {
929
- await spin('Installing dependencies...', async () => {
930
- await runCommand('npm install', projectDir);
1073
+ await spin("Installing dependencies...", async () => {
1074
+ await runCommand("npm install", projectDir);
931
1075
  });
932
1076
  } catch (e) {
933
- console.error('❌ Error installing dependencies.');
1077
+ console.error("❌ Error installing dependencies.");
934
1078
  console.error(e.message);
935
1079
  process.exit(1);
936
1080
  }
937
1081
 
938
1082
  try {
939
- // Inline JWT Generation Logic
940
- const crypto = require('crypto');
941
- const secret = crypto.randomBytes(64).toString('hex');
942
-
943
- let envContent = '';
944
- if (fs.existsSync(envPath)) {
945
- envContent = fs.readFileSync(envPath, 'utf8');
946
- }
947
-
948
- if (envContent.match(/^JWT_SECRET=/m)) {
949
- envContent = envContent.replace(/^JWT_SECRET=.*/m, `JWT_SECRET="${secret}"`);
950
- } else {
951
- if (envContent && !envContent.endsWith('\n')) {
952
- envContent += '\n';
953
- }
954
- envContent += `JWT_SECRET="${secret}"\n`;
955
- }
956
-
957
- fs.writeFileSync(envPath, envContent);
958
- console.log('✅ JWT Secret generated.');
1083
+ // Inline JWT Generation Logic
1084
+ const crypto = require("crypto");
1085
+ const secret = crypto.randomBytes(64).toString("hex");
1086
+
1087
+ let envContent = "";
1088
+ if (fs.existsSync(envPath)) {
1089
+ envContent = fs.readFileSync(envPath, "utf8");
1090
+ }
1091
+
1092
+ if (envContent.match(/^JWT_SECRET=/m)) {
1093
+ envContent = envContent.replace(
1094
+ /^JWT_SECRET=.*/m,
1095
+ `JWT_SECRET="${secret}"`
1096
+ );
1097
+ } else {
1098
+ if (envContent && !envContent.endsWith("\n")) {
1099
+ envContent += "\n";
1100
+ }
1101
+ envContent += `JWT_SECRET="${secret}"\n`;
1102
+ }
1103
+
1104
+ fs.writeFileSync(envPath, envContent);
1105
+ console.log("✅ JWT Secret generated.");
959
1106
  } catch (e) {
960
- console.warn('⚠️ Failed to generate JWT secret automatically.');
1107
+ console.warn("⚠️ Failed to generate JWT secret automatically.");
961
1108
  }
962
1109
 
963
1110
  // Removed Prisma setup steps
@@ -965,4 +1112,4 @@ function createProject(skipFirstArg = false) {
965
1112
  console.log(`\n✅ Project ${projectName} created successfully!`);
966
1113
  rl.close();
967
1114
  })();
968
- }
1115
+ }