servcraft 0.2.0 → 0.3.1

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/cli/index.js CHANGED
@@ -1,221 +1,17 @@
1
1
  #!/usr/bin/env node
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
2
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
3
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
4
  }) : x)(function(x) {
9
5
  if (typeof require !== "undefined") return require.apply(this, arguments);
10
6
  throw Error('Dynamic require of "' + x + '" is not supported');
11
7
  });
12
- var __esm = (fn, res) => function __init() {
13
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
14
- };
15
- var __export = (target, all) => {
16
- for (var name in all)
17
- __defProp(target, name, { get: all[name], enumerable: true });
18
- };
19
- var __copyProps = (to, from, except, desc) => {
20
- if (from && typeof from === "object" || typeof from === "function") {
21
- for (let key of __getOwnPropNames(from))
22
- if (!__hasOwnProp.call(to, key) && key !== except)
23
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
- }
25
- return to;
26
- };
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
-
29
- // node_modules/tsup/assets/esm_shims.js
30
- import path from "path";
31
- import { fileURLToPath } from "url";
32
- var init_esm_shims = __esm({
33
- "node_modules/tsup/assets/esm_shims.js"() {
34
- "use strict";
35
- }
36
- });
37
-
38
- // src/cli/utils/error-handler.ts
39
- var error_handler_exports = {};
40
- __export(error_handler_exports, {
41
- ErrorTypes: () => ErrorTypes,
42
- ServCraftError: () => ServCraftError,
43
- displayError: () => displayError,
44
- handleSystemError: () => handleSystemError,
45
- validateProject: () => validateProject
46
- });
47
- import chalk4 from "chalk";
48
- function displayError(error2) {
49
- console.error("\n" + chalk4.red.bold("\u2717 Error: ") + chalk4.red(error2.message));
50
- if (error2 instanceof ServCraftError) {
51
- if (error2.suggestions.length > 0) {
52
- console.log("\n" + chalk4.yellow.bold("\u{1F4A1} Suggestions:"));
53
- error2.suggestions.forEach((suggestion) => {
54
- console.log(chalk4.yellow(" \u2022 ") + suggestion);
55
- });
56
- }
57
- if (error2.docsLink) {
58
- console.log("\n" + chalk4.blue.bold("\u{1F4DA} Documentation: ") + chalk4.blue.underline(error2.docsLink));
59
- }
60
- }
61
- console.log();
62
- }
63
- function handleSystemError(err) {
64
- switch (err.code) {
65
- case "ENOENT":
66
- return new ServCraftError(
67
- `File or directory not found: ${err.path}`,
68
- [`Check if the path exists`, `Create the directory first`]
69
- );
70
- case "EACCES":
71
- case "EPERM":
72
- return new ServCraftError(
73
- `Permission denied: ${err.path}`,
74
- [
75
- `Check file permissions`,
76
- `Try running with elevated privileges (not recommended)`,
77
- `Change ownership of the directory`
78
- ]
79
- );
80
- case "EEXIST":
81
- return new ServCraftError(
82
- `File or directory already exists: ${err.path}`,
83
- [`Use a different name`, `Remove the existing file first`, `Use ${chalk4.cyan("--force")} to overwrite`]
84
- );
85
- case "ENOTDIR":
86
- return new ServCraftError(
87
- `Not a directory: ${err.path}`,
88
- [`Check the path`, `A file exists where a directory is expected`]
89
- );
90
- case "EISDIR":
91
- return new ServCraftError(
92
- `Is a directory: ${err.path}`,
93
- [`Cannot perform this operation on a directory`, `Did you mean to target a file?`]
94
- );
95
- default:
96
- return new ServCraftError(
97
- err.message,
98
- [`Check system error code: ${err.code}`, `Review the error details above`]
99
- );
100
- }
101
- }
102
- function validateProject() {
103
- try {
104
- const fs10 = __require("fs");
105
- const path12 = __require("path");
106
- if (!fs10.existsSync("package.json")) {
107
- return ErrorTypes.NOT_IN_PROJECT();
108
- }
109
- const packageJson = JSON.parse(fs10.readFileSync("package.json", "utf-8"));
110
- if (!packageJson.dependencies?.fastify) {
111
- return new ServCraftError(
112
- "This does not appear to be a ServCraft project",
113
- [
114
- `ServCraft projects require Fastify`,
115
- `Run ${chalk4.cyan("servcraft init")} to create a new project`
116
- ]
117
- );
118
- }
119
- return null;
120
- } catch (err) {
121
- return new ServCraftError(
122
- "Failed to validate project",
123
- [`Ensure you are in the project root directory`, `Check if ${chalk4.yellow("package.json")} is valid`]
124
- );
125
- }
126
- }
127
- var ServCraftError, ErrorTypes;
128
- var init_error_handler = __esm({
129
- "src/cli/utils/error-handler.ts"() {
130
- "use strict";
131
- init_esm_shims();
132
- ServCraftError = class extends Error {
133
- suggestions;
134
- docsLink;
135
- constructor(message, suggestions = [], docsLink) {
136
- super(message);
137
- this.name = "ServCraftError";
138
- this.suggestions = suggestions;
139
- this.docsLink = docsLink;
140
- }
141
- };
142
- ErrorTypes = {
143
- MODULE_NOT_FOUND: (moduleName) => new ServCraftError(
144
- `Module "${moduleName}" not found`,
145
- [
146
- `Run ${chalk4.cyan("servcraft list")} to see available modules`,
147
- `Check the spelling of the module name`,
148
- `Visit ${chalk4.blue("https://github.com/Le-Sourcier/servcraft#modules")} for module list`
149
- ],
150
- "https://github.com/Le-Sourcier/servcraft#add-pre-built-modules"
151
- ),
152
- MODULE_ALREADY_EXISTS: (moduleName) => new ServCraftError(
153
- `Module "${moduleName}" already exists`,
154
- [
155
- `Use ${chalk4.cyan("servcraft add " + moduleName + " --force")} to overwrite`,
156
- `Use ${chalk4.cyan("servcraft add " + moduleName + " --update")} to update`,
157
- `Use ${chalk4.cyan("servcraft add " + moduleName + " --skip-existing")} to skip`
158
- ]
159
- ),
160
- NOT_IN_PROJECT: () => new ServCraftError(
161
- "Not in a ServCraft project directory",
162
- [
163
- `Run ${chalk4.cyan("servcraft init")} to create a new project`,
164
- `Navigate to your ServCraft project directory`,
165
- `Check if ${chalk4.yellow("package.json")} exists`
166
- ],
167
- "https://github.com/Le-Sourcier/servcraft#initialize-project"
168
- ),
169
- FILE_ALREADY_EXISTS: (fileName) => new ServCraftError(
170
- `File "${fileName}" already exists`,
171
- [
172
- `Use ${chalk4.cyan("--force")} flag to overwrite`,
173
- `Choose a different name`,
174
- `Delete the existing file first`
175
- ]
176
- ),
177
- INVALID_DATABASE: (database) => new ServCraftError(
178
- `Invalid database type: "${database}"`,
179
- [
180
- `Valid options: ${chalk4.cyan("postgresql, mysql, sqlite, mongodb, none")}`,
181
- `Use ${chalk4.cyan("servcraft init --db postgresql")} for PostgreSQL`
182
- ]
183
- ),
184
- INVALID_VALIDATOR: (validator) => new ServCraftError(
185
- `Invalid validator type: "${validator}"`,
186
- [`Valid options: ${chalk4.cyan("zod, joi, yup")}`, `Default is ${chalk4.cyan("zod")}`]
187
- ),
188
- MISSING_DEPENDENCY: (dependency, command) => new ServCraftError(
189
- `Missing dependency: "${dependency}"`,
190
- [`Run ${chalk4.cyan(command)} to install`, `Check your ${chalk4.yellow("package.json")}`]
191
- ),
192
- INVALID_FIELD_FORMAT: (field) => new ServCraftError(
193
- `Invalid field format: "${field}"`,
194
- [
195
- `Expected format: ${chalk4.cyan("name:type")}`,
196
- `Example: ${chalk4.cyan("name:string age:number isActive:boolean")}`,
197
- `Supported types: string, number, boolean, date`
198
- ]
199
- ),
200
- GIT_NOT_INITIALIZED: () => new ServCraftError(
201
- "Git repository not initialized",
202
- [
203
- `Run ${chalk4.cyan("git init")} to initialize git`,
204
- `This is required for some ServCraft features`
205
- ]
206
- )
207
- };
208
- }
209
- });
210
8
 
211
9
  // src/cli/index.ts
212
- init_esm_shims();
213
- import { Command as Command9 } from "commander";
10
+ import { Command as Command11 } from "commander";
214
11
 
215
12
  // src/cli/commands/init.ts
216
- init_esm_shims();
217
13
  import { Command } from "commander";
218
- import path4 from "path";
14
+ import path3 from "path";
219
15
  import fs2 from "fs/promises";
220
16
  import ora from "ora";
221
17
  import inquirer from "inquirer";
@@ -223,15 +19,13 @@ import chalk3 from "chalk";
223
19
  import { execSync } from "child_process";
224
20
 
225
21
  // src/cli/utils/helpers.ts
226
- init_esm_shims();
227
22
  import fs from "fs/promises";
228
- import path3 from "path";
23
+ import path2 from "path";
229
24
  import chalk2 from "chalk";
230
25
 
231
26
  // src/cli/utils/dry-run.ts
232
- init_esm_shims();
233
27
  import chalk from "chalk";
234
- import path2 from "path";
28
+ import path from "path";
235
29
  var DryRunManager = class _DryRunManager {
236
30
  static instance;
237
31
  enabled = false;
@@ -306,7 +100,7 @@ var DryRunManager = class _DryRunManager {
306
100
  }
307
101
  // Helper to format file path relative to cwd
308
102
  relativePath(filePath) {
309
- return path2.relative(process.cwd(), filePath);
103
+ return path.relative(process.cwd(), filePath);
310
104
  }
311
105
  };
312
106
 
@@ -352,7 +146,7 @@ async function writeFile(filePath, content) {
352
146
  });
353
147
  return;
354
148
  }
355
- await ensureDir(path3.dirname(filePath));
149
+ await ensureDir(path2.dirname(filePath));
356
150
  await fs.writeFile(filePath, content, "utf-8");
357
151
  }
358
152
  function success(message) {
@@ -371,10 +165,10 @@ function getProjectRoot() {
371
165
  return process.cwd();
372
166
  }
373
167
  function getSourceDir() {
374
- return path3.join(getProjectRoot(), "src");
168
+ return path2.join(getProjectRoot(), "src");
375
169
  }
376
170
  function getModulesDir() {
377
- return path3.join(getSourceDir(), "modules");
171
+ return path2.join(getSourceDir(), "modules");
378
172
  }
379
173
 
380
174
  // src/cli/commands/init.ts
@@ -484,7 +278,7 @@ var initCommand = new Command("init").alias("new").description("Initialize a new
484
278
  orm: db === "mongodb" ? "mongoose" : db === "none" ? "none" : "prisma"
485
279
  };
486
280
  }
487
- const projectDir = path4.resolve(process.cwd(), options.name);
281
+ const projectDir = path3.resolve(process.cwd(), options.name);
488
282
  const spinner = ora("Creating project...").start();
489
283
  try {
490
284
  try {
@@ -498,21 +292,21 @@ var initCommand = new Command("init").alias("new").description("Initialize a new
498
292
  spinner.text = "Generating project files...";
499
293
  const packageJson = generatePackageJson(options);
500
294
  await writeFile(
501
- path4.join(projectDir, "package.json"),
295
+ path3.join(projectDir, "package.json"),
502
296
  JSON.stringify(packageJson, null, 2)
503
297
  );
504
298
  if (options.language === "typescript") {
505
- await writeFile(path4.join(projectDir, "tsconfig.json"), generateTsConfig(options));
506
- await writeFile(path4.join(projectDir, "tsup.config.ts"), generateTsupConfig(options));
299
+ await writeFile(path3.join(projectDir, "tsconfig.json"), generateTsConfig(options));
300
+ await writeFile(path3.join(projectDir, "tsup.config.ts"), generateTsupConfig(options));
507
301
  } else {
508
- await writeFile(path4.join(projectDir, "jsconfig.json"), generateJsConfig(options));
302
+ await writeFile(path3.join(projectDir, "jsconfig.json"), generateJsConfig(options));
509
303
  }
510
- await writeFile(path4.join(projectDir, ".env.example"), generateEnvExample(options));
511
- await writeFile(path4.join(projectDir, ".env"), generateEnvExample(options));
512
- await writeFile(path4.join(projectDir, ".gitignore"), generateGitignore());
513
- await writeFile(path4.join(projectDir, "Dockerfile"), generateDockerfile(options));
304
+ await writeFile(path3.join(projectDir, ".env.example"), generateEnvExample(options));
305
+ await writeFile(path3.join(projectDir, ".env"), generateEnvExample(options));
306
+ await writeFile(path3.join(projectDir, ".gitignore"), generateGitignore());
307
+ await writeFile(path3.join(projectDir, "Dockerfile"), generateDockerfile(options));
514
308
  await writeFile(
515
- path4.join(projectDir, "docker-compose.yml"),
309
+ path3.join(projectDir, "docker-compose.yml"),
516
310
  generateDockerCompose(options)
517
311
  );
518
312
  const ext = options.language === "typescript" ? "ts" : options.moduleSystem === "esm" ? "js" : "cjs";
@@ -533,45 +327,45 @@ var initCommand = new Command("init").alias("new").description("Initialize a new
533
327
  dirs.push("src/database/models");
534
328
  }
535
329
  for (const dir of dirs) {
536
- await ensureDir(path4.join(projectDir, dir));
330
+ await ensureDir(path3.join(projectDir, dir));
537
331
  }
538
- await writeFile(path4.join(projectDir, `src/index.${ext}`), generateEntryFile(options));
332
+ await writeFile(path3.join(projectDir, `src/index.${ext}`), generateEntryFile(options));
539
333
  await writeFile(
540
- path4.join(projectDir, `src/core/server.${ext}`),
334
+ path3.join(projectDir, `src/core/server.${ext}`),
541
335
  generateServerFile(options)
542
336
  );
543
337
  await writeFile(
544
- path4.join(projectDir, `src/core/logger.${ext}`),
338
+ path3.join(projectDir, `src/core/logger.${ext}`),
545
339
  generateLoggerFile(options)
546
340
  );
547
341
  await writeFile(
548
- path4.join(projectDir, `src/config/index.${ext}`),
342
+ path3.join(projectDir, `src/config/index.${ext}`),
549
343
  generateConfigFile(options)
550
344
  );
551
345
  await writeFile(
552
- path4.join(projectDir, `src/middleware/index.${ext}`),
346
+ path3.join(projectDir, `src/middleware/index.${ext}`),
553
347
  generateMiddlewareFile(options)
554
348
  );
555
349
  await writeFile(
556
- path4.join(projectDir, `src/utils/index.${ext}`),
350
+ path3.join(projectDir, `src/utils/index.${ext}`),
557
351
  generateUtilsFile(options)
558
352
  );
559
353
  await writeFile(
560
- path4.join(projectDir, `src/types/index.${ext}`),
354
+ path3.join(projectDir, `src/types/index.${ext}`),
561
355
  generateTypesFile(options)
562
356
  );
563
357
  if (options.orm === "prisma") {
564
358
  await writeFile(
565
- path4.join(projectDir, "prisma/schema.prisma"),
359
+ path3.join(projectDir, "prisma/schema.prisma"),
566
360
  generatePrismaSchema(options)
567
361
  );
568
362
  } else if (options.orm === "mongoose") {
569
363
  await writeFile(
570
- path4.join(projectDir, `src/database/connection.${ext}`),
364
+ path3.join(projectDir, `src/database/connection.${ext}`),
571
365
  generateMongooseConnection(options)
572
366
  );
573
367
  await writeFile(
574
- path4.join(projectDir, `src/database/models/user.model.${ext}`),
368
+ path3.join(projectDir, `src/database/models/user.model.${ext}`),
575
369
  generateMongooseUserModel(options)
576
370
  );
577
371
  }
@@ -1410,15 +1204,13 @@ declare module 'fastify' {
1410
1204
  }
1411
1205
 
1412
1206
  // src/cli/commands/generate.ts
1413
- init_esm_shims();
1414
1207
  import { Command as Command2 } from "commander";
1415
- import path5 from "path";
1208
+ import path4 from "path";
1416
1209
  import ora2 from "ora";
1417
1210
  import inquirer2 from "inquirer";
1418
1211
  import chalk5 from "chalk";
1419
1212
 
1420
1213
  // src/cli/utils/field-parser.ts
1421
- init_esm_shims();
1422
1214
  var tsTypeMap = {
1423
1215
  string: "string",
1424
1216
  number: "number",
@@ -1560,11 +1352,109 @@ function parseFields(fieldsStr) {
1560
1352
  return fieldsStr.split(/\s+/).filter(Boolean).map(parseField);
1561
1353
  }
1562
1354
 
1563
- // src/cli/commands/generate.ts
1564
- init_error_handler();
1355
+ // src/cli/utils/error-handler.ts
1356
+ import chalk4 from "chalk";
1357
+ var ServCraftError = class extends Error {
1358
+ suggestions;
1359
+ docsLink;
1360
+ constructor(message, suggestions = [], docsLink) {
1361
+ super(message);
1362
+ this.name = "ServCraftError";
1363
+ this.suggestions = suggestions;
1364
+ this.docsLink = docsLink;
1365
+ }
1366
+ };
1367
+ var ErrorTypes = {
1368
+ MODULE_NOT_FOUND: (moduleName) => new ServCraftError(
1369
+ `Module "${moduleName}" not found`,
1370
+ [
1371
+ `Run ${chalk4.cyan("servcraft list")} to see available modules`,
1372
+ `Check the spelling of the module name`,
1373
+ `Visit ${chalk4.blue("https://github.com/Le-Sourcier/servcraft#modules")} for module list`
1374
+ ],
1375
+ "https://github.com/Le-Sourcier/servcraft#add-pre-built-modules"
1376
+ ),
1377
+ MODULE_ALREADY_EXISTS: (moduleName) => new ServCraftError(`Module "${moduleName}" already exists`, [
1378
+ `Use ${chalk4.cyan("servcraft add " + moduleName + " --force")} to overwrite`,
1379
+ `Use ${chalk4.cyan("servcraft add " + moduleName + " --update")} to update`,
1380
+ `Use ${chalk4.cyan("servcraft add " + moduleName + " --skip-existing")} to skip`
1381
+ ]),
1382
+ NOT_IN_PROJECT: () => new ServCraftError(
1383
+ "Not in a ServCraft project directory",
1384
+ [
1385
+ `Run ${chalk4.cyan("servcraft init")} to create a new project`,
1386
+ `Navigate to your ServCraft project directory`,
1387
+ `Check if ${chalk4.yellow("package.json")} exists`
1388
+ ],
1389
+ "https://github.com/Le-Sourcier/servcraft#initialize-project"
1390
+ ),
1391
+ FILE_ALREADY_EXISTS: (fileName) => new ServCraftError(`File "${fileName}" already exists`, [
1392
+ `Use ${chalk4.cyan("--force")} flag to overwrite`,
1393
+ `Choose a different name`,
1394
+ `Delete the existing file first`
1395
+ ]),
1396
+ INVALID_DATABASE: (database) => new ServCraftError(`Invalid database type: "${database}"`, [
1397
+ `Valid options: ${chalk4.cyan("postgresql, mysql, sqlite, mongodb, none")}`,
1398
+ `Use ${chalk4.cyan("servcraft init --db postgresql")} for PostgreSQL`
1399
+ ]),
1400
+ INVALID_VALIDATOR: (validator) => new ServCraftError(`Invalid validator type: "${validator}"`, [
1401
+ `Valid options: ${chalk4.cyan("zod, joi, yup")}`,
1402
+ `Default is ${chalk4.cyan("zod")}`
1403
+ ]),
1404
+ MISSING_DEPENDENCY: (dependency, command) => new ServCraftError(`Missing dependency: "${dependency}"`, [
1405
+ `Run ${chalk4.cyan(command)} to install`,
1406
+ `Check your ${chalk4.yellow("package.json")}`
1407
+ ]),
1408
+ INVALID_FIELD_FORMAT: (field) => new ServCraftError(`Invalid field format: "${field}"`, [
1409
+ `Expected format: ${chalk4.cyan("name:type")}`,
1410
+ `Example: ${chalk4.cyan("name:string age:number isActive:boolean")}`,
1411
+ `Supported types: string, number, boolean, date`
1412
+ ]),
1413
+ GIT_NOT_INITIALIZED: () => new ServCraftError("Git repository not initialized", [
1414
+ `Run ${chalk4.cyan("git init")} to initialize git`,
1415
+ `This is required for some ServCraft features`
1416
+ ])
1417
+ };
1418
+ function displayError(error2) {
1419
+ console.error("\n" + chalk4.red.bold("\u2717 Error: ") + chalk4.red(error2.message));
1420
+ if (error2 instanceof ServCraftError) {
1421
+ if (error2.suggestions.length > 0) {
1422
+ console.log("\n" + chalk4.yellow.bold("\u{1F4A1} Suggestions:"));
1423
+ error2.suggestions.forEach((suggestion) => {
1424
+ console.log(chalk4.yellow(" \u2022 ") + suggestion);
1425
+ });
1426
+ }
1427
+ if (error2.docsLink) {
1428
+ console.log(
1429
+ "\n" + chalk4.blue.bold("\u{1F4DA} Documentation: ") + chalk4.blue.underline(error2.docsLink)
1430
+ );
1431
+ }
1432
+ }
1433
+ console.log();
1434
+ }
1435
+ function validateProject() {
1436
+ try {
1437
+ const fs12 = __require("fs");
1438
+ if (!fs12.existsSync("package.json")) {
1439
+ return ErrorTypes.NOT_IN_PROJECT();
1440
+ }
1441
+ const packageJson = JSON.parse(fs12.readFileSync("package.json", "utf-8"));
1442
+ if (!packageJson.dependencies?.fastify) {
1443
+ return new ServCraftError("This does not appear to be a ServCraft project", [
1444
+ `ServCraft projects require Fastify`,
1445
+ `Run ${chalk4.cyan("servcraft init")} to create a new project`
1446
+ ]);
1447
+ }
1448
+ return null;
1449
+ } catch {
1450
+ return new ServCraftError("Failed to validate project", [
1451
+ `Ensure you are in the project root directory`,
1452
+ `Check if ${chalk4.yellow("package.json")} is valid`
1453
+ ]);
1454
+ }
1455
+ }
1565
1456
 
1566
1457
  // src/cli/templates/controller.ts
1567
- init_esm_shims();
1568
1458
  function controllerTemplate(name, pascalName, camelName) {
1569
1459
  return `import type { FastifyRequest, FastifyReply } from 'fastify';
1570
1460
  import type { ${pascalName}Service } from './${name}.service.js';
@@ -1634,7 +1524,6 @@ export function create${pascalName}Controller(${camelName}Service: ${pascalName}
1634
1524
  }
1635
1525
 
1636
1526
  // src/cli/templates/service.ts
1637
- init_esm_shims();
1638
1527
  function serviceTemplate(name, pascalName, camelName) {
1639
1528
  return `import type { PaginatedResult, PaginationParams } from '../../types/index.js';
1640
1529
  import { NotFoundError, ConflictError } from '../../utils/errors.js';
@@ -1695,7 +1584,6 @@ export function create${pascalName}Service(repository?: ${pascalName}Repository)
1695
1584
  }
1696
1585
 
1697
1586
  // src/cli/templates/repository.ts
1698
- init_esm_shims();
1699
1587
  function repositoryTemplate(name, pascalName, camelName, pluralName) {
1700
1588
  return `import { randomUUID } from 'crypto';
1701
1589
  import type { PaginatedResult, PaginationParams } from '../../types/index.js';
@@ -1802,7 +1690,6 @@ export function create${pascalName}Repository(): ${pascalName}Repository {
1802
1690
  }
1803
1691
 
1804
1692
  // src/cli/templates/types.ts
1805
- init_esm_shims();
1806
1693
  function typesTemplate(name, pascalName) {
1807
1694
  return `import type { BaseEntity } from '../../types/index.js';
1808
1695
 
@@ -1832,7 +1719,6 @@ export interface ${pascalName}Filters {
1832
1719
  }
1833
1720
 
1834
1721
  // src/cli/templates/schemas.ts
1835
- init_esm_shims();
1836
1722
  function schemasTemplate(name, pascalName, camelName) {
1837
1723
  return `import { z } from 'zod';
1838
1724
 
@@ -1861,7 +1747,6 @@ export type ${pascalName}QueryInput = z.infer<typeof ${camelName}QuerySchema>;
1861
1747
  }
1862
1748
 
1863
1749
  // src/cli/templates/routes.ts
1864
- init_esm_shims();
1865
1750
  function routesTemplate(name, pascalName, camelName, pluralName) {
1866
1751
  return `import type { FastifyInstance } from 'fastify';
1867
1752
  import type { ${pascalName}Controller } from './${name}.controller.js';
@@ -1914,7 +1799,6 @@ export function register${pascalName}Routes(
1914
1799
  }
1915
1800
 
1916
1801
  // src/cli/templates/module-index.ts
1917
- init_esm_shims();
1918
1802
  function moduleIndexTemplate(name, pascalName, camelName) {
1919
1803
  return `import type { FastifyInstance } from 'fastify';
1920
1804
  import { logger } from '../../core/logger.js';
@@ -1950,7 +1834,6 @@ export * from './${name}.schemas.js';
1950
1834
  }
1951
1835
 
1952
1836
  // src/cli/templates/prisma-model.ts
1953
- init_esm_shims();
1954
1837
  function prismaModelTemplate(name, pascalName, tableName) {
1955
1838
  return `
1956
1839
  // Add this model to your prisma/schema.prisma file
@@ -1970,7 +1853,6 @@ model ${pascalName} {
1970
1853
  }
1971
1854
 
1972
1855
  // src/cli/templates/dynamic-types.ts
1973
- init_esm_shims();
1974
1856
  function dynamicTypesTemplate(name, pascalName, fields) {
1975
1857
  const fieldLines = fields.map((field) => {
1976
1858
  const tsType = tsTypeMap[field.type];
@@ -2015,7 +1897,6 @@ ${fields.filter((f) => ["string", "enum", "boolean"].includes(f.type)).map((f) =
2015
1897
  }
2016
1898
 
2017
1899
  // src/cli/templates/dynamic-schemas.ts
2018
- init_esm_shims();
2019
1900
  function dynamicSchemasTemplate(name, pascalName, camelName, fields, validator = "zod") {
2020
1901
  switch (validator) {
2021
1902
  case "joi":
@@ -2194,7 +2075,6 @@ function getJsType(field) {
2194
2075
  }
2195
2076
 
2196
2077
  // src/cli/templates/dynamic-prisma.ts
2197
- init_esm_shims();
2198
2078
  function dynamicPrismaTemplate(modelName, tableName, fields) {
2199
2079
  const fieldLines = [];
2200
2080
  for (const field of fields) {
@@ -2262,6 +2142,353 @@ ${indexLines.join("\n")}
2262
2142
  `;
2263
2143
  }
2264
2144
 
2145
+ // src/cli/templates/controller-test.ts
2146
+ function controllerTestTemplate(name, pascalName, camelName) {
2147
+ return `import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2148
+ import { build } from '../../app.js';
2149
+ import { FastifyInstance } from 'fastify';
2150
+
2151
+ describe('${pascalName}Controller', () => {
2152
+ let app: FastifyInstance;
2153
+
2154
+ beforeAll(async () => {
2155
+ app = await build();
2156
+ await app.ready();
2157
+ });
2158
+
2159
+ afterAll(async () => {
2160
+ await app.close();
2161
+ });
2162
+
2163
+ describe('GET /${name}', () => {
2164
+ it('should return list of ${name}', async () => {
2165
+ const response = await app.inject({
2166
+ method: 'GET',
2167
+ url: '/${name}',
2168
+ });
2169
+
2170
+ expect(response.statusCode).toBe(200);
2171
+ expect(response.json()).toHaveProperty('data');
2172
+ });
2173
+ });
2174
+
2175
+ describe('GET /${name}/:id', () => {
2176
+ it('should return a single ${camelName}', async () => {
2177
+ // TODO: Create test ${camelName} first
2178
+ const response = await app.inject({
2179
+ method: 'GET',
2180
+ url: '/${name}/1',
2181
+ });
2182
+
2183
+ expect(response.statusCode).toBe(200);
2184
+ expect(response.json()).toHaveProperty('data');
2185
+ });
2186
+
2187
+ it('should return 404 for non-existent ${camelName}', async () => {
2188
+ const response = await app.inject({
2189
+ method: 'GET',
2190
+ url: '/${name}/999999',
2191
+ });
2192
+
2193
+ expect(response.statusCode).toBe(404);
2194
+ });
2195
+ });
2196
+
2197
+ describe('POST /${name}', () => {
2198
+ it('should create a new ${camelName}', async () => {
2199
+ const response = await app.inject({
2200
+ method: 'POST',
2201
+ url: '/${name}',
2202
+ payload: {
2203
+ // TODO: Add required fields
2204
+ },
2205
+ });
2206
+
2207
+ expect(response.statusCode).toBe(201);
2208
+ expect(response.json()).toHaveProperty('data');
2209
+ });
2210
+
2211
+ it('should return 400 for invalid data', async () => {
2212
+ const response = await app.inject({
2213
+ method: 'POST',
2214
+ url: '/${name}',
2215
+ payload: {},
2216
+ });
2217
+
2218
+ expect(response.statusCode).toBe(400);
2219
+ });
2220
+ });
2221
+
2222
+ describe('PUT /${name}/:id', () => {
2223
+ it('should update a ${camelName}', async () => {
2224
+ // TODO: Create test ${camelName} first
2225
+ const response = await app.inject({
2226
+ method: 'PUT',
2227
+ url: '/${name}/1',
2228
+ payload: {
2229
+ // TODO: Add fields to update
2230
+ },
2231
+ });
2232
+
2233
+ expect(response.statusCode).toBe(200);
2234
+ expect(response.json()).toHaveProperty('data');
2235
+ });
2236
+ });
2237
+
2238
+ describe('DELETE /${name}/:id', () => {
2239
+ it('should delete a ${camelName}', async () => {
2240
+ // TODO: Create test ${camelName} first
2241
+ const response = await app.inject({
2242
+ method: 'DELETE',
2243
+ url: '/${name}/1',
2244
+ });
2245
+
2246
+ expect(response.statusCode).toBe(204);
2247
+ });
2248
+ });
2249
+ });
2250
+ `;
2251
+ }
2252
+
2253
+ // src/cli/templates/service-test.ts
2254
+ function serviceTestTemplate(name, pascalName, camelName) {
2255
+ return `import { describe, it, expect, beforeEach } from 'vitest';
2256
+ import { ${pascalName}Service } from '../${name}.service.js';
2257
+
2258
+ describe('${pascalName}Service', () => {
2259
+ let service: ${pascalName}Service;
2260
+
2261
+ beforeEach(() => {
2262
+ service = new ${pascalName}Service();
2263
+ });
2264
+
2265
+ describe('getAll', () => {
2266
+ it('should return all ${name}', async () => {
2267
+ const result = await service.getAll();
2268
+
2269
+ expect(result).toBeDefined();
2270
+ expect(Array.isArray(result)).toBe(true);
2271
+ });
2272
+
2273
+ it('should apply pagination', async () => {
2274
+ const result = await service.getAll({ page: 1, limit: 10 });
2275
+
2276
+ expect(result).toBeDefined();
2277
+ expect(result.length).toBeLessThanOrEqual(10);
2278
+ });
2279
+ });
2280
+
2281
+ describe('getById', () => {
2282
+ it('should return a ${camelName} by id', async () => {
2283
+ // TODO: Create test ${camelName} first
2284
+ const id = '1';
2285
+ const result = await service.getById(id);
2286
+
2287
+ expect(result).toBeDefined();
2288
+ expect(result.id).toBe(id);
2289
+ });
2290
+
2291
+ it('should return null for non-existent id', async () => {
2292
+ const result = await service.getById('999999');
2293
+
2294
+ expect(result).toBeNull();
2295
+ });
2296
+ });
2297
+
2298
+ describe('create', () => {
2299
+ it('should create a new ${camelName}', async () => {
2300
+ const data = {
2301
+ // TODO: Add required fields
2302
+ };
2303
+
2304
+ const result = await service.create(data);
2305
+
2306
+ expect(result).toBeDefined();
2307
+ expect(result.id).toBeDefined();
2308
+ });
2309
+
2310
+ it('should throw error for invalid data', async () => {
2311
+ await expect(service.create({} as any)).rejects.toThrow();
2312
+ });
2313
+ });
2314
+
2315
+ describe('update', () => {
2316
+ it('should update a ${camelName}', async () => {
2317
+ // TODO: Create test ${camelName} first
2318
+ const id = '1';
2319
+ const updates = {
2320
+ // TODO: Add fields to update
2321
+ };
2322
+
2323
+ const result = await service.update(id, updates);
2324
+
2325
+ expect(result).toBeDefined();
2326
+ expect(result.id).toBe(id);
2327
+ });
2328
+
2329
+ it('should return null for non-existent id', async () => {
2330
+ const result = await service.update('999999', {});
2331
+
2332
+ expect(result).toBeNull();
2333
+ });
2334
+ });
2335
+
2336
+ describe('delete', () => {
2337
+ it('should delete a ${camelName}', async () => {
2338
+ // TODO: Create test ${camelName} first
2339
+ const id = '1';
2340
+ const result = await service.delete(id);
2341
+
2342
+ expect(result).toBe(true);
2343
+ });
2344
+
2345
+ it('should return false for non-existent id', async () => {
2346
+ const result = await service.delete('999999');
2347
+
2348
+ expect(result).toBe(false);
2349
+ });
2350
+ });
2351
+ });
2352
+ `;
2353
+ }
2354
+
2355
+ // src/cli/templates/integration-test.ts
2356
+ function integrationTestTemplate(name, pascalName, camelName) {
2357
+ return `import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
2358
+ import { build } from '../../app.js';
2359
+ import { FastifyInstance } from 'fastify';
2360
+ import { prisma } from '../../lib/prisma.js';
2361
+
2362
+ describe('${pascalName} Integration Tests', () => {
2363
+ let app: FastifyInstance;
2364
+
2365
+ beforeAll(async () => {
2366
+ app = await build();
2367
+ await app.ready();
2368
+ });
2369
+
2370
+ afterAll(async () => {
2371
+ await app.close();
2372
+ await prisma.$disconnect();
2373
+ });
2374
+
2375
+ beforeEach(async () => {
2376
+ // Clean up test data
2377
+ // await prisma.${camelName}.deleteMany();
2378
+ });
2379
+
2380
+ describe('Full CRUD workflow', () => {
2381
+ it('should create, read, update, and delete a ${camelName}', async () => {
2382
+ // Create
2383
+ const createResponse = await app.inject({
2384
+ method: 'POST',
2385
+ url: '/${name}',
2386
+ payload: {
2387
+ // TODO: Add required fields
2388
+ },
2389
+ });
2390
+
2391
+ expect(createResponse.statusCode).toBe(201);
2392
+ const created = createResponse.json().data;
2393
+ expect(created.id).toBeDefined();
2394
+
2395
+ // Read
2396
+ const readResponse = await app.inject({
2397
+ method: 'GET',
2398
+ url: \`/${name}/\${created.id}\`,
2399
+ });
2400
+
2401
+ expect(readResponse.statusCode).toBe(200);
2402
+ const read = readResponse.json().data;
2403
+ expect(read.id).toBe(created.id);
2404
+
2405
+ // Update
2406
+ const updateResponse = await app.inject({
2407
+ method: 'PUT',
2408
+ url: \`/${name}/\${created.id}\`,
2409
+ payload: {
2410
+ // TODO: Add fields to update
2411
+ },
2412
+ });
2413
+
2414
+ expect(updateResponse.statusCode).toBe(200);
2415
+ const updated = updateResponse.json().data;
2416
+ expect(updated.id).toBe(created.id);
2417
+
2418
+ // Delete
2419
+ const deleteResponse = await app.inject({
2420
+ method: 'DELETE',
2421
+ url: \`/${name}/\${created.id}\`,
2422
+ });
2423
+
2424
+ expect(deleteResponse.statusCode).toBe(204);
2425
+
2426
+ // Verify deletion
2427
+ const verifyResponse = await app.inject({
2428
+ method: 'GET',
2429
+ url: \`/${name}/\${created.id}\`,
2430
+ });
2431
+
2432
+ expect(verifyResponse.statusCode).toBe(404);
2433
+ });
2434
+ });
2435
+
2436
+ describe('List and pagination', () => {
2437
+ it('should list ${name} with pagination', async () => {
2438
+ // Create multiple ${name}
2439
+ const count = 5;
2440
+ for (let i = 0; i < count; i++) {
2441
+ await app.inject({
2442
+ method: 'POST',
2443
+ url: '/${name}',
2444
+ payload: {
2445
+ // TODO: Add required fields
2446
+ },
2447
+ });
2448
+ }
2449
+
2450
+ // Test pagination
2451
+ const response = await app.inject({
2452
+ method: 'GET',
2453
+ url: '/${name}?page=1&limit=3',
2454
+ });
2455
+
2456
+ expect(response.statusCode).toBe(200);
2457
+ const result = response.json();
2458
+ expect(result.data).toBeDefined();
2459
+ expect(result.data.length).toBeLessThanOrEqual(3);
2460
+ expect(result.total).toBeGreaterThanOrEqual(count);
2461
+ });
2462
+ });
2463
+
2464
+ describe('Validation', () => {
2465
+ it('should validate required fields on create', async () => {
2466
+ const response = await app.inject({
2467
+ method: 'POST',
2468
+ url: '/${name}',
2469
+ payload: {},
2470
+ });
2471
+
2472
+ expect(response.statusCode).toBe(400);
2473
+ expect(response.json()).toHaveProperty('error');
2474
+ });
2475
+
2476
+ it('should validate data types', async () => {
2477
+ const response = await app.inject({
2478
+ method: 'POST',
2479
+ url: '/${name}',
2480
+ payload: {
2481
+ // TODO: Add invalid field types
2482
+ },
2483
+ });
2484
+
2485
+ expect(response.statusCode).toBe(400);
2486
+ });
2487
+ });
2488
+ });
2489
+ `;
2490
+ }
2491
+
2265
2492
  // src/cli/commands/generate.ts
2266
2493
  function enableDryRunIfNeeded(options) {
2267
2494
  const dryRun = DryRunManager.getInstance();
@@ -2278,7 +2505,7 @@ function showDryRunSummary(options) {
2278
2505
  var generateCommand = new Command2("generate").alias("g").description("Generate resources (module, controller, service, etc.)");
2279
2506
  generateCommand.command("module <name> [fields...]").alias("m").description(
2280
2507
  "Generate a complete module with controller, service, repository, types, schemas, and routes"
2281
- ).option("--no-routes", "Skip routes generation").option("--no-repository", "Skip repository generation").option("--prisma", "Generate Prisma model suggestion").option("--validator <type>", "Validator type: zod, joi, yup", "zod").option("-i, --interactive", "Interactive mode to define fields").option("--dry-run", "Preview changes without writing files").action(async (name, fieldsArgs, options) => {
2508
+ ).option("--no-routes", "Skip routes generation").option("--no-repository", "Skip repository generation").option("--prisma", "Generate Prisma model suggestion").option("--validator <type>", "Validator type: zod, joi, yup", "zod").option("-i, --interactive", "Interactive mode to define fields").option("--with-tests", "Generate test files (__tests__ directory)").option("--dry-run", "Preview changes without writing files").action(async (name, fieldsArgs, options) => {
2282
2509
  enableDryRunIfNeeded(options);
2283
2510
  let fields = [];
2284
2511
  if (options.interactive) {
@@ -2294,7 +2521,7 @@ generateCommand.command("module <name> [fields...]").alias("m").description(
2294
2521
  const pluralName = pluralize(kebabName);
2295
2522
  const tableName = pluralize(kebabName.replace(/-/g, "_"));
2296
2523
  const validatorType = options.validator || "zod";
2297
- const moduleDir = path5.join(getModulesDir(), kebabName);
2524
+ const moduleDir = path4.join(getModulesDir(), kebabName);
2298
2525
  if (await fileExists(moduleDir)) {
2299
2526
  spinner.stop();
2300
2527
  error(`Module "${kebabName}" already exists`);
@@ -2333,7 +2560,22 @@ generateCommand.command("module <name> [fields...]").alias("m").description(
2333
2560
  });
2334
2561
  }
2335
2562
  for (const file of files) {
2336
- await writeFile(path5.join(moduleDir, file.name), file.content);
2563
+ await writeFile(path4.join(moduleDir, file.name), file.content);
2564
+ }
2565
+ if (options.withTests) {
2566
+ const testDir = path4.join(moduleDir, "__tests__");
2567
+ await writeFile(
2568
+ path4.join(testDir, `${kebabName}.controller.test.ts`),
2569
+ controllerTestTemplate(kebabName, pascalName, camelName)
2570
+ );
2571
+ await writeFile(
2572
+ path4.join(testDir, `${kebabName}.service.test.ts`),
2573
+ serviceTestTemplate(kebabName, pascalName, camelName)
2574
+ );
2575
+ await writeFile(
2576
+ path4.join(testDir, `${kebabName}.integration.test.ts`),
2577
+ integrationTestTemplate(kebabName, pascalName, camelName)
2578
+ );
2337
2579
  }
2338
2580
  spinner.succeed(`Module "${pascalName}" generated successfully!`);
2339
2581
  if (options.prisma || hasFields) {
@@ -2358,6 +2600,11 @@ generateCommand.command("module <name> [fields...]").alias("m").description(
2358
2600
  }
2359
2601
  console.log("\n\u{1F4C1} Files created:");
2360
2602
  files.forEach((f) => success(` src/modules/${kebabName}/${f.name}`));
2603
+ if (options.withTests) {
2604
+ success(` src/modules/${kebabName}/__tests__/${kebabName}.controller.test.ts`);
2605
+ success(` src/modules/${kebabName}/__tests__/${kebabName}.service.test.ts`);
2606
+ success(` src/modules/${kebabName}/__tests__/${kebabName}.integration.test.ts`);
2607
+ }
2361
2608
  console.log("\n\u{1F4CC} Next steps:");
2362
2609
  if (!hasFields) {
2363
2610
  info(` 1. Update the types in ${kebabName}.types.ts`);
@@ -2385,8 +2632,8 @@ generateCommand.command("controller <name>").alias("c").description("Generate a
2385
2632
  const pascalName = toPascalCase(name);
2386
2633
  const camelName = toCamelCase(name);
2387
2634
  const moduleName = options.module ? toKebabCase(options.module) : kebabName;
2388
- const moduleDir = path5.join(getModulesDir(), moduleName);
2389
- const filePath = path5.join(moduleDir, `${kebabName}.controller.ts`);
2635
+ const moduleDir = path4.join(getModulesDir(), moduleName);
2636
+ const filePath = path4.join(moduleDir, `${kebabName}.controller.ts`);
2390
2637
  if (await fileExists(filePath)) {
2391
2638
  spinner.stop();
2392
2639
  displayError(ErrorTypes.FILE_ALREADY_EXISTS(`${kebabName}.controller.ts`));
@@ -2409,8 +2656,8 @@ generateCommand.command("service <name>").alias("s").description("Generate a ser
2409
2656
  const pascalName = toPascalCase(name);
2410
2657
  const camelName = toCamelCase(name);
2411
2658
  const moduleName = options.module ? toKebabCase(options.module) : kebabName;
2412
- const moduleDir = path5.join(getModulesDir(), moduleName);
2413
- const filePath = path5.join(moduleDir, `${kebabName}.service.ts`);
2659
+ const moduleDir = path4.join(getModulesDir(), moduleName);
2660
+ const filePath = path4.join(moduleDir, `${kebabName}.service.ts`);
2414
2661
  if (await fileExists(filePath)) {
2415
2662
  spinner.stop();
2416
2663
  error(`Service "${kebabName}" already exists`);
@@ -2434,8 +2681,8 @@ generateCommand.command("repository <name>").alias("r").description("Generate a
2434
2681
  const camelName = toCamelCase(name);
2435
2682
  const pluralName = pluralize(kebabName);
2436
2683
  const moduleName = options.module ? toKebabCase(options.module) : kebabName;
2437
- const moduleDir = path5.join(getModulesDir(), moduleName);
2438
- const filePath = path5.join(moduleDir, `${kebabName}.repository.ts`);
2684
+ const moduleDir = path4.join(getModulesDir(), moduleName);
2685
+ const filePath = path4.join(moduleDir, `${kebabName}.repository.ts`);
2439
2686
  if (await fileExists(filePath)) {
2440
2687
  spinner.stop();
2441
2688
  error(`Repository "${kebabName}" already exists`);
@@ -2457,8 +2704,8 @@ generateCommand.command("types <name>").alias("t").description("Generate types/i
2457
2704
  const kebabName = toKebabCase(name);
2458
2705
  const pascalName = toPascalCase(name);
2459
2706
  const moduleName = options.module ? toKebabCase(options.module) : kebabName;
2460
- const moduleDir = path5.join(getModulesDir(), moduleName);
2461
- const filePath = path5.join(moduleDir, `${kebabName}.types.ts`);
2707
+ const moduleDir = path4.join(getModulesDir(), moduleName);
2708
+ const filePath = path4.join(moduleDir, `${kebabName}.types.ts`);
2462
2709
  if (await fileExists(filePath)) {
2463
2710
  spinner.stop();
2464
2711
  error(`Types file "${kebabName}.types.ts" already exists`);
@@ -2481,8 +2728,8 @@ generateCommand.command("schema <name>").alias("v").description("Generate valida
2481
2728
  const pascalName = toPascalCase(name);
2482
2729
  const camelName = toCamelCase(name);
2483
2730
  const moduleName = options.module ? toKebabCase(options.module) : kebabName;
2484
- const moduleDir = path5.join(getModulesDir(), moduleName);
2485
- const filePath = path5.join(moduleDir, `${kebabName}.schemas.ts`);
2731
+ const moduleDir = path4.join(getModulesDir(), moduleName);
2732
+ const filePath = path4.join(moduleDir, `${kebabName}.schemas.ts`);
2486
2733
  if (await fileExists(filePath)) {
2487
2734
  spinner.stop();
2488
2735
  error(`Schemas file "${kebabName}.schemas.ts" already exists`);
@@ -2506,8 +2753,8 @@ generateCommand.command("routes <name>").description("Generate routes").option("
2506
2753
  const camelName = toCamelCase(name);
2507
2754
  const pluralName = pluralize(kebabName);
2508
2755
  const moduleName = options.module ? toKebabCase(options.module) : kebabName;
2509
- const moduleDir = path5.join(getModulesDir(), moduleName);
2510
- const filePath = path5.join(moduleDir, `${kebabName}.routes.ts`);
2756
+ const moduleDir = path4.join(getModulesDir(), moduleName);
2757
+ const filePath = path4.join(moduleDir, `${kebabName}.routes.ts`);
2511
2758
  if (await fileExists(filePath)) {
2512
2759
  spinner.stop();
2513
2760
  error(`Routes file "${kebabName}.routes.ts" already exists`);
@@ -2594,24 +2841,22 @@ async function promptForFields() {
2594
2841
  }
2595
2842
 
2596
2843
  // src/cli/commands/add-module.ts
2597
- init_esm_shims();
2598
2844
  import { Command as Command3 } from "commander";
2599
- import path8 from "path";
2845
+ import path7 from "path";
2600
2846
  import ora3 from "ora";
2601
2847
  import chalk7 from "chalk";
2602
2848
  import * as fs5 from "fs/promises";
2603
2849
 
2604
2850
  // src/cli/utils/env-manager.ts
2605
- init_esm_shims();
2606
2851
  import * as fs3 from "fs/promises";
2607
- import * as path6 from "path";
2852
+ import * as path5 from "path";
2608
2853
  import { existsSync } from "fs";
2609
2854
  var EnvManager = class {
2610
2855
  envPath;
2611
2856
  envExamplePath;
2612
2857
  constructor(projectRoot) {
2613
- this.envPath = path6.join(projectRoot, ".env");
2614
- this.envExamplePath = path6.join(projectRoot, ".env.example");
2858
+ this.envPath = path5.join(projectRoot, ".env");
2859
+ this.envExamplePath = path5.join(projectRoot, ".env.example");
2615
2860
  }
2616
2861
  /**
2617
2862
  * Add environment variables to .env file
@@ -3261,17 +3506,16 @@ var EnvManager = class {
3261
3506
  };
3262
3507
 
3263
3508
  // src/cli/utils/template-manager.ts
3264
- init_esm_shims();
3265
3509
  import * as fs4 from "fs/promises";
3266
- import * as path7 from "path";
3510
+ import * as path6 from "path";
3267
3511
  import { createHash } from "crypto";
3268
3512
  import { existsSync as existsSync2 } from "fs";
3269
3513
  var TemplateManager = class {
3270
3514
  templatesDir;
3271
3515
  manifestsDir;
3272
3516
  constructor(projectRoot) {
3273
- this.templatesDir = path7.join(projectRoot, ".servcraft", "templates");
3274
- this.manifestsDir = path7.join(projectRoot, ".servcraft", "manifests");
3517
+ this.templatesDir = path6.join(projectRoot, ".servcraft", "templates");
3518
+ this.manifestsDir = path6.join(projectRoot, ".servcraft", "manifests");
3275
3519
  }
3276
3520
  /**
3277
3521
  * Initialize template system
@@ -3285,10 +3529,10 @@ var TemplateManager = class {
3285
3529
  */
3286
3530
  async saveTemplate(moduleName, files) {
3287
3531
  await this.initialize();
3288
- const moduleTemplateDir = path7.join(this.templatesDir, moduleName);
3532
+ const moduleTemplateDir = path6.join(this.templatesDir, moduleName);
3289
3533
  await fs4.mkdir(moduleTemplateDir, { recursive: true });
3290
3534
  for (const [fileName, content] of Object.entries(files)) {
3291
- const filePath = path7.join(moduleTemplateDir, fileName);
3535
+ const filePath = path6.join(moduleTemplateDir, fileName);
3292
3536
  await fs4.writeFile(filePath, content, "utf-8");
3293
3537
  }
3294
3538
  }
@@ -3297,7 +3541,7 @@ var TemplateManager = class {
3297
3541
  */
3298
3542
  async getTemplate(moduleName, fileName) {
3299
3543
  try {
3300
- const filePath = path7.join(this.templatesDir, moduleName, fileName);
3544
+ const filePath = path6.join(this.templatesDir, moduleName, fileName);
3301
3545
  return await fs4.readFile(filePath, "utf-8");
3302
3546
  } catch {
3303
3547
  return null;
@@ -3322,7 +3566,7 @@ var TemplateManager = class {
3322
3566
  installedAt: /* @__PURE__ */ new Date(),
3323
3567
  updatedAt: /* @__PURE__ */ new Date()
3324
3568
  };
3325
- const manifestPath = path7.join(this.manifestsDir, `${moduleName}.json`);
3569
+ const manifestPath = path6.join(this.manifestsDir, `${moduleName}.json`);
3326
3570
  await fs4.writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
3327
3571
  }
3328
3572
  /**
@@ -3330,7 +3574,7 @@ var TemplateManager = class {
3330
3574
  */
3331
3575
  async getManifest(moduleName) {
3332
3576
  try {
3333
- const manifestPath = path7.join(this.manifestsDir, `${moduleName}.json`);
3577
+ const manifestPath = path6.join(this.manifestsDir, `${moduleName}.json`);
3334
3578
  const content = await fs4.readFile(manifestPath, "utf-8");
3335
3579
  return JSON.parse(content);
3336
3580
  } catch {
@@ -3359,7 +3603,7 @@ var TemplateManager = class {
3359
3603
  }
3360
3604
  const results = [];
3361
3605
  for (const [fileName, fileInfo] of Object.entries(manifest.files)) {
3362
- const filePath = path7.join(moduleDir, fileName);
3606
+ const filePath = path6.join(moduleDir, fileName);
3363
3607
  if (!existsSync2(filePath)) {
3364
3608
  results.push({
3365
3609
  fileName,
@@ -3385,7 +3629,7 @@ var TemplateManager = class {
3385
3629
  */
3386
3630
  async createBackup(moduleName, moduleDir) {
3387
3631
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
3388
- const backupDir = path7.join(path7.dirname(moduleDir), `${moduleName}.backup-${timestamp}`);
3632
+ const backupDir = path6.join(path6.dirname(moduleDir), `${moduleName}.backup-${timestamp}`);
3389
3633
  await this.copyDirectory(moduleDir, backupDir);
3390
3634
  return backupDir;
3391
3635
  }
@@ -3396,8 +3640,8 @@ var TemplateManager = class {
3396
3640
  await fs4.mkdir(dest, { recursive: true });
3397
3641
  const entries = await fs4.readdir(src, { withFileTypes: true });
3398
3642
  for (const entry of entries) {
3399
- const srcPath = path7.join(src, entry.name);
3400
- const destPath = path7.join(dest, entry.name);
3643
+ const srcPath = path6.join(src, entry.name);
3644
+ const destPath = path6.join(dest, entry.name);
3401
3645
  if (entry.isDirectory()) {
3402
3646
  await this.copyDirectory(srcPath, destPath);
3403
3647
  } else {
@@ -3498,13 +3742,12 @@ var TemplateManager = class {
3498
3742
  }
3499
3743
  manifest.files = fileHashes;
3500
3744
  manifest.updatedAt = /* @__PURE__ */ new Date();
3501
- const manifestPath = path7.join(this.manifestsDir, `${moduleName}.json`);
3745
+ const manifestPath = path6.join(this.manifestsDir, `${moduleName}.json`);
3502
3746
  await fs4.writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
3503
3747
  }
3504
3748
  };
3505
3749
 
3506
3750
  // src/cli/utils/interactive-prompt.ts
3507
- init_esm_shims();
3508
3751
  import inquirer3 from "inquirer";
3509
3752
  import chalk6 from "chalk";
3510
3753
  var InteractivePrompt = class {
@@ -3690,7 +3933,6 @@ var InteractivePrompt = class {
3690
3933
  };
3691
3934
 
3692
3935
  // src/cli/commands/add-module.ts
3693
- init_error_handler();
3694
3936
  var AVAILABLE_MODULES = {
3695
3937
  auth: {
3696
3938
  name: "Authentication",
@@ -3858,7 +4100,7 @@ var addModuleCommand = new Command3("add").description("Add a pre-built module t
3858
4100
  }
3859
4101
  const spinner = ora3(`Adding ${module.name} module...`).start();
3860
4102
  try {
3861
- const moduleDir = path8.join(getModulesDir(), moduleName);
4103
+ const moduleDir = path7.join(getModulesDir(), moduleName);
3862
4104
  const templateManager = new TemplateManager(process.cwd());
3863
4105
  const moduleExists = await fileExists(moduleDir);
3864
4106
  if (moduleExists) {
@@ -4002,7 +4244,7 @@ export * from './auth.schemas.js';
4002
4244
  `
4003
4245
  };
4004
4246
  for (const [name, content] of Object.entries(files)) {
4005
- await writeFile(path8.join(dir, name), content);
4247
+ await writeFile(path7.join(dir, name), content);
4006
4248
  }
4007
4249
  }
4008
4250
  async function generateUsersModule(dir) {
@@ -4042,7 +4284,7 @@ export * from './user.schemas.js';
4042
4284
  `
4043
4285
  };
4044
4286
  for (const [name, content] of Object.entries(files)) {
4045
- await writeFile(path8.join(dir, name), content);
4287
+ await writeFile(path7.join(dir, name), content);
4046
4288
  }
4047
4289
  }
4048
4290
  async function generateEmailModule(dir) {
@@ -4099,7 +4341,7 @@ export { EmailService, emailService } from './email.service.js';
4099
4341
  `
4100
4342
  };
4101
4343
  for (const [name, content] of Object.entries(files)) {
4102
- await writeFile(path8.join(dir, name), content);
4344
+ await writeFile(path7.join(dir, name), content);
4103
4345
  }
4104
4346
  }
4105
4347
  async function generateAuditModule(dir) {
@@ -4143,7 +4385,7 @@ export { AuditService, auditService } from './audit.service.js';
4143
4385
  `
4144
4386
  };
4145
4387
  for (const [name, content] of Object.entries(files)) {
4146
- await writeFile(path8.join(dir, name), content);
4388
+ await writeFile(path7.join(dir, name), content);
4147
4389
  }
4148
4390
  }
4149
4391
  async function generateUploadModule(dir) {
@@ -4169,7 +4411,7 @@ export interface UploadOptions {
4169
4411
  `
4170
4412
  };
4171
4413
  for (const [name, content] of Object.entries(files)) {
4172
- await writeFile(path8.join(dir, name), content);
4414
+ await writeFile(path7.join(dir, name), content);
4173
4415
  }
4174
4416
  }
4175
4417
  async function generateCacheModule(dir) {
@@ -4215,7 +4457,7 @@ export { CacheService, cacheService } from './cache.service.js';
4215
4457
  `
4216
4458
  };
4217
4459
  for (const [name, content] of Object.entries(files)) {
4218
- await writeFile(path8.join(dir, name), content);
4460
+ await writeFile(path7.join(dir, name), content);
4219
4461
  }
4220
4462
  }
4221
4463
  async function generateGenericModule(dir, name) {
@@ -4229,18 +4471,18 @@ export interface ${name.charAt(0).toUpperCase() + name.slice(1)}Data {
4229
4471
  `
4230
4472
  };
4231
4473
  for (const [fileName, content] of Object.entries(files)) {
4232
- await writeFile(path8.join(dir, fileName), content);
4474
+ await writeFile(path7.join(dir, fileName), content);
4233
4475
  }
4234
4476
  }
4235
4477
  async function findServercraftModules() {
4236
- const scriptDir = path8.dirname(new URL(import.meta.url).pathname);
4478
+ const scriptDir = path7.dirname(new URL(import.meta.url).pathname);
4237
4479
  const possiblePaths = [
4238
4480
  // Local node_modules (when servcraft is a dependency)
4239
- path8.join(process.cwd(), "node_modules", "servcraft", "src", "modules"),
4481
+ path7.join(process.cwd(), "node_modules", "servcraft", "src", "modules"),
4240
4482
  // From dist/cli/index.js -> src/modules (npx or global install)
4241
- path8.resolve(scriptDir, "..", "..", "src", "modules"),
4483
+ path7.resolve(scriptDir, "..", "..", "src", "modules"),
4242
4484
  // From src/cli/commands/add-module.ts -> src/modules (development)
4243
- path8.resolve(scriptDir, "..", "..", "modules")
4485
+ path7.resolve(scriptDir, "..", "..", "modules")
4244
4486
  ];
4245
4487
  for (const p of possiblePaths) {
4246
4488
  try {
@@ -4264,7 +4506,7 @@ async function generateModuleFiles(moduleName, moduleDir) {
4264
4506
  const sourceDirName = moduleNameMap[moduleName] || moduleName;
4265
4507
  const servercraftModulesDir = await findServercraftModules();
4266
4508
  if (servercraftModulesDir) {
4267
- const sourceModuleDir = path8.join(servercraftModulesDir, sourceDirName);
4509
+ const sourceModuleDir = path7.join(servercraftModulesDir, sourceDirName);
4268
4510
  if (await fileExists(sourceModuleDir)) {
4269
4511
  await copyModuleFromSource(sourceModuleDir, moduleDir);
4270
4512
  return;
@@ -4296,8 +4538,8 @@ async function generateModuleFiles(moduleName, moduleDir) {
4296
4538
  async function copyModuleFromSource(sourceDir, targetDir) {
4297
4539
  const entries = await fs5.readdir(sourceDir, { withFileTypes: true });
4298
4540
  for (const entry of entries) {
4299
- const sourcePath = path8.join(sourceDir, entry.name);
4300
- const targetPath = path8.join(targetDir, entry.name);
4541
+ const sourcePath = path7.join(sourceDir, entry.name);
4542
+ const targetPath = path7.join(targetDir, entry.name);
4301
4543
  if (entry.isDirectory()) {
4302
4544
  await fs5.mkdir(targetPath, { recursive: true });
4303
4545
  await copyModuleFromSource(sourcePath, targetPath);
@@ -4310,7 +4552,7 @@ async function getModuleFiles(moduleName, moduleDir) {
4310
4552
  const files = {};
4311
4553
  const entries = await fs5.readdir(moduleDir);
4312
4554
  for (const entry of entries) {
4313
- const filePath = path8.join(moduleDir, entry);
4555
+ const filePath = path7.join(moduleDir, entry);
4314
4556
  const stat2 = await fs5.stat(filePath);
4315
4557
  if (stat2.isFile() && entry.endsWith(".ts")) {
4316
4558
  const content = await fs5.readFile(filePath, "utf-8");
@@ -4328,7 +4570,7 @@ async function showDiffForModule(templateManager, moduleName, moduleDir) {
4328
4570
  if (file.isModified) {
4329
4571
  console.log(chalk7.yellow(`
4330
4572
  \u{1F4C4} ${file.fileName}:`));
4331
- const currentPath = path8.join(moduleDir, file.fileName);
4573
+ const currentPath = path7.join(moduleDir, file.fileName);
4332
4574
  const currentContent = await fs5.readFile(currentPath, "utf-8");
4333
4575
  const originalContent = await templateManager.getTemplate(moduleName, file.fileName);
4334
4576
  if (originalContent) {
@@ -4341,11 +4583,11 @@ async function showDiffForModule(templateManager, moduleName, moduleDir) {
4341
4583
  async function performSmartMerge(templateManager, moduleName, moduleDir, _displayName) {
4342
4584
  const spinner = ora3("Analyzing files for merge...").start();
4343
4585
  const newFiles = {};
4344
- const templateDir = path8.join(templateManager["templatesDir"], moduleName);
4586
+ const templateDir = path7.join(templateManager["templatesDir"], moduleName);
4345
4587
  try {
4346
4588
  const entries = await fs5.readdir(templateDir);
4347
4589
  for (const entry of entries) {
4348
- const content = await fs5.readFile(path8.join(templateDir, entry), "utf-8");
4590
+ const content = await fs5.readFile(path7.join(templateDir, entry), "utf-8");
4349
4591
  newFiles[entry] = content;
4350
4592
  }
4351
4593
  } catch {
@@ -4363,7 +4605,7 @@ async function performSmartMerge(templateManager, moduleName, moduleDir, _displa
4363
4605
  };
4364
4606
  for (const fileInfo of modifiedFiles) {
4365
4607
  const fileName = fileInfo.fileName;
4366
- const filePath = path8.join(moduleDir, fileName);
4608
+ const filePath = path7.join(moduleDir, fileName);
4367
4609
  const newContent = newFiles[fileName];
4368
4610
  if (!newContent) {
4369
4611
  continue;
@@ -4432,7 +4674,6 @@ async function performSmartMerge(templateManager, moduleName, moduleDir, _displa
4432
4674
  }
4433
4675
 
4434
4676
  // src/cli/commands/db.ts
4435
- init_esm_shims();
4436
4677
  import { Command as Command4 } from "commander";
4437
4678
  import { execSync as execSync2, spawn } from "child_process";
4438
4679
  import ora4 from "ora";
@@ -4526,25 +4767,21 @@ dbCommand.command("status").description("Show migration status").action(async ()
4526
4767
  });
4527
4768
 
4528
4769
  // src/cli/commands/docs.ts
4529
- init_esm_shims();
4530
4770
  import { Command as Command5 } from "commander";
4531
- import path10 from "path";
4771
+ import path9 from "path";
4532
4772
  import fs7 from "fs/promises";
4533
4773
  import ora6 from "ora";
4534
4774
  import chalk9 from "chalk";
4535
4775
 
4536
4776
  // src/cli/utils/docs-generator.ts
4537
- init_esm_shims();
4538
4777
  import fs6 from "fs/promises";
4539
- import path9 from "path";
4778
+ import path8 from "path";
4540
4779
  import ora5 from "ora";
4541
4780
 
4542
4781
  // src/core/server.ts
4543
- init_esm_shims();
4544
4782
  import Fastify from "fastify";
4545
4783
 
4546
4784
  // src/core/logger.ts
4547
- init_esm_shims();
4548
4785
  import pino from "pino";
4549
4786
  var defaultConfig = {
4550
4787
  level: process.env.LOG_LEVEL || "info",
@@ -4677,14 +4914,7 @@ function createServer(config2 = {}) {
4677
4914
  return new Server(config2);
4678
4915
  }
4679
4916
 
4680
- // src/middleware/index.ts
4681
- init_esm_shims();
4682
-
4683
- // src/middleware/error-handler.ts
4684
- init_esm_shims();
4685
-
4686
4917
  // src/utils/errors.ts
4687
- init_esm_shims();
4688
4918
  var AppError = class _AppError extends Error {
4689
4919
  statusCode;
4690
4920
  isOperational;
@@ -4738,11 +4968,7 @@ function isAppError(error2) {
4738
4968
  return error2 instanceof AppError;
4739
4969
  }
4740
4970
 
4741
- // src/config/index.ts
4742
- init_esm_shims();
4743
-
4744
4971
  // src/config/env.ts
4745
- init_esm_shims();
4746
4972
  import { z } from "zod";
4747
4973
  import dotenv from "dotenv";
4748
4974
  dotenv.config();
@@ -4888,7 +5114,6 @@ function registerErrorHandler(app) {
4888
5114
  }
4889
5115
 
4890
5116
  // src/middleware/security.ts
4891
- init_esm_shims();
4892
5117
  import helmet from "@fastify/helmet";
4893
5118
  import cors from "@fastify/cors";
4894
5119
  import rateLimit from "@fastify/rate-limit";
@@ -4948,11 +5173,7 @@ async function registerSecurity(app, options = {}) {
4948
5173
  }
4949
5174
  }
4950
5175
 
4951
- // src/modules/swagger/index.ts
4952
- init_esm_shims();
4953
-
4954
5176
  // src/modules/swagger/swagger.service.ts
4955
- init_esm_shims();
4956
5177
  import swagger from "@fastify/swagger";
4957
5178
  import swaggerUi from "@fastify/swagger-ui";
4958
5179
  var defaultConfig3 = {
@@ -5012,16 +5233,11 @@ async function registerSwagger(app, customConfig) {
5012
5233
  logger.info("Swagger documentation registered at /docs");
5013
5234
  }
5014
5235
 
5015
- // src/modules/swagger/schema-builder.ts
5016
- init_esm_shims();
5017
-
5018
5236
  // src/modules/auth/index.ts
5019
- init_esm_shims();
5020
5237
  import jwt from "@fastify/jwt";
5021
5238
  import cookie from "@fastify/cookie";
5022
5239
 
5023
5240
  // src/modules/auth/auth.service.ts
5024
- init_esm_shims();
5025
5241
  import bcrypt from "bcryptjs";
5026
5242
  import { Redis } from "ioredis";
5027
5243
  var AuthService = class {
@@ -5220,11 +5436,7 @@ function createAuthService(app) {
5220
5436
  return new AuthService(app);
5221
5437
  }
5222
5438
 
5223
- // src/modules/auth/auth.controller.ts
5224
- init_esm_shims();
5225
-
5226
5439
  // src/modules/auth/schemas.ts
5227
- init_esm_shims();
5228
5440
  import { z as z2 } from "zod";
5229
5441
  var loginSchema = z2.object({
5230
5442
  email: z2.string().email("Invalid email address"),
@@ -5251,7 +5463,6 @@ var changePasswordSchema = z2.object({
5251
5463
  });
5252
5464
 
5253
5465
  // src/utils/response.ts
5254
- init_esm_shims();
5255
5466
  function success2(reply, data, statusCode = 200) {
5256
5467
  const response = {
5257
5468
  success: true,
@@ -5267,7 +5478,6 @@ function noContent(reply) {
5267
5478
  }
5268
5479
 
5269
5480
  // src/modules/validation/validator.ts
5270
- init_esm_shims();
5271
5481
  import { z as z3 } from "zod";
5272
5482
  function validateBody(schema, data) {
5273
5483
  const result = schema.safeParse(data);
@@ -5438,11 +5648,7 @@ function createAuthController(authService, userService) {
5438
5648
  return new AuthController(authService, userService);
5439
5649
  }
5440
5650
 
5441
- // src/modules/auth/auth.routes.ts
5442
- init_esm_shims();
5443
-
5444
5651
  // src/modules/auth/auth.middleware.ts
5445
- init_esm_shims();
5446
5652
  function createAuthMiddleware(authService) {
5447
5653
  return async function authenticate(request, _reply) {
5448
5654
  const authHeader = request.headers.authorization;
@@ -5485,14 +5691,7 @@ function registerAuthRoutes(app, controller, authService) {
5485
5691
  );
5486
5692
  }
5487
5693
 
5488
- // src/modules/user/user.service.ts
5489
- init_esm_shims();
5490
-
5491
- // src/modules/user/user.repository.ts
5492
- init_esm_shims();
5493
-
5494
5694
  // src/database/prisma.ts
5495
- init_esm_shims();
5496
5695
  import { PrismaClient } from "@prisma/client";
5497
5696
  var prismaClientSingleton = () => {
5498
5697
  return new PrismaClient({
@@ -5506,7 +5705,6 @@ if (!isProduction()) {
5506
5705
  }
5507
5706
 
5508
5707
  // src/utils/pagination.ts
5509
- init_esm_shims();
5510
5708
  var DEFAULT_PAGE = 1;
5511
5709
  var DEFAULT_LIMIT = 20;
5512
5710
  var MAX_LIMIT = 100;
@@ -5771,7 +5969,6 @@ function createUserRepository() {
5771
5969
  }
5772
5970
 
5773
5971
  // src/modules/user/types.ts
5774
- init_esm_shims();
5775
5972
  var DEFAULT_ROLE_PERMISSIONS = {
5776
5973
  user: ["profile:read", "profile:update"],
5777
5974
  moderator: [
@@ -5902,9 +6099,6 @@ function createUserService(repository) {
5902
6099
  return new UserService(repository || createUserRepository());
5903
6100
  }
5904
6101
 
5905
- // src/modules/auth/types.ts
5906
- init_esm_shims();
5907
-
5908
6102
  // src/modules/auth/index.ts
5909
6103
  async function registerAuthModule(app) {
5910
6104
  await app.register(jwt, {
@@ -5924,14 +6118,7 @@ async function registerAuthModule(app) {
5924
6118
  logger.info("Auth module registered");
5925
6119
  }
5926
6120
 
5927
- // src/modules/user/index.ts
5928
- init_esm_shims();
5929
-
5930
- // src/modules/user/user.controller.ts
5931
- init_esm_shims();
5932
-
5933
6121
  // src/modules/user/schemas.ts
5934
- init_esm_shims();
5935
6122
  import { z as z4 } from "zod";
5936
6123
  var userStatusEnum = z4.enum(["active", "inactive", "suspended", "banned"]);
5937
6124
  var userRoleEnum = z4.enum(["user", "admin", "moderator", "super_admin"]);
@@ -6058,7 +6245,6 @@ function createUserController(userService) {
6058
6245
  }
6059
6246
 
6060
6247
  // src/modules/user/user.routes.ts
6061
- init_esm_shims();
6062
6248
  var idParamsSchema = {
6063
6249
  type: "object",
6064
6250
  properties: {
@@ -6147,8 +6333,8 @@ async function generateDocs(outputPath = "openapi.json", silent = false) {
6147
6333
  await registerUserModule(app, authService);
6148
6334
  await app.ready();
6149
6335
  const spec = app.swagger();
6150
- const absoluteOutput = path9.resolve(outputPath);
6151
- await fs6.mkdir(path9.dirname(absoluteOutput), { recursive: true });
6336
+ const absoluteOutput = path8.resolve(outputPath);
6337
+ await fs6.mkdir(path8.dirname(absoluteOutput), { recursive: true });
6152
6338
  await fs6.writeFile(absoluteOutput, JSON.stringify(spec, null, 2), "utf8");
6153
6339
  spinner?.succeed(`OpenAPI spec generated at ${absoluteOutput}`);
6154
6340
  await app.close();
@@ -6193,7 +6379,7 @@ docsCommand.command("export").description("Export documentation to Postman, Inso
6193
6379
  const spinner = ora6("Exporting documentation...").start();
6194
6380
  try {
6195
6381
  const projectRoot = getProjectRoot();
6196
- const specPath = path10.join(projectRoot, "openapi.json");
6382
+ const specPath = path9.join(projectRoot, "openapi.json");
6197
6383
  try {
6198
6384
  await fs7.access(specPath);
6199
6385
  } catch {
@@ -6220,7 +6406,7 @@ docsCommand.command("export").description("Export documentation to Postman, Inso
6220
6406
  default:
6221
6407
  throw new Error(`Unknown format: ${options.format}`);
6222
6408
  }
6223
- const outPath = path10.join(projectRoot, options.output || defaultName);
6409
+ const outPath = path9.join(projectRoot, options.output || defaultName);
6224
6410
  await fs7.writeFile(outPath, output);
6225
6411
  spinner.succeed(`Exported to: ${options.output || defaultName}`);
6226
6412
  if (options.format === "postman") {
@@ -6234,7 +6420,7 @@ docsCommand.command("export").description("Export documentation to Postman, Inso
6234
6420
  docsCommand.command("status").description("Show documentation status").action(async () => {
6235
6421
  const projectRoot = getProjectRoot();
6236
6422
  console.log(chalk9.bold("\n\u{1F4CA} Documentation Status\n"));
6237
- const specPath = path10.join(projectRoot, "openapi.json");
6423
+ const specPath = path9.join(projectRoot, "openapi.json");
6238
6424
  try {
6239
6425
  const stat2 = await fs7.stat(specPath);
6240
6426
  success(
@@ -6350,7 +6536,6 @@ function formatDate(date) {
6350
6536
  }
6351
6537
 
6352
6538
  // src/cli/commands/list.ts
6353
- init_esm_shims();
6354
6539
  import { Command as Command6 } from "commander";
6355
6540
  import chalk10 from "chalk";
6356
6541
  import fs8 from "fs/promises";
@@ -6508,7 +6693,7 @@ var listCommand = new Command6("list").alias("ls").description("List available a
6508
6693
  if (!byCategory[mod.category]) {
6509
6694
  byCategory[mod.category] = [];
6510
6695
  }
6511
- byCategory[mod.category].push({
6696
+ byCategory[mod.category]?.push({
6512
6697
  id: key,
6513
6698
  name: mod.name,
6514
6699
  description: mod.description,
@@ -6576,14 +6761,12 @@ var listCommand = new Command6("list").alias("ls").description("List available a
6576
6761
  );
6577
6762
 
6578
6763
  // src/cli/commands/remove.ts
6579
- init_esm_shims();
6580
6764
  import { Command as Command7 } from "commander";
6581
- import path11 from "path";
6765
+ import path10 from "path";
6582
6766
  import ora7 from "ora";
6583
6767
  import chalk11 from "chalk";
6584
6768
  import fs9 from "fs/promises";
6585
6769
  import inquirer4 from "inquirer";
6586
- init_error_handler();
6587
6770
  var removeCommand = new Command7("remove").alias("rm").description("Remove an installed module from your project").argument("<module>", "Module to remove").option("-y, --yes", "Skip confirmation prompt").option("--keep-env", "Keep environment variables").action(async (moduleName, options) => {
6588
6771
  const projectError = validateProject();
6589
6772
  if (projectError) {
@@ -6591,18 +6774,15 @@ var removeCommand = new Command7("remove").alias("rm").description("Remove an in
6591
6774
  return;
6592
6775
  }
6593
6776
  console.log(chalk11.bold.cyan("\n\u{1F5D1}\uFE0F ServCraft Module Removal\n"));
6594
- const moduleDir = path11.join(getModulesDir(), moduleName);
6777
+ const moduleDir = path10.join(getModulesDir(), moduleName);
6595
6778
  try {
6596
6779
  const exists = await fs9.access(moduleDir).then(() => true).catch(() => false);
6597
6780
  if (!exists) {
6598
6781
  displayError(
6599
- new (init_error_handler(), __toCommonJS(error_handler_exports)).ServCraftError(
6600
- `Module "${moduleName}" is not installed`,
6601
- [
6602
- `Run ${chalk11.cyan("servcraft list --installed")} to see installed modules`,
6603
- `Check the spelling of the module name`
6604
- ]
6605
- )
6782
+ new ServCraftError(`Module "${moduleName}" is not installed`, [
6783
+ `Run ${chalk11.cyan("servcraft list --installed")} to see installed modules`,
6784
+ `Check the spelling of the module name`
6785
+ ])
6606
6786
  );
6607
6787
  return;
6608
6788
  }
@@ -6651,15 +6831,430 @@ var removeCommand = new Command7("remove").alias("rm").description("Remove an in
6651
6831
  });
6652
6832
 
6653
6833
  // src/cli/commands/doctor.ts
6654
- init_esm_shims();
6655
6834
  import { Command as Command8 } from "commander";
6656
6835
  import chalk12 from "chalk";
6836
+ import fs10 from "fs/promises";
6837
+ async function checkNodeVersion() {
6838
+ const version = process.version;
6839
+ const major = parseInt(version.slice(1).split(".")[0] || "0", 10);
6840
+ if (major >= 18) {
6841
+ return { name: "Node.js", status: "pass", message: `${version} \u2713` };
6842
+ }
6843
+ return {
6844
+ name: "Node.js",
6845
+ status: "fail",
6846
+ message: `${version} (< 18)`,
6847
+ suggestion: "Upgrade to Node.js 18+"
6848
+ };
6849
+ }
6850
+ async function checkPackageJson() {
6851
+ const checks = [];
6852
+ try {
6853
+ const content = await fs10.readFile("package.json", "utf-8");
6854
+ const pkg = JSON.parse(content);
6855
+ checks.push({ name: "package.json", status: "pass", message: "Found" });
6856
+ if (pkg.dependencies?.fastify) {
6857
+ checks.push({ name: "Fastify", status: "pass", message: "Installed" });
6858
+ } else {
6859
+ checks.push({
6860
+ name: "Fastify",
6861
+ status: "fail",
6862
+ message: "Missing",
6863
+ suggestion: "npm install fastify"
6864
+ });
6865
+ }
6866
+ } catch {
6867
+ checks.push({
6868
+ name: "package.json",
6869
+ status: "fail",
6870
+ message: "Not found",
6871
+ suggestion: "Run servcraft init"
6872
+ });
6873
+ }
6874
+ return checks;
6875
+ }
6876
+ async function checkDirectories() {
6877
+ const checks = [];
6878
+ const dirs = ["src", "node_modules", ".git", ".env"];
6879
+ for (const dir of dirs) {
6880
+ try {
6881
+ await fs10.access(dir);
6882
+ checks.push({ name: dir, status: "pass", message: "Exists" });
6883
+ } catch {
6884
+ const isCritical = dir === "src" || dir === "node_modules";
6885
+ checks.push({
6886
+ name: dir,
6887
+ status: isCritical ? "fail" : "warn",
6888
+ message: "Not found",
6889
+ suggestion: dir === "node_modules" ? "npm install" : dir === ".env" ? "Create .env file" : void 0
6890
+ });
6891
+ }
6892
+ }
6893
+ return checks;
6894
+ }
6657
6895
  var doctorCommand = new Command8("doctor").description("Diagnose project configuration and dependencies").action(async () => {
6658
- console.log(chalk12.bold.cyan("\nServCraft Doctor - Coming soon!\n"));
6896
+ console.log(chalk12.bold.cyan("\n\u{1F50D} ServCraft Doctor\n"));
6897
+ const allChecks = [];
6898
+ allChecks.push(await checkNodeVersion());
6899
+ allChecks.push(...await checkPackageJson());
6900
+ allChecks.push(...await checkDirectories());
6901
+ allChecks.forEach((check) => {
6902
+ const icon = check.status === "pass" ? chalk12.green("\u2713") : check.status === "warn" ? chalk12.yellow("\u26A0") : chalk12.red("\u2717");
6903
+ const color = check.status === "pass" ? chalk12.green : check.status === "warn" ? chalk12.yellow : chalk12.red;
6904
+ console.log(`${icon} ${check.name.padEnd(20)} ${color(check.message)}`);
6905
+ if (check.suggestion) {
6906
+ console.log(chalk12.gray(` \u2192 ${check.suggestion}`));
6907
+ }
6908
+ });
6909
+ const pass = allChecks.filter((c) => c.status === "pass").length;
6910
+ const warn2 = allChecks.filter((c) => c.status === "warn").length;
6911
+ const fail = allChecks.filter((c) => c.status === "fail").length;
6912
+ console.log(chalk12.gray("\n" + "\u2500".repeat(60)));
6913
+ console.log(
6914
+ `
6915
+ ${chalk12.green(pass + " passed")} | ${chalk12.yellow(warn2 + " warnings")} | ${chalk12.red(fail + " failed")}
6916
+ `
6917
+ );
6918
+ if (fail === 0 && warn2 === 0) {
6919
+ console.log(chalk12.green.bold("\u2728 Everything looks good!\n"));
6920
+ } else if (fail > 0) {
6921
+ console.log(chalk12.red.bold("\u2717 Fix critical issues before using ServCraft.\n"));
6922
+ } else {
6923
+ console.log(chalk12.yellow.bold("\u26A0 Some warnings, but should work.\n"));
6924
+ }
6925
+ });
6926
+
6927
+ // src/cli/commands/update.ts
6928
+ import { Command as Command9 } from "commander";
6929
+ import chalk13 from "chalk";
6930
+ import fs11 from "fs/promises";
6931
+ import path11 from "path";
6932
+ import { fileURLToPath } from "url";
6933
+ import inquirer5 from "inquirer";
6934
+ var __filename2 = fileURLToPath(import.meta.url);
6935
+ var __dirname2 = path11.dirname(__filename2);
6936
+ var AVAILABLE_MODULES3 = [
6937
+ "auth",
6938
+ "users",
6939
+ "email",
6940
+ "mfa",
6941
+ "oauth",
6942
+ "rate-limit",
6943
+ "cache",
6944
+ "upload",
6945
+ "search",
6946
+ "notification",
6947
+ "webhook",
6948
+ "websocket",
6949
+ "queue",
6950
+ "payment",
6951
+ "i18n",
6952
+ "feature-flag",
6953
+ "analytics",
6954
+ "media-processing",
6955
+ "api-versioning",
6956
+ "audit",
6957
+ "swagger",
6958
+ "validation"
6959
+ ];
6960
+ async function getInstalledModules2() {
6961
+ try {
6962
+ const modulesDir = getModulesDir();
6963
+ const entries = await fs11.readdir(modulesDir, { withFileTypes: true });
6964
+ const installedModules = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => AVAILABLE_MODULES3.includes(name));
6965
+ return installedModules;
6966
+ } catch {
6967
+ return [];
6968
+ }
6969
+ }
6970
+ async function copyModuleFiles(moduleName, _projectRoot) {
6971
+ const cliRoot = path11.resolve(__dirname2, "../../../");
6972
+ const sourceModulePath = path11.join(cliRoot, "src", "modules", moduleName);
6973
+ const targetModulesDir = getModulesDir();
6974
+ const targetModulePath = path11.join(targetModulesDir, moduleName);
6975
+ try {
6976
+ await fs11.access(sourceModulePath);
6977
+ } catch {
6978
+ throw new Error(`Module source not found: ${moduleName}`);
6979
+ }
6980
+ await fs11.cp(sourceModulePath, targetModulePath, { recursive: true });
6981
+ }
6982
+ async function updateModule(moduleName, options) {
6983
+ const projectError = validateProject();
6984
+ if (projectError) {
6985
+ displayError(projectError);
6986
+ return;
6987
+ }
6988
+ const projectRoot = getProjectRoot();
6989
+ const installedModules = await getInstalledModules2();
6990
+ if (!installedModules.includes(moduleName)) {
6991
+ console.log(chalk13.yellow(`
6992
+ \u26A0 Module "${moduleName}" is not installed
6993
+ `));
6994
+ console.log(
6995
+ chalk13.gray(`Run ${chalk13.cyan(`servcraft add ${moduleName}`)} to install it first.
6996
+ `)
6997
+ );
6998
+ return;
6999
+ }
7000
+ if (options.check) {
7001
+ console.log(chalk13.cyan(`
7002
+ \u{1F4E6} Checking updates for "${moduleName}"...
7003
+ `));
7004
+ console.log(chalk13.gray("Note: Version tracking will be implemented in a future release."));
7005
+ console.log(chalk13.gray("Currently, update will always reinstall the latest version.\n"));
7006
+ return;
7007
+ }
7008
+ const { confirmed } = await inquirer5.prompt([
7009
+ {
7010
+ type: "confirm",
7011
+ name: "confirmed",
7012
+ message: `Update "${moduleName}" module? This will overwrite existing files.`,
7013
+ default: false
7014
+ }
7015
+ ]);
7016
+ if (!confirmed) {
7017
+ console.log(chalk13.yellow("\n\u26A0 Update cancelled\n"));
7018
+ return;
7019
+ }
7020
+ console.log(chalk13.cyan(`
7021
+ \u{1F504} Updating "${moduleName}" module...
7022
+ `));
7023
+ try {
7024
+ await copyModuleFiles(moduleName, projectRoot);
7025
+ console.log(chalk13.green(`\u2714 Module "${moduleName}" updated successfully!
7026
+ `));
7027
+ console.log(
7028
+ chalk13.gray("Note: Remember to review any breaking changes in the documentation.\n")
7029
+ );
7030
+ } catch (error2) {
7031
+ if (error2 instanceof Error) {
7032
+ console.error(chalk13.red(`
7033
+ \u2717 Failed to update module: ${error2.message}
7034
+ `));
7035
+ }
7036
+ }
7037
+ }
7038
+ async function updateAllModules(options) {
7039
+ const projectError = validateProject();
7040
+ if (projectError) {
7041
+ displayError(projectError);
7042
+ return;
7043
+ }
7044
+ const installedModules = await getInstalledModules2();
7045
+ if (installedModules.length === 0) {
7046
+ console.log(chalk13.yellow("\n\u26A0 No modules installed\n"));
7047
+ console.log(chalk13.gray(`Run ${chalk13.cyan("servcraft list")} to see available modules.
7048
+ `));
7049
+ return;
7050
+ }
7051
+ if (options.check) {
7052
+ console.log(chalk13.cyan("\n\u{1F4E6} Checking updates for all modules...\n"));
7053
+ console.log(chalk13.bold("Installed modules:"));
7054
+ installedModules.forEach((mod) => {
7055
+ console.log(` \u2022 ${chalk13.cyan(mod)}`);
7056
+ });
7057
+ console.log();
7058
+ console.log(chalk13.gray("Note: Version tracking will be implemented in a future release."));
7059
+ console.log(chalk13.gray("Currently, update will always reinstall the latest version.\n"));
7060
+ return;
7061
+ }
7062
+ console.log(chalk13.cyan(`
7063
+ \u{1F4E6} Found ${installedModules.length} installed module(s):
7064
+ `));
7065
+ installedModules.forEach((mod) => {
7066
+ console.log(` \u2022 ${chalk13.cyan(mod)}`);
7067
+ });
7068
+ console.log();
7069
+ const { confirmed } = await inquirer5.prompt([
7070
+ {
7071
+ type: "confirm",
7072
+ name: "confirmed",
7073
+ message: "Update all modules? This will overwrite existing files.",
7074
+ default: false
7075
+ }
7076
+ ]);
7077
+ if (!confirmed) {
7078
+ console.log(chalk13.yellow("\n\u26A0 Update cancelled\n"));
7079
+ return;
7080
+ }
7081
+ console.log(chalk13.cyan("\n\u{1F504} Updating all modules...\n"));
7082
+ const projectRoot = getProjectRoot();
7083
+ let successCount = 0;
7084
+ let failCount = 0;
7085
+ for (const moduleName of installedModules) {
7086
+ try {
7087
+ await copyModuleFiles(moduleName, projectRoot);
7088
+ console.log(chalk13.green(`\u2714 Updated: ${moduleName}`));
7089
+ successCount++;
7090
+ } catch {
7091
+ console.error(chalk13.red(`\u2717 Failed: ${moduleName}`));
7092
+ failCount++;
7093
+ }
7094
+ }
7095
+ console.log();
7096
+ console.log(
7097
+ chalk13.bold(
7098
+ `
7099
+ \u2714 Update complete: ${chalk13.green(successCount)} succeeded, ${chalk13.red(failCount)} failed
7100
+ `
7101
+ )
7102
+ );
7103
+ if (successCount > 0) {
7104
+ console.log(
7105
+ chalk13.gray("Note: Remember to review any breaking changes in the documentation.\n")
7106
+ );
7107
+ }
7108
+ }
7109
+ var updateCommand = new Command9("update").description("Update installed modules to latest version").argument("[module]", "Specific module to update").option("--check", "Check for updates without applying").option("-y, --yes", "Skip confirmation prompt").action(async (moduleName, options) => {
7110
+ if (moduleName) {
7111
+ await updateModule(moduleName, { check: options?.check });
7112
+ } else {
7113
+ await updateAllModules({ check: options?.check });
7114
+ }
7115
+ });
7116
+
7117
+ // src/cli/commands/completion.ts
7118
+ import { Command as Command10 } from "commander";
7119
+ var bashScript = `
7120
+ # servcraft bash completion script
7121
+ _servcraft_completions() {
7122
+ local cur prev words cword
7123
+ _init_completion || return
7124
+
7125
+ # Main commands
7126
+ local commands="init add generate list remove doctor update completion docs --version --help"
7127
+
7128
+ # Generate subcommands
7129
+ local generate_subcommands="module controller service repository types schema routes m c s r t"
7130
+
7131
+ case "\${words[1]}" in
7132
+ generate|g)
7133
+ if [[ \${cword} -eq 2 ]]; then
7134
+ COMPREPLY=( $(compgen -W "\${generate_subcommands}" -- "\${cur}") )
7135
+ fi
7136
+ ;;
7137
+ add|remove|rm|update)
7138
+ if [[ \${cword} -eq 2 ]]; then
7139
+ # Get available modules
7140
+ local modules="auth cache rate-limit notification payment oauth mfa queue websocket upload"
7141
+ COMPREPLY=( $(compgen -W "\${modules}" -- "\${cur}") )
7142
+ fi
7143
+ ;;
7144
+ completion)
7145
+ if [[ \${cword} -eq 2 ]]; then
7146
+ COMPREPLY=( $(compgen -W "bash zsh" -- "\${cur}") )
7147
+ fi
7148
+ ;;
7149
+ *)
7150
+ if [[ \${cword} -eq 1 ]]; then
7151
+ COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
7152
+ fi
7153
+ ;;
7154
+ esac
7155
+ }
7156
+
7157
+ complete -F _servcraft_completions servcraft
7158
+ `;
7159
+ var zshScript = `
7160
+ #compdef servcraft
7161
+
7162
+ _servcraft() {
7163
+ local context state state_descr line
7164
+ typeset -A opt_args
7165
+
7166
+ _arguments -C \\
7167
+ '1: :_servcraft_commands' \\
7168
+ '*::arg:->args'
7169
+
7170
+ case $state in
7171
+ args)
7172
+ case $line[1] in
7173
+ generate|g)
7174
+ _servcraft_generate
7175
+ ;;
7176
+ add|remove|rm|update)
7177
+ _servcraft_modules
7178
+ ;;
7179
+ completion)
7180
+ _arguments '1: :(bash zsh)'
7181
+ ;;
7182
+ esac
7183
+ ;;
7184
+ esac
7185
+ }
7186
+
7187
+ _servcraft_commands() {
7188
+ local commands
7189
+ commands=(
7190
+ 'init:Initialize a new ServCraft project'
7191
+ 'add:Add a pre-built module to your project'
7192
+ 'generate:Generate code files (controller, service, etc.)'
7193
+ 'list:List available and installed modules'
7194
+ 'remove:Remove an installed module'
7195
+ 'doctor:Diagnose project configuration'
7196
+ 'update:Update installed modules'
7197
+ 'completion:Generate shell completion scripts'
7198
+ 'docs:Open documentation'
7199
+ '--version:Show version'
7200
+ '--help:Show help'
7201
+ )
7202
+ _describe 'command' commands
7203
+ }
7204
+
7205
+ _servcraft_generate() {
7206
+ local subcommands
7207
+ subcommands=(
7208
+ 'module:Generate a complete module (controller + service + routes)'
7209
+ 'controller:Generate a controller'
7210
+ 'service:Generate a service'
7211
+ 'repository:Generate a repository'
7212
+ 'types:Generate TypeScript types'
7213
+ 'schema:Generate validation schema'
7214
+ 'routes:Generate routes file'
7215
+ 'm:Alias for module'
7216
+ 'c:Alias for controller'
7217
+ 's:Alias for service'
7218
+ 'r:Alias for repository'
7219
+ 't:Alias for types'
7220
+ )
7221
+ _describe 'subcommand' subcommands
7222
+ }
7223
+
7224
+ _servcraft_modules() {
7225
+ local modules
7226
+ modules=(
7227
+ 'auth:Authentication & Authorization'
7228
+ 'cache:Redis caching'
7229
+ 'rate-limit:Rate limiting'
7230
+ 'notification:Email/SMS notifications'
7231
+ 'payment:Payment integration'
7232
+ 'oauth:OAuth providers'
7233
+ 'mfa:Multi-factor authentication'
7234
+ 'queue:Background jobs'
7235
+ 'websocket:WebSocket support'
7236
+ 'upload:File upload handling'
7237
+ )
7238
+ _describe 'module' modules
7239
+ }
7240
+
7241
+ _servcraft "$@"
7242
+ `;
7243
+ var completionCommand = new Command10("completion").description("Generate shell completion scripts").argument("<shell>", "Shell type (bash or zsh)").action((shell) => {
7244
+ const shellLower = shell.toLowerCase();
7245
+ if (shellLower === "bash") {
7246
+ console.log(bashScript);
7247
+ } else if (shellLower === "zsh") {
7248
+ console.log(zshScript);
7249
+ } else {
7250
+ console.error(`Unsupported shell: ${shell}`);
7251
+ console.error("Supported shells: bash, zsh");
7252
+ process.exit(1);
7253
+ }
6659
7254
  });
6660
7255
 
6661
7256
  // src/cli/index.ts
6662
- var program = new Command9();
7257
+ var program = new Command11();
6663
7258
  program.name("servcraft").description("Servcraft - A modular Node.js backend framework CLI").version("0.1.0");
6664
7259
  program.addCommand(initCommand);
6665
7260
  program.addCommand(generateCommand);
@@ -6669,5 +7264,7 @@ program.addCommand(docsCommand);
6669
7264
  program.addCommand(listCommand);
6670
7265
  program.addCommand(removeCommand);
6671
7266
  program.addCommand(doctorCommand);
7267
+ program.addCommand(updateCommand);
7268
+ program.addCommand(completionCommand);
6672
7269
  program.parse();
6673
7270
  //# sourceMappingURL=index.js.map