servcraft 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/.claude/settings.local.json +30 -0
  2. package/.github/CODEOWNERS +18 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
  4. package/.github/dependabot.yml +59 -0
  5. package/.github/workflows/ci.yml +188 -0
  6. package/.github/workflows/release.yml +195 -0
  7. package/AUDIT.md +602 -0
  8. package/LICENSE +21 -0
  9. package/README.md +1102 -1
  10. package/dist/cli/index.cjs +2026 -2168
  11. package/dist/cli/index.cjs.map +1 -1
  12. package/dist/cli/index.js +2026 -2168
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +595 -616
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +114 -52
  17. package/dist/index.d.ts +114 -52
  18. package/dist/index.js +595 -616
  19. package/dist/index.js.map +1 -1
  20. package/docs/CLI-001_MULTI_DB_PLAN.md +546 -0
  21. package/docs/DATABASE_MULTI_ORM.md +399 -0
  22. package/docs/PHASE1_BREAKDOWN.md +346 -0
  23. package/docs/PROGRESS.md +550 -0
  24. package/docs/modules/ANALYTICS.md +226 -0
  25. package/docs/modules/API-VERSIONING.md +252 -0
  26. package/docs/modules/AUDIT.md +192 -0
  27. package/docs/modules/AUTH.md +431 -0
  28. package/docs/modules/CACHE.md +346 -0
  29. package/docs/modules/EMAIL.md +254 -0
  30. package/docs/modules/FEATURE-FLAG.md +291 -0
  31. package/docs/modules/I18N.md +294 -0
  32. package/docs/modules/MEDIA-PROCESSING.md +281 -0
  33. package/docs/modules/MFA.md +266 -0
  34. package/docs/modules/NOTIFICATION.md +311 -0
  35. package/docs/modules/OAUTH.md +237 -0
  36. package/docs/modules/PAYMENT.md +804 -0
  37. package/docs/modules/QUEUE.md +540 -0
  38. package/docs/modules/RATE-LIMIT.md +339 -0
  39. package/docs/modules/SEARCH.md +288 -0
  40. package/docs/modules/SECURITY.md +327 -0
  41. package/docs/modules/SESSION.md +382 -0
  42. package/docs/modules/SWAGGER.md +305 -0
  43. package/docs/modules/UPLOAD.md +296 -0
  44. package/docs/modules/USER.md +505 -0
  45. package/docs/modules/VALIDATION.md +294 -0
  46. package/docs/modules/WEBHOOK.md +270 -0
  47. package/docs/modules/WEBSOCKET.md +691 -0
  48. package/package.json +53 -38
  49. package/prisma/schema.prisma +395 -1
  50. package/src/cli/commands/add-module.ts +520 -87
  51. package/src/cli/commands/db.ts +3 -4
  52. package/src/cli/commands/docs.ts +256 -6
  53. package/src/cli/commands/generate.ts +12 -19
  54. package/src/cli/commands/init.ts +384 -214
  55. package/src/cli/index.ts +0 -4
  56. package/src/cli/templates/repository.ts +6 -1
  57. package/src/cli/templates/routes.ts +6 -21
  58. package/src/cli/utils/docs-generator.ts +6 -7
  59. package/src/cli/utils/env-manager.ts +717 -0
  60. package/src/cli/utils/field-parser.ts +16 -7
  61. package/src/cli/utils/interactive-prompt.ts +223 -0
  62. package/src/cli/utils/template-manager.ts +346 -0
  63. package/src/config/database.config.ts +183 -0
  64. package/src/config/env.ts +0 -10
  65. package/src/config/index.ts +0 -14
  66. package/src/core/server.ts +1 -1
  67. package/src/database/adapters/mongoose.adapter.ts +132 -0
  68. package/src/database/adapters/prisma.adapter.ts +118 -0
  69. package/src/database/connection.ts +190 -0
  70. package/src/database/interfaces/database.interface.ts +85 -0
  71. package/src/database/interfaces/index.ts +7 -0
  72. package/src/database/interfaces/repository.interface.ts +129 -0
  73. package/src/database/models/mongoose/index.ts +7 -0
  74. package/src/database/models/mongoose/payment.schema.ts +347 -0
  75. package/src/database/models/mongoose/user.schema.ts +154 -0
  76. package/src/database/prisma.ts +1 -4
  77. package/src/database/redis.ts +101 -0
  78. package/src/database/repositories/mongoose/index.ts +7 -0
  79. package/src/database/repositories/mongoose/payment.repository.ts +380 -0
  80. package/src/database/repositories/mongoose/user.repository.ts +255 -0
  81. package/src/database/seed.ts +6 -1
  82. package/src/index.ts +9 -20
  83. package/src/middleware/security.ts +2 -6
  84. package/src/modules/analytics/analytics.routes.ts +80 -0
  85. package/src/modules/analytics/analytics.service.ts +364 -0
  86. package/src/modules/analytics/index.ts +18 -0
  87. package/src/modules/analytics/types.ts +180 -0
  88. package/src/modules/api-versioning/index.ts +15 -0
  89. package/src/modules/api-versioning/types.ts +86 -0
  90. package/src/modules/api-versioning/versioning.middleware.ts +120 -0
  91. package/src/modules/api-versioning/versioning.routes.ts +54 -0
  92. package/src/modules/api-versioning/versioning.service.ts +189 -0
  93. package/src/modules/audit/audit.repository.ts +206 -0
  94. package/src/modules/audit/audit.service.ts +27 -59
  95. package/src/modules/auth/auth.controller.ts +2 -2
  96. package/src/modules/auth/auth.middleware.ts +3 -9
  97. package/src/modules/auth/auth.routes.ts +10 -107
  98. package/src/modules/auth/auth.service.ts +126 -23
  99. package/src/modules/auth/index.ts +3 -4
  100. package/src/modules/cache/cache.service.ts +367 -0
  101. package/src/modules/cache/index.ts +10 -0
  102. package/src/modules/cache/types.ts +44 -0
  103. package/src/modules/email/email.service.ts +3 -10
  104. package/src/modules/email/templates.ts +2 -8
  105. package/src/modules/feature-flag/feature-flag.repository.ts +303 -0
  106. package/src/modules/feature-flag/feature-flag.routes.ts +247 -0
  107. package/src/modules/feature-flag/feature-flag.service.ts +566 -0
  108. package/src/modules/feature-flag/index.ts +20 -0
  109. package/src/modules/feature-flag/types.ts +192 -0
  110. package/src/modules/i18n/i18n.middleware.ts +186 -0
  111. package/src/modules/i18n/i18n.routes.ts +191 -0
  112. package/src/modules/i18n/i18n.service.ts +456 -0
  113. package/src/modules/i18n/index.ts +18 -0
  114. package/src/modules/i18n/types.ts +118 -0
  115. package/src/modules/media-processing/index.ts +17 -0
  116. package/src/modules/media-processing/media-processing.routes.ts +111 -0
  117. package/src/modules/media-processing/media-processing.service.ts +245 -0
  118. package/src/modules/media-processing/types.ts +156 -0
  119. package/src/modules/mfa/index.ts +20 -0
  120. package/src/modules/mfa/mfa.repository.ts +206 -0
  121. package/src/modules/mfa/mfa.routes.ts +595 -0
  122. package/src/modules/mfa/mfa.service.ts +572 -0
  123. package/src/modules/mfa/totp.ts +150 -0
  124. package/src/modules/mfa/types.ts +57 -0
  125. package/src/modules/notification/index.ts +20 -0
  126. package/src/modules/notification/notification.repository.ts +356 -0
  127. package/src/modules/notification/notification.service.ts +483 -0
  128. package/src/modules/notification/types.ts +119 -0
  129. package/src/modules/oauth/index.ts +20 -0
  130. package/src/modules/oauth/oauth.repository.ts +219 -0
  131. package/src/modules/oauth/oauth.routes.ts +446 -0
  132. package/src/modules/oauth/oauth.service.ts +293 -0
  133. package/src/modules/oauth/providers/apple.provider.ts +250 -0
  134. package/src/modules/oauth/providers/facebook.provider.ts +181 -0
  135. package/src/modules/oauth/providers/github.provider.ts +248 -0
  136. package/src/modules/oauth/providers/google.provider.ts +189 -0
  137. package/src/modules/oauth/providers/twitter.provider.ts +214 -0
  138. package/src/modules/oauth/types.ts +94 -0
  139. package/src/modules/payment/index.ts +19 -0
  140. package/src/modules/payment/payment.repository.ts +733 -0
  141. package/src/modules/payment/payment.routes.ts +390 -0
  142. package/src/modules/payment/payment.service.ts +354 -0
  143. package/src/modules/payment/providers/mobile-money.provider.ts +274 -0
  144. package/src/modules/payment/providers/paypal.provider.ts +190 -0
  145. package/src/modules/payment/providers/stripe.provider.ts +215 -0
  146. package/src/modules/payment/types.ts +140 -0
  147. package/src/modules/queue/cron.ts +438 -0
  148. package/src/modules/queue/index.ts +87 -0
  149. package/src/modules/queue/queue.routes.ts +600 -0
  150. package/src/modules/queue/queue.service.ts +842 -0
  151. package/src/modules/queue/types.ts +222 -0
  152. package/src/modules/queue/workers.ts +366 -0
  153. package/src/modules/rate-limit/index.ts +59 -0
  154. package/src/modules/rate-limit/rate-limit.middleware.ts +134 -0
  155. package/src/modules/rate-limit/rate-limit.routes.ts +269 -0
  156. package/src/modules/rate-limit/rate-limit.service.ts +348 -0
  157. package/src/modules/rate-limit/stores/memory.store.ts +165 -0
  158. package/src/modules/rate-limit/stores/redis.store.ts +322 -0
  159. package/src/modules/rate-limit/types.ts +153 -0
  160. package/src/modules/search/adapters/elasticsearch.adapter.ts +326 -0
  161. package/src/modules/search/adapters/meilisearch.adapter.ts +261 -0
  162. package/src/modules/search/adapters/memory.adapter.ts +278 -0
  163. package/src/modules/search/index.ts +21 -0
  164. package/src/modules/search/search.service.ts +234 -0
  165. package/src/modules/search/types.ts +214 -0
  166. package/src/modules/security/index.ts +40 -0
  167. package/src/modules/security/sanitize.ts +223 -0
  168. package/src/modules/security/security-audit.service.ts +388 -0
  169. package/src/modules/security/security.middleware.ts +398 -0
  170. package/src/modules/session/index.ts +3 -0
  171. package/src/modules/session/session.repository.ts +159 -0
  172. package/src/modules/session/session.service.ts +340 -0
  173. package/src/modules/session/types.ts +38 -0
  174. package/src/modules/swagger/index.ts +7 -1
  175. package/src/modules/swagger/schema-builder.ts +16 -4
  176. package/src/modules/swagger/swagger.service.ts +9 -10
  177. package/src/modules/swagger/types.ts +0 -2
  178. package/src/modules/upload/index.ts +14 -0
  179. package/src/modules/upload/types.ts +83 -0
  180. package/src/modules/upload/upload.repository.ts +199 -0
  181. package/src/modules/upload/upload.routes.ts +311 -0
  182. package/src/modules/upload/upload.service.ts +448 -0
  183. package/src/modules/user/index.ts +3 -3
  184. package/src/modules/user/user.controller.ts +15 -9
  185. package/src/modules/user/user.repository.ts +237 -113
  186. package/src/modules/user/user.routes.ts +39 -164
  187. package/src/modules/user/user.service.ts +4 -3
  188. package/src/modules/validation/validator.ts +12 -17
  189. package/src/modules/webhook/index.ts +91 -0
  190. package/src/modules/webhook/retry.ts +196 -0
  191. package/src/modules/webhook/signature.ts +135 -0
  192. package/src/modules/webhook/types.ts +181 -0
  193. package/src/modules/webhook/webhook.repository.ts +358 -0
  194. package/src/modules/webhook/webhook.routes.ts +442 -0
  195. package/src/modules/webhook/webhook.service.ts +457 -0
  196. package/src/modules/websocket/features.ts +504 -0
  197. package/src/modules/websocket/index.ts +106 -0
  198. package/src/modules/websocket/middlewares.ts +298 -0
  199. package/src/modules/websocket/types.ts +181 -0
  200. package/src/modules/websocket/websocket.service.ts +692 -0
  201. package/src/utils/errors.ts +7 -0
  202. package/src/utils/pagination.ts +4 -1
  203. package/tests/helpers/db-check.ts +79 -0
  204. package/tests/integration/auth-redis.test.ts +94 -0
  205. package/tests/integration/cache-redis.test.ts +387 -0
  206. package/tests/integration/mongoose-repositories.test.ts +410 -0
  207. package/tests/integration/payment-prisma.test.ts +637 -0
  208. package/tests/integration/queue-bullmq.test.ts +417 -0
  209. package/tests/integration/user-prisma.test.ts +441 -0
  210. package/tests/integration/websocket-socketio.test.ts +552 -0
  211. package/tests/setup.ts +11 -9
  212. package/vitest.config.ts +3 -8
  213. package/npm-cache/_cacache/content-v2/sha512/1c/d0/03440d500a0487621aad1d6402978340698976602046db8e24fa03c01ee6c022c69b0582f969042d9442ee876ac35c038e960dd427d1e622fa24b8eb7dba +0 -0
  214. package/npm-cache/_cacache/content-v2/sha512/42/55/28b493ca491833e5aab0e9c3108d29ab3f36c248ca88f45d4630674fce9130959e56ae308797ac2b6328fa7f09a610b9550ed09cb971d039876d293fc69d +0 -0
  215. package/npm-cache/_cacache/content-v2/sha512/e0/12/f360dc9315ee5f17844a0c8c233ee6bf7c30837c4a02ea0d56c61c7f7ab21c0e958e50ed2c57c59f983c762b93056778c9009b2398ffc26def0183999b13 +0 -0
  216. package/npm-cache/_cacache/content-v2/sha512/ed/b0/fae1161902898f4c913c67d7f6cdf6be0665aec3b389b9c4f4f0a101ca1da59badf1b59c4e0030f5223023b8d63cfe501c46a32c20c895d4fb3f11ca2232 +0 -0
  217. package/npm-cache/_cacache/index-v5/58/94/c2cba79e0f16b4c10e95a87e32255741149e8222cc314a476aab67c39cc0 +0 -5
@@ -1,16 +1,266 @@
1
1
  import { Command } from 'commander';
2
+ import path from 'path';
3
+ import fs from 'fs/promises';
4
+ import ora from 'ora';
5
+ import chalk from 'chalk';
2
6
  import { generateDocs } from '../utils/docs-generator.js';
3
- import { success, error } from '../utils/helpers.js';
7
+ import { success, error, info, warn, getProjectRoot } from '../utils/helpers.js';
4
8
 
5
- export const docsCommand = new Command('docs')
6
- .description('Generate Swagger/OpenAPI documentation')
9
+ export const docsCommand = new Command('docs').description('API documentation commands');
10
+
11
+ // Generate documentation
12
+ docsCommand
13
+ .command('generate')
14
+ .alias('gen')
15
+ .description('Generate OpenAPI/Swagger documentation')
16
+ .option('-o, --output <file>', 'Output file path', 'openapi.json')
17
+ .option('-f, --format <format>', 'Output format: json, yaml', 'json')
18
+ .action(async (options) => {
19
+ try {
20
+ const outputPath = await generateDocs(options.output, false);
21
+
22
+ // Convert to YAML if requested
23
+ if (options.format === 'yaml') {
24
+ const jsonContent = await fs.readFile(outputPath, 'utf-8');
25
+ const spec = JSON.parse(jsonContent);
26
+ const yamlPath = outputPath.replace('.json', '.yaml');
27
+ await fs.writeFile(yamlPath, jsonToYaml(spec));
28
+ success(`YAML documentation generated: ${yamlPath}`);
29
+ }
30
+
31
+ console.log('\n📚 Documentation URLs:');
32
+ info(' Swagger UI: http://localhost:3000/docs');
33
+ info(' OpenAPI JSON: http://localhost:3000/docs/json');
34
+ } catch (err) {
35
+ error(err instanceof Error ? err.message : String(err));
36
+ }
37
+ });
38
+
39
+ // Default action (backwards compatible)
40
+ docsCommand
7
41
  .option('-o, --output <path>', 'Output file path', 'openapi.json')
8
42
  .action(async (options) => {
43
+ if (options.output) {
44
+ try {
45
+ const outputPath = await generateDocs(options.output);
46
+ success(`Documentation written to ${outputPath}`);
47
+ } catch (err) {
48
+ error(err instanceof Error ? err.message : String(err));
49
+ process.exitCode = 1;
50
+ }
51
+ }
52
+ });
53
+
54
+ // Export to Postman/Insomnia
55
+ docsCommand
56
+ .command('export')
57
+ .description('Export documentation to Postman, Insomnia, or YAML')
58
+ .option('-f, --format <format>', 'Export format: postman, insomnia, yaml', 'postman')
59
+ .option('-o, --output <file>', 'Output file path')
60
+ .action(async (options) => {
61
+ const spinner = ora('Exporting documentation...').start();
62
+
9
63
  try {
10
- const outputPath = await generateDocs(options.output);
11
- success(`Documentation written to ${outputPath}`);
64
+ const projectRoot = getProjectRoot();
65
+ const specPath = path.join(projectRoot, 'openapi.json');
66
+
67
+ // Check if spec exists, generate if not
68
+ try {
69
+ await fs.access(specPath);
70
+ } catch {
71
+ spinner.text = 'Generating OpenAPI spec first...';
72
+ await generateDocs('openapi.json', true);
73
+ }
74
+
75
+ const specContent = await fs.readFile(specPath, 'utf-8');
76
+ const spec = JSON.parse(specContent);
77
+
78
+ let output: string;
79
+ let defaultName: string;
80
+
81
+ switch (options.format) {
82
+ case 'postman':
83
+ output = JSON.stringify(convertToPostman(spec), null, 2);
84
+ defaultName = 'postman_collection.json';
85
+ break;
86
+ case 'insomnia':
87
+ output = JSON.stringify(convertToInsomnia(spec), null, 2);
88
+ defaultName = 'insomnia_collection.json';
89
+ break;
90
+ case 'yaml':
91
+ output = jsonToYaml(spec);
92
+ defaultName = 'openapi.yaml';
93
+ break;
94
+ default:
95
+ throw new Error(`Unknown format: ${options.format}`);
96
+ }
97
+
98
+ const outPath = path.join(projectRoot, options.output || defaultName);
99
+ await fs.writeFile(outPath, output);
100
+
101
+ spinner.succeed(`Exported to: ${options.output || defaultName}`);
102
+
103
+ if (options.format === 'postman') {
104
+ info('\n Import in Postman: File > Import > Select file');
105
+ }
12
106
  } catch (err) {
107
+ spinner.fail('Export failed');
13
108
  error(err instanceof Error ? err.message : String(err));
14
- process.exitCode = 1;
15
109
  }
16
110
  });
111
+
112
+ // Show documentation status
113
+ docsCommand
114
+ .command('status')
115
+ .description('Show documentation status')
116
+ .action(async () => {
117
+ const projectRoot = getProjectRoot();
118
+
119
+ console.log(chalk.bold('\n📊 Documentation Status\n'));
120
+
121
+ // Check OpenAPI spec
122
+ const specPath = path.join(projectRoot, 'openapi.json');
123
+ try {
124
+ const stat = await fs.stat(specPath);
125
+ success(
126
+ `openapi.json exists (${formatBytes(stat.size)}, modified ${formatDate(stat.mtime)})`
127
+ );
128
+
129
+ const content = await fs.readFile(specPath, 'utf-8');
130
+ const spec = JSON.parse(content);
131
+ const pathCount = Object.keys(spec.paths || {}).length;
132
+ info(` ${pathCount} endpoints documented`);
133
+ } catch {
134
+ warn('openapi.json not found - run "servcraft docs generate"');
135
+ }
136
+
137
+ console.log('\n📌 Commands:');
138
+ info(' servcraft docs generate Generate OpenAPI spec');
139
+ info(' servcraft docs export Export to Postman/Insomnia');
140
+ });
141
+
142
+ // Helper functions
143
+ function jsonToYaml(obj: unknown, indent = 0): string {
144
+ const spaces = ' '.repeat(indent);
145
+
146
+ if (obj === null || obj === undefined) return 'null';
147
+ if (typeof obj === 'string') {
148
+ if (obj.includes('\n') || obj.includes(':') || obj.includes('#')) {
149
+ return `"${obj.replace(/"/g, '\\"')}"`;
150
+ }
151
+ return obj || '""';
152
+ }
153
+ if (typeof obj === 'number' || typeof obj === 'boolean') return String(obj);
154
+
155
+ if (Array.isArray(obj)) {
156
+ if (obj.length === 0) return '[]';
157
+ return obj.map((item) => `${spaces}- ${jsonToYaml(item, indent + 1).trimStart()}`).join('\n');
158
+ }
159
+
160
+ if (typeof obj === 'object') {
161
+ const entries = Object.entries(obj);
162
+ if (entries.length === 0) return '{}';
163
+ return entries
164
+ .map(([key, value]) => {
165
+ const valueStr = jsonToYaml(value, indent + 1);
166
+ if (
167
+ typeof value === 'object' &&
168
+ value !== null &&
169
+ !Array.isArray(value) &&
170
+ Object.keys(value).length > 0
171
+ ) {
172
+ return `${spaces}${key}:\n${valueStr}`;
173
+ }
174
+ return `${spaces}${key}: ${valueStr}`;
175
+ })
176
+ .join('\n');
177
+ }
178
+
179
+ return String(obj);
180
+ }
181
+
182
+ interface OpenApiSpec {
183
+ info: { title: string; description?: string; version: string };
184
+ paths: Record<
185
+ string,
186
+ Record<string, { summary?: string; description?: string; requestBody?: unknown }>
187
+ >;
188
+ servers?: Array<{ url: string }>;
189
+ }
190
+
191
+ function convertToPostman(spec: OpenApiSpec): Record<string, unknown> {
192
+ const baseUrl = spec.servers?.[0]?.url || 'http://localhost:3000';
193
+ const items: Array<Record<string, unknown>> = [];
194
+
195
+ for (const [pathUrl, methods] of Object.entries(spec.paths || {})) {
196
+ for (const [method, details] of Object.entries(methods)) {
197
+ items.push({
198
+ name: details.summary || `${method.toUpperCase()} ${pathUrl}`,
199
+ request: {
200
+ method: method.toUpperCase(),
201
+ header: [
202
+ { key: 'Content-Type', value: 'application/json' },
203
+ { key: 'Authorization', value: 'Bearer {{token}}' },
204
+ ],
205
+ url: {
206
+ raw: `{{baseUrl}}${pathUrl}`,
207
+ host: ['{{baseUrl}}'],
208
+ path: pathUrl.split('/').filter(Boolean),
209
+ },
210
+ ...(details.requestBody ? { body: { mode: 'raw', raw: '{}' } } : {}),
211
+ },
212
+ });
213
+ }
214
+ }
215
+
216
+ return {
217
+ info: {
218
+ name: spec.info.title,
219
+ schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json',
220
+ },
221
+ item: items,
222
+ variable: [
223
+ { key: 'baseUrl', value: baseUrl },
224
+ { key: 'token', value: '' },
225
+ ],
226
+ };
227
+ }
228
+
229
+ function convertToInsomnia(spec: OpenApiSpec): Record<string, unknown> {
230
+ const baseUrl = spec.servers?.[0]?.url || 'http://localhost:3000';
231
+ const resources: Array<Record<string, unknown>> = [
232
+ { _type: 'environment', name: 'Base Environment', data: { baseUrl, token: '' } },
233
+ ];
234
+
235
+ for (const [pathUrl, methods] of Object.entries(spec.paths || {})) {
236
+ for (const [method, details] of Object.entries(methods)) {
237
+ resources.push({
238
+ _type: 'request',
239
+ name: details.summary || `${method.toUpperCase()} ${pathUrl}`,
240
+ method: method.toUpperCase(),
241
+ url: `{{ baseUrl }}${pathUrl}`,
242
+ headers: [
243
+ { name: 'Content-Type', value: 'application/json' },
244
+ { name: 'Authorization', value: 'Bearer {{ token }}' },
245
+ ],
246
+ });
247
+ }
248
+ }
249
+
250
+ return { _type: 'export', __export_format: 4, resources };
251
+ }
252
+
253
+ function formatBytes(bytes: number): string {
254
+ if (bytes < 1024) return `${bytes} B`;
255
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
256
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
257
+ }
258
+
259
+ function formatDate(date: Date): string {
260
+ return date.toLocaleDateString('en-US', {
261
+ month: 'short',
262
+ day: 'numeric',
263
+ hour: '2-digit',
264
+ minute: '2-digit',
265
+ });
266
+ }
@@ -11,7 +11,6 @@ import {
11
11
  writeFile,
12
12
  success,
13
13
  error,
14
- warn,
15
14
  info,
16
15
  getModulesDir,
17
16
  } from '../utils/helpers.js';
@@ -27,7 +26,6 @@ import { prismaModelTemplate } from '../templates/prisma-model.js';
27
26
  import { dynamicTypesTemplate } from '../templates/dynamic-types.js';
28
27
  import { dynamicSchemasTemplate, type ValidatorType } from '../templates/dynamic-schemas.js';
29
28
  import { dynamicPrismaTemplate } from '../templates/dynamic-prisma.js';
30
- import { generateDocs } from '../utils/docs-generator.js';
31
29
 
32
30
  export const generateCommand = new Command('generate')
33
31
  .alias('g')
@@ -37,7 +35,9 @@ export const generateCommand = new Command('generate')
37
35
  generateCommand
38
36
  .command('module <name> [fields...]')
39
37
  .alias('m')
40
- .description('Generate a complete module with controller, service, repository, types, schemas, and routes')
38
+ .description(
39
+ 'Generate a complete module with controller, service, repository, types, schemas, and routes'
40
+ )
41
41
  .option('--no-routes', 'Skip routes generation')
42
42
  .option('--no-repository', 'Skip repository generation')
43
43
  .option('--prisma', 'Generate Prisma model suggestion')
@@ -88,8 +88,14 @@ generateCommand
88
88
  ? dynamicSchemasTemplate(kebabName, pascalName, camelName, fields, validatorType)
89
89
  : schemasTemplate(kebabName, pascalName, camelName),
90
90
  },
91
- { name: `${kebabName}.service.ts`, content: serviceTemplate(kebabName, pascalName, camelName) },
92
- { name: `${kebabName}.controller.ts`, content: controllerTemplate(kebabName, pascalName, camelName) },
91
+ {
92
+ name: `${kebabName}.service.ts`,
93
+ content: serviceTemplate(kebabName, pascalName, camelName),
94
+ },
95
+ {
96
+ name: `${kebabName}.controller.ts`,
97
+ content: controllerTemplate(kebabName, pascalName, camelName),
98
+ },
93
99
  { name: 'index.ts', content: moduleIndexTemplate(kebabName, pascalName, camelName) },
94
100
  ];
95
101
 
@@ -103,7 +109,7 @@ generateCommand
103
109
  if (options.routes !== false) {
104
110
  files.push({
105
111
  name: `${kebabName}.routes.ts`,
106
- content: routesTemplate(kebabName, pascalName, camelName, pluralName, fields),
112
+ content: routesTemplate(kebabName, pascalName, camelName, pluralName),
107
113
  });
108
114
  }
109
115
 
@@ -155,19 +161,6 @@ generateCommand
155
161
  info(` ${hasFields ? '3' : '4'}. Add the Prisma model to schema.prisma`);
156
162
  info(` ${hasFields ? '4' : '5'}. Run: npm run db:migrate`);
157
163
  }
158
-
159
- const { generateDocsNow } = await inquirer.prompt<{ generateDocsNow: boolean }>([
160
- {
161
- type: 'confirm',
162
- name: 'generateDocsNow',
163
- message: 'Generate Swagger/OpenAPI documentation now?',
164
- default: true,
165
- },
166
- ]);
167
-
168
- if (generateDocsNow) {
169
- await generateDocs('openapi.json', true);
170
- }
171
164
  } catch (err) {
172
165
  spinner.fail('Failed to generate module');
173
166
  error(err instanceof Error ? err.message : String(err));