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.
- package/.claude/settings.local.json +30 -0
- package/.github/CODEOWNERS +18 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
- package/.github/dependabot.yml +59 -0
- package/.github/workflows/ci.yml +188 -0
- package/.github/workflows/release.yml +195 -0
- package/AUDIT.md +602 -0
- package/LICENSE +21 -0
- package/README.md +1102 -1
- package/dist/cli/index.cjs +2026 -2168
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +2026 -2168
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +595 -616
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -52
- package/dist/index.d.ts +114 -52
- package/dist/index.js +595 -616
- package/dist/index.js.map +1 -1
- package/docs/CLI-001_MULTI_DB_PLAN.md +546 -0
- package/docs/DATABASE_MULTI_ORM.md +399 -0
- package/docs/PHASE1_BREAKDOWN.md +346 -0
- package/docs/PROGRESS.md +550 -0
- package/docs/modules/ANALYTICS.md +226 -0
- package/docs/modules/API-VERSIONING.md +252 -0
- package/docs/modules/AUDIT.md +192 -0
- package/docs/modules/AUTH.md +431 -0
- package/docs/modules/CACHE.md +346 -0
- package/docs/modules/EMAIL.md +254 -0
- package/docs/modules/FEATURE-FLAG.md +291 -0
- package/docs/modules/I18N.md +294 -0
- package/docs/modules/MEDIA-PROCESSING.md +281 -0
- package/docs/modules/MFA.md +266 -0
- package/docs/modules/NOTIFICATION.md +311 -0
- package/docs/modules/OAUTH.md +237 -0
- package/docs/modules/PAYMENT.md +804 -0
- package/docs/modules/QUEUE.md +540 -0
- package/docs/modules/RATE-LIMIT.md +339 -0
- package/docs/modules/SEARCH.md +288 -0
- package/docs/modules/SECURITY.md +327 -0
- package/docs/modules/SESSION.md +382 -0
- package/docs/modules/SWAGGER.md +305 -0
- package/docs/modules/UPLOAD.md +296 -0
- package/docs/modules/USER.md +505 -0
- package/docs/modules/VALIDATION.md +294 -0
- package/docs/modules/WEBHOOK.md +270 -0
- package/docs/modules/WEBSOCKET.md +691 -0
- package/package.json +53 -38
- package/prisma/schema.prisma +395 -1
- package/src/cli/commands/add-module.ts +520 -87
- package/src/cli/commands/db.ts +3 -4
- package/src/cli/commands/docs.ts +256 -6
- package/src/cli/commands/generate.ts +12 -19
- package/src/cli/commands/init.ts +384 -214
- package/src/cli/index.ts +0 -4
- package/src/cli/templates/repository.ts +6 -1
- package/src/cli/templates/routes.ts +6 -21
- package/src/cli/utils/docs-generator.ts +6 -7
- package/src/cli/utils/env-manager.ts +717 -0
- package/src/cli/utils/field-parser.ts +16 -7
- package/src/cli/utils/interactive-prompt.ts +223 -0
- package/src/cli/utils/template-manager.ts +346 -0
- package/src/config/database.config.ts +183 -0
- package/src/config/env.ts +0 -10
- package/src/config/index.ts +0 -14
- package/src/core/server.ts +1 -1
- package/src/database/adapters/mongoose.adapter.ts +132 -0
- package/src/database/adapters/prisma.adapter.ts +118 -0
- package/src/database/connection.ts +190 -0
- package/src/database/interfaces/database.interface.ts +85 -0
- package/src/database/interfaces/index.ts +7 -0
- package/src/database/interfaces/repository.interface.ts +129 -0
- package/src/database/models/mongoose/index.ts +7 -0
- package/src/database/models/mongoose/payment.schema.ts +347 -0
- package/src/database/models/mongoose/user.schema.ts +154 -0
- package/src/database/prisma.ts +1 -4
- package/src/database/redis.ts +101 -0
- package/src/database/repositories/mongoose/index.ts +7 -0
- package/src/database/repositories/mongoose/payment.repository.ts +380 -0
- package/src/database/repositories/mongoose/user.repository.ts +255 -0
- package/src/database/seed.ts +6 -1
- package/src/index.ts +9 -20
- package/src/middleware/security.ts +2 -6
- package/src/modules/analytics/analytics.routes.ts +80 -0
- package/src/modules/analytics/analytics.service.ts +364 -0
- package/src/modules/analytics/index.ts +18 -0
- package/src/modules/analytics/types.ts +180 -0
- package/src/modules/api-versioning/index.ts +15 -0
- package/src/modules/api-versioning/types.ts +86 -0
- package/src/modules/api-versioning/versioning.middleware.ts +120 -0
- package/src/modules/api-versioning/versioning.routes.ts +54 -0
- package/src/modules/api-versioning/versioning.service.ts +189 -0
- package/src/modules/audit/audit.repository.ts +206 -0
- package/src/modules/audit/audit.service.ts +27 -59
- package/src/modules/auth/auth.controller.ts +2 -2
- package/src/modules/auth/auth.middleware.ts +3 -9
- package/src/modules/auth/auth.routes.ts +10 -107
- package/src/modules/auth/auth.service.ts +126 -23
- package/src/modules/auth/index.ts +3 -4
- package/src/modules/cache/cache.service.ts +367 -0
- package/src/modules/cache/index.ts +10 -0
- package/src/modules/cache/types.ts +44 -0
- package/src/modules/email/email.service.ts +3 -10
- package/src/modules/email/templates.ts +2 -8
- package/src/modules/feature-flag/feature-flag.repository.ts +303 -0
- package/src/modules/feature-flag/feature-flag.routes.ts +247 -0
- package/src/modules/feature-flag/feature-flag.service.ts +566 -0
- package/src/modules/feature-flag/index.ts +20 -0
- package/src/modules/feature-flag/types.ts +192 -0
- package/src/modules/i18n/i18n.middleware.ts +186 -0
- package/src/modules/i18n/i18n.routes.ts +191 -0
- package/src/modules/i18n/i18n.service.ts +456 -0
- package/src/modules/i18n/index.ts +18 -0
- package/src/modules/i18n/types.ts +118 -0
- package/src/modules/media-processing/index.ts +17 -0
- package/src/modules/media-processing/media-processing.routes.ts +111 -0
- package/src/modules/media-processing/media-processing.service.ts +245 -0
- package/src/modules/media-processing/types.ts +156 -0
- package/src/modules/mfa/index.ts +20 -0
- package/src/modules/mfa/mfa.repository.ts +206 -0
- package/src/modules/mfa/mfa.routes.ts +595 -0
- package/src/modules/mfa/mfa.service.ts +572 -0
- package/src/modules/mfa/totp.ts +150 -0
- package/src/modules/mfa/types.ts +57 -0
- package/src/modules/notification/index.ts +20 -0
- package/src/modules/notification/notification.repository.ts +356 -0
- package/src/modules/notification/notification.service.ts +483 -0
- package/src/modules/notification/types.ts +119 -0
- package/src/modules/oauth/index.ts +20 -0
- package/src/modules/oauth/oauth.repository.ts +219 -0
- package/src/modules/oauth/oauth.routes.ts +446 -0
- package/src/modules/oauth/oauth.service.ts +293 -0
- package/src/modules/oauth/providers/apple.provider.ts +250 -0
- package/src/modules/oauth/providers/facebook.provider.ts +181 -0
- package/src/modules/oauth/providers/github.provider.ts +248 -0
- package/src/modules/oauth/providers/google.provider.ts +189 -0
- package/src/modules/oauth/providers/twitter.provider.ts +214 -0
- package/src/modules/oauth/types.ts +94 -0
- package/src/modules/payment/index.ts +19 -0
- package/src/modules/payment/payment.repository.ts +733 -0
- package/src/modules/payment/payment.routes.ts +390 -0
- package/src/modules/payment/payment.service.ts +354 -0
- package/src/modules/payment/providers/mobile-money.provider.ts +274 -0
- package/src/modules/payment/providers/paypal.provider.ts +190 -0
- package/src/modules/payment/providers/stripe.provider.ts +215 -0
- package/src/modules/payment/types.ts +140 -0
- package/src/modules/queue/cron.ts +438 -0
- package/src/modules/queue/index.ts +87 -0
- package/src/modules/queue/queue.routes.ts +600 -0
- package/src/modules/queue/queue.service.ts +842 -0
- package/src/modules/queue/types.ts +222 -0
- package/src/modules/queue/workers.ts +366 -0
- package/src/modules/rate-limit/index.ts +59 -0
- package/src/modules/rate-limit/rate-limit.middleware.ts +134 -0
- package/src/modules/rate-limit/rate-limit.routes.ts +269 -0
- package/src/modules/rate-limit/rate-limit.service.ts +348 -0
- package/src/modules/rate-limit/stores/memory.store.ts +165 -0
- package/src/modules/rate-limit/stores/redis.store.ts +322 -0
- package/src/modules/rate-limit/types.ts +153 -0
- package/src/modules/search/adapters/elasticsearch.adapter.ts +326 -0
- package/src/modules/search/adapters/meilisearch.adapter.ts +261 -0
- package/src/modules/search/adapters/memory.adapter.ts +278 -0
- package/src/modules/search/index.ts +21 -0
- package/src/modules/search/search.service.ts +234 -0
- package/src/modules/search/types.ts +214 -0
- package/src/modules/security/index.ts +40 -0
- package/src/modules/security/sanitize.ts +223 -0
- package/src/modules/security/security-audit.service.ts +388 -0
- package/src/modules/security/security.middleware.ts +398 -0
- package/src/modules/session/index.ts +3 -0
- package/src/modules/session/session.repository.ts +159 -0
- package/src/modules/session/session.service.ts +340 -0
- package/src/modules/session/types.ts +38 -0
- package/src/modules/swagger/index.ts +7 -1
- package/src/modules/swagger/schema-builder.ts +16 -4
- package/src/modules/swagger/swagger.service.ts +9 -10
- package/src/modules/swagger/types.ts +0 -2
- package/src/modules/upload/index.ts +14 -0
- package/src/modules/upload/types.ts +83 -0
- package/src/modules/upload/upload.repository.ts +199 -0
- package/src/modules/upload/upload.routes.ts +311 -0
- package/src/modules/upload/upload.service.ts +448 -0
- package/src/modules/user/index.ts +3 -3
- package/src/modules/user/user.controller.ts +15 -9
- package/src/modules/user/user.repository.ts +237 -113
- package/src/modules/user/user.routes.ts +39 -164
- package/src/modules/user/user.service.ts +4 -3
- package/src/modules/validation/validator.ts +12 -17
- package/src/modules/webhook/index.ts +91 -0
- package/src/modules/webhook/retry.ts +196 -0
- package/src/modules/webhook/signature.ts +135 -0
- package/src/modules/webhook/types.ts +181 -0
- package/src/modules/webhook/webhook.repository.ts +358 -0
- package/src/modules/webhook/webhook.routes.ts +442 -0
- package/src/modules/webhook/webhook.service.ts +457 -0
- package/src/modules/websocket/features.ts +504 -0
- package/src/modules/websocket/index.ts +106 -0
- package/src/modules/websocket/middlewares.ts +298 -0
- package/src/modules/websocket/types.ts +181 -0
- package/src/modules/websocket/websocket.service.ts +692 -0
- package/src/utils/errors.ts +7 -0
- package/src/utils/pagination.ts +4 -1
- package/tests/helpers/db-check.ts +79 -0
- package/tests/integration/auth-redis.test.ts +94 -0
- package/tests/integration/cache-redis.test.ts +387 -0
- package/tests/integration/mongoose-repositories.test.ts +410 -0
- package/tests/integration/payment-prisma.test.ts +637 -0
- package/tests/integration/queue-bullmq.test.ts +417 -0
- package/tests/integration/user-prisma.test.ts +441 -0
- package/tests/integration/websocket-socketio.test.ts +552 -0
- package/tests/setup.ts +11 -9
- package/vitest.config.ts +3 -8
- package/npm-cache/_cacache/content-v2/sha512/1c/d0/03440d500a0487621aad1d6402978340698976602046db8e24fa03c01ee6c022c69b0582f969042d9442ee876ac35c038e960dd427d1e622fa24b8eb7dba +0 -0
- package/npm-cache/_cacache/content-v2/sha512/42/55/28b493ca491833e5aab0e9c3108d29ab3f36c248ca88f45d4630674fce9130959e56ae308797ac2b6328fa7f09a610b9550ed09cb971d039876d293fc69d +0 -0
- package/npm-cache/_cacache/content-v2/sha512/e0/12/f360dc9315ee5f17844a0c8c233ee6bf7c30837c4a02ea0d56c61c7f7ab21c0e958e50ed2c57c59f983c762b93056778c9009b2398ffc26def0183999b13 +0 -0
- package/npm-cache/_cacache/content-v2/sha512/ed/b0/fae1161902898f4c913c67d7f6cdf6be0665aec3b389b9c4f4f0a101ca1da59badf1b59c4e0030f5223023b8d63cfe501c46a32c20c895d4fb3f11ca2232 +0 -0
- package/npm-cache/_cacache/index-v5/58/94/c2cba79e0f16b4c10e95a87e32255741149e8222cc314a476aab67c39cc0 +0 -5
package/src/cli/commands/docs.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
11
|
-
|
|
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(
|
|
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
|
-
{
|
|
92
|
-
|
|
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
|
|
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));
|