@hazeljs/cli 0.2.0-alpha.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.
Files changed (121) hide show
  1. package/@template/.eslintrc.js +36 -0
  2. package/@template/.lintstagedrc +6 -0
  3. package/@template/README.md +61 -0
  4. package/@template/jest.config.js +28 -0
  5. package/@template/jest.setup.js +81 -0
  6. package/@template/package.json +34 -0
  7. package/@template/src/app.module.ts +7 -0
  8. package/@template/src/hello.controller.ts +9 -0
  9. package/@template/src/index.ts +18 -0
  10. package/@template/tsconfig.json +25 -0
  11. package/LICENSE +192 -0
  12. package/README.md +683 -0
  13. package/dist/commands/add.d.ts +2 -0
  14. package/dist/commands/add.js +176 -0
  15. package/dist/commands/add.test.d.ts +1 -0
  16. package/dist/commands/add.test.js +51 -0
  17. package/dist/commands/build.d.ts +2 -0
  18. package/dist/commands/build.js +52 -0
  19. package/dist/commands/generate-agent.d.ts +2 -0
  20. package/dist/commands/generate-agent.js +58 -0
  21. package/dist/commands/generate-agent.test.d.ts +1 -0
  22. package/dist/commands/generate-agent.test.js +36 -0
  23. package/dist/commands/generate-ai-service.d.ts +2 -0
  24. package/dist/commands/generate-ai-service.js +48 -0
  25. package/dist/commands/generate-ai-service.test.d.ts +1 -0
  26. package/dist/commands/generate-ai-service.test.js +41 -0
  27. package/dist/commands/generate-app.d.ts +2 -0
  28. package/dist/commands/generate-app.js +448 -0
  29. package/dist/commands/generate-auth.d.ts +2 -0
  30. package/dist/commands/generate-auth.js +194 -0
  31. package/dist/commands/generate-auth.test.d.ts +1 -0
  32. package/dist/commands/generate-auth.test.js +48 -0
  33. package/dist/commands/generate-cache.d.ts +2 -0
  34. package/dist/commands/generate-cache.js +64 -0
  35. package/dist/commands/generate-cache.test.d.ts +1 -0
  36. package/dist/commands/generate-cache.test.js +36 -0
  37. package/dist/commands/generate-config.d.ts +2 -0
  38. package/dist/commands/generate-config.js +57 -0
  39. package/dist/commands/generate-config.test.d.ts +1 -0
  40. package/dist/commands/generate-config.test.js +35 -0
  41. package/dist/commands/generate-controller.d.ts +2 -0
  42. package/dist/commands/generate-controller.js +60 -0
  43. package/dist/commands/generate-controller.test.d.ts +1 -0
  44. package/dist/commands/generate-controller.test.js +48 -0
  45. package/dist/commands/generate-cron.d.ts +2 -0
  46. package/dist/commands/generate-cron.js +59 -0
  47. package/dist/commands/generate-cron.test.d.ts +1 -0
  48. package/dist/commands/generate-cron.test.js +42 -0
  49. package/dist/commands/generate-crud.d.ts +2 -0
  50. package/dist/commands/generate-crud.js +177 -0
  51. package/dist/commands/generate-crud.test.d.ts +1 -0
  52. package/dist/commands/generate-crud.test.js +52 -0
  53. package/dist/commands/generate-discovery.d.ts +2 -0
  54. package/dist/commands/generate-discovery.js +61 -0
  55. package/dist/commands/generate-discovery.test.d.ts +1 -0
  56. package/dist/commands/generate-discovery.test.js +36 -0
  57. package/dist/commands/generate-dto.d.ts +2 -0
  58. package/dist/commands/generate-dto.js +69 -0
  59. package/dist/commands/generate-dto.test.d.ts +1 -0
  60. package/dist/commands/generate-dto.test.js +44 -0
  61. package/dist/commands/generate-exception-filter.d.ts +2 -0
  62. package/dist/commands/generate-exception-filter.js +48 -0
  63. package/dist/commands/generate-exception-filter.test.d.ts +1 -0
  64. package/dist/commands/generate-exception-filter.test.js +43 -0
  65. package/dist/commands/generate-guard.d.ts +2 -0
  66. package/dist/commands/generate-guard.js +36 -0
  67. package/dist/commands/generate-guard.test.d.ts +1 -0
  68. package/dist/commands/generate-guard.test.js +41 -0
  69. package/dist/commands/generate-interceptor.d.ts +2 -0
  70. package/dist/commands/generate-interceptor.js +37 -0
  71. package/dist/commands/generate-interceptor.test.d.ts +1 -0
  72. package/dist/commands/generate-interceptor.test.js +41 -0
  73. package/dist/commands/generate-middleware.d.ts +2 -0
  74. package/dist/commands/generate-middleware.js +46 -0
  75. package/dist/commands/generate-middleware.test.d.ts +1 -0
  76. package/dist/commands/generate-middleware.test.js +41 -0
  77. package/dist/commands/generate-module.d.ts +2 -0
  78. package/dist/commands/generate-module.js +106 -0
  79. package/dist/commands/generate-module.test.d.ts +1 -0
  80. package/dist/commands/generate-module.test.js +54 -0
  81. package/dist/commands/generate-pipe.d.ts +2 -0
  82. package/dist/commands/generate-pipe.js +33 -0
  83. package/dist/commands/generate-pipe.test.d.ts +1 -0
  84. package/dist/commands/generate-pipe.test.js +35 -0
  85. package/dist/commands/generate-rag.d.ts +2 -0
  86. package/dist/commands/generate-rag.js +66 -0
  87. package/dist/commands/generate-rag.test.d.ts +1 -0
  88. package/dist/commands/generate-rag.test.js +35 -0
  89. package/dist/commands/generate-repository.d.ts +2 -0
  90. package/dist/commands/generate-repository.js +40 -0
  91. package/dist/commands/generate-repository.test.d.ts +1 -0
  92. package/dist/commands/generate-repository.test.js +41 -0
  93. package/dist/commands/generate-serverless-handler.d.ts +2 -0
  94. package/dist/commands/generate-serverless-handler.js +46 -0
  95. package/dist/commands/generate-serverless-handler.test.d.ts +1 -0
  96. package/dist/commands/generate-serverless-handler.test.js +42 -0
  97. package/dist/commands/generate-service.d.ts +2 -0
  98. package/dist/commands/generate-service.js +52 -0
  99. package/dist/commands/generate-service.test.d.ts +1 -0
  100. package/dist/commands/generate-service.test.js +41 -0
  101. package/dist/commands/generate-websocket-gateway.d.ts +2 -0
  102. package/dist/commands/generate-websocket-gateway.js +47 -0
  103. package/dist/commands/generate-websocket-gateway.test.d.ts +1 -0
  104. package/dist/commands/generate-websocket-gateway.test.js +41 -0
  105. package/dist/commands/info.d.ts +2 -0
  106. package/dist/commands/info.js +91 -0
  107. package/dist/commands/pdf-to-audio.d.ts +2 -0
  108. package/dist/commands/pdf-to-audio.js +170 -0
  109. package/dist/commands/start.d.ts +2 -0
  110. package/dist/commands/start.js +61 -0
  111. package/dist/commands/test.d.ts +2 -0
  112. package/dist/commands/test.js +63 -0
  113. package/dist/index.d.ts +2 -0
  114. package/dist/index.js +75 -0
  115. package/dist/index.test.d.ts +1 -0
  116. package/dist/index.test.js +93 -0
  117. package/dist/utils/generator.d.ts +25 -0
  118. package/dist/utils/generator.js +107 -0
  119. package/dist/utils/generator.test.d.ts +1 -0
  120. package/dist/utils/generator.test.js +137 -0
  121. package/package.json +73 -0
@@ -0,0 +1,448 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateApp = generateApp;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const child_process_1 = require("child_process");
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const inquirer_1 = __importDefault(require("inquirer"));
12
+ function copyRecursiveSync(src, dest) {
13
+ if (fs_1.default.existsSync(src)) {
14
+ fs_1.default.mkdirSync(dest, { recursive: true });
15
+ for (const entry of fs_1.default.readdirSync(src)) {
16
+ const srcPath = path_1.default.join(src, entry);
17
+ const destPath = path_1.default.join(dest, entry);
18
+ if (fs_1.default.lstatSync(srcPath).isDirectory()) {
19
+ copyRecursiveSync(srcPath, destPath);
20
+ }
21
+ else {
22
+ fs_1.default.copyFileSync(srcPath, destPath);
23
+ }
24
+ }
25
+ }
26
+ }
27
+ function updatePackageJson(destPath, appName, description) {
28
+ const packageJsonPath = path_1.default.join(destPath, 'package.json');
29
+ if (fs_1.default.existsSync(packageJsonPath)) {
30
+ const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
31
+ packageJson.name = appName;
32
+ packageJson.description = description;
33
+ packageJson.version = '0.1.0';
34
+ fs_1.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
35
+ }
36
+ }
37
+ function scaffoldPackageBoilerplate(destPath, packages) {
38
+ const srcPath = path_1.default.join(destPath, 'src');
39
+ // Build up enhanced app.module.ts imports based on selected packages
40
+ const imports = ["import { HazelModule } from '@hazeljs/core';"];
41
+ const moduleImports = [];
42
+ const controllers = [];
43
+ // Always include the default HelloController
44
+ imports.push("import { HelloController } from './hello.controller';");
45
+ controllers.push('HelloController');
46
+ if (packages.includes('@hazeljs/config')) {
47
+ imports.push("import { ConfigModule } from '@hazeljs/config';");
48
+ moduleImports.push("ConfigModule.forRoot({ envFilePath: '.env' })");
49
+ // Create .env file
50
+ fs_1.default.writeFileSync(path_1.default.join(destPath, '.env'), 'PORT=3000\nNODE_ENV=development\n');
51
+ fs_1.default.writeFileSync(path_1.default.join(destPath, '.env.example'), 'PORT=3000\nNODE_ENV=development\n');
52
+ console.log(chalk_1.default.green(' ✓ Created .env and .env.example'));
53
+ }
54
+ if (packages.includes('@hazeljs/swagger')) {
55
+ imports.push("import { SwaggerModule } from '@hazeljs/swagger';");
56
+ moduleImports.push('SwaggerModule');
57
+ }
58
+ if (packages.includes('@hazeljs/prisma')) {
59
+ imports.push("import { PrismaModule } from '@hazeljs/prisma';");
60
+ moduleImports.push('PrismaModule');
61
+ }
62
+ if (packages.includes('@hazeljs/typeorm')) {
63
+ imports.push("import { TypeOrmModule } from '@hazeljs/typeorm';");
64
+ moduleImports.push('TypeOrmModule');
65
+ }
66
+ if (packages.includes('@hazeljs/audit')) {
67
+ imports.push("import { AuditModule, ConsoleAuditTransport } from '@hazeljs/audit';");
68
+ moduleImports.push("AuditModule.forRoot({ transports: [new ConsoleAuditTransport()] })");
69
+ }
70
+ if (packages.includes('@hazeljs/auth')) {
71
+ imports.push("import { JwtModule } from '@hazeljs/auth';");
72
+ moduleImports.push("JwtModule.forRoot({ secret: process.env.JWT_SECRET || 'change-me', expiresIn: '1d' })");
73
+ }
74
+ if (packages.includes('@hazeljs/oauth')) {
75
+ imports.push("import { OAuthModule } from '@hazeljs/oauth';");
76
+ moduleImports.push("OAuthModule.forRoot({ providers: { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, redirectUri: process.env.OAUTH_REDIRECT_URI! } } })");
77
+ }
78
+ if (packages.includes('@hazeljs/cache')) {
79
+ imports.push("import { CacheModule } from '@hazeljs/cache';");
80
+ moduleImports.push('CacheModule');
81
+ }
82
+ if (packages.includes('@hazeljs/cron')) {
83
+ imports.push("import { CronModule } from '@hazeljs/cron';");
84
+ moduleImports.push('CronModule');
85
+ }
86
+ if (packages.includes('@hazeljs/websocket')) {
87
+ imports.push("import { WebSocketModule } from '@hazeljs/websocket';");
88
+ moduleImports.push('WebSocketModule');
89
+ }
90
+ if (packages.includes('@hazeljs/ai')) {
91
+ imports.push("import { AIModule } from '@hazeljs/ai';");
92
+ moduleImports.push('AIModule');
93
+ }
94
+ if (packages.includes('@hazeljs/agent')) {
95
+ imports.push("import { AgentModule } from '@hazeljs/agent';");
96
+ moduleImports.push('AgentModule');
97
+ }
98
+ if (packages.includes('@hazeljs/rag')) {
99
+ imports.push("import { RAGModule } from '@hazeljs/rag';");
100
+ moduleImports.push('RAGModule');
101
+ }
102
+ if (packages.includes('@hazeljs/discovery')) {
103
+ // Discovery uses ServiceRegistry/DiscoveryClient programmatically - no module import
104
+ }
105
+ if (packages.includes('@hazeljs/prompts')) {
106
+ // Prompts is a library (PromptTemplate, PromptRegistry) - no module import
107
+ }
108
+ if (packages.includes('@hazeljs/mcp')) {
109
+ // MCP uses createMcpServer() programmatically - no module import
110
+ }
111
+ if (packages.includes('@hazeljs/pdf-to-audio')) {
112
+ imports.push("import { PdfToAudioModule } from '@hazeljs/pdf-to-audio';");
113
+ moduleImports.push('PdfToAudioModule');
114
+ }
115
+ if (packages.includes('@hazeljs/data')) {
116
+ imports.push("import { DataModule } from '@hazeljs/data';");
117
+ moduleImports.push('DataModule.forRoot()');
118
+ }
119
+ if (packages.includes('@hazeljs/event-emitter')) {
120
+ imports.push("import { EventEmitterModule } from '@hazeljs/event-emitter';");
121
+ moduleImports.push('EventEmitterModule.forRoot()');
122
+ }
123
+ if (packages.includes('@hazeljs/gateway')) {
124
+ imports.push("import { GatewayModule } from '@hazeljs/gateway';");
125
+ moduleImports.push('GatewayModule');
126
+ }
127
+ if (packages.includes('@hazeljs/graphql')) {
128
+ imports.push("import { GraphQLModule } from '@hazeljs/graphql';");
129
+ moduleImports.push('GraphQLModule');
130
+ }
131
+ if (packages.includes('@hazeljs/grpc')) {
132
+ imports.push("import { GrpcModule } from '@hazeljs/grpc';");
133
+ moduleImports.push('GrpcModule');
134
+ }
135
+ if (packages.includes('@hazeljs/kafka')) {
136
+ imports.push("import { KafkaModule } from '@hazeljs/kafka';");
137
+ moduleImports.push('KafkaModule');
138
+ }
139
+ if (packages.includes('@hazeljs/messaging')) {
140
+ imports.push("import { MessagingModule } from '@hazeljs/messaging';");
141
+ moduleImports.push('MessagingModule');
142
+ }
143
+ if (packages.includes('@hazeljs/ml')) {
144
+ imports.push("import { MLModule } from '@hazeljs/ml';");
145
+ moduleImports.push('MLModule.forRoot()');
146
+ }
147
+ if (packages.includes('@hazeljs/queue')) {
148
+ imports.push("import { QueueModule } from '@hazeljs/queue';");
149
+ moduleImports.push('QueueModule');
150
+ }
151
+ if (packages.includes('@hazeljs/resilience')) {
152
+ // Resilience is a library of decorators, not a module - no import needed in app.module
153
+ // User can import { CircuitBreaker, WithRetry } in their services
154
+ }
155
+ // Generate the enhanced app.module.ts
156
+ const importsSection = moduleImports.length > 0
157
+ ? `\n imports: [\n ${moduleImports.join(',\n ')},\n ],`
158
+ : '';
159
+ const appModule = `${imports.join('\n')}
160
+
161
+ @HazelModule({${importsSection}
162
+ controllers: [${controllers.join(', ')}],
163
+ })
164
+ export class AppModule {}
165
+ `;
166
+ fs_1.default.writeFileSync(path_1.default.join(srcPath, 'app.module.ts'), appModule);
167
+ console.log(chalk_1.default.green(' ✓ Updated app.module.ts with package imports'));
168
+ // Update index.ts / main.ts if swagger is selected
169
+ if (packages.includes('@hazeljs/swagger')) {
170
+ const mainContent = `import 'reflect-metadata';
171
+ import { HazelApp } from '@hazeljs/core';
172
+ import { SwaggerModule } from '@hazeljs/swagger';
173
+ import { AppModule } from './app.module';
174
+
175
+ async function bootstrap(): Promise<void> {
176
+ // Setup Swagger documentation (must be called before app creation)
177
+ SwaggerModule.setRootModule(AppModule);
178
+
179
+ const app = new HazelApp(AppModule);
180
+
181
+ // Enable CORS
182
+ app.enableCors({
183
+ origin: '*',
184
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
185
+ });
186
+
187
+ const port = parseInt(process.env.PORT || '3000', 10);
188
+ await app.listen(port);
189
+ }
190
+
191
+ bootstrap();
192
+ `;
193
+ fs_1.default.writeFileSync(path_1.default.join(srcPath, 'index.ts'), mainContent);
194
+ console.log(chalk_1.default.green(' ✓ Updated index.ts with Swagger setup'));
195
+ }
196
+ }
197
+ function generateApp(program) {
198
+ program
199
+ .command('new <appName>')
200
+ .description('Create a new HazelJS application')
201
+ .option('-d, --dest <destPath>', 'Destination path', '.')
202
+ .option('--skip-install', 'Skip npm install')
203
+ .option('--skip-git', 'Skip git initialization')
204
+ .option('-i, --interactive', 'Interactive setup')
205
+ .action(async (appName, options) => {
206
+ try {
207
+ let projectConfig = {
208
+ name: appName,
209
+ description: `A HazelJS application`,
210
+ author: '',
211
+ license: 'Apache-2.0',
212
+ packages: [],
213
+ };
214
+ // Interactive setup
215
+ if (options.interactive) {
216
+ console.log(chalk_1.default.blue('\n🚀 Welcome to HazelJS project setup!\n'));
217
+ const answers = await inquirer_1.default.prompt([
218
+ {
219
+ type: 'input',
220
+ name: 'description',
221
+ message: 'Project description:',
222
+ default: projectConfig.description,
223
+ },
224
+ {
225
+ type: 'input',
226
+ name: 'author',
227
+ message: 'Author:',
228
+ },
229
+ {
230
+ type: 'list',
231
+ name: 'license',
232
+ message: 'License:',
233
+ choices: ['MIT', 'Apache-2.0', 'GPL-3.0', 'BSD-3-Clause', 'ISC'],
234
+ default: 'Apache-2.0',
235
+ },
236
+ {
237
+ type: 'checkbox',
238
+ name: 'packages',
239
+ message: 'Select additional HazelJS packages to install:',
240
+ choices: [
241
+ { name: 'AI Integration (@hazeljs/ai)', value: '@hazeljs/ai' },
242
+ { name: 'AI Agents (@hazeljs/agent)', value: '@hazeljs/agent' },
243
+ { name: 'Audit Logging (@hazeljs/audit)', value: '@hazeljs/audit' },
244
+ { name: 'Authentication (@hazeljs/auth)', value: '@hazeljs/auth' },
245
+ { name: 'OAuth - Google/Microsoft/GitHub (@hazeljs/oauth)', value: '@hazeljs/oauth' },
246
+ { name: 'Caching (@hazeljs/cache)', value: '@hazeljs/cache' },
247
+ { name: 'Configuration (@hazeljs/config)', value: '@hazeljs/config' },
248
+ { name: 'Cron Jobs (@hazeljs/cron)', value: '@hazeljs/cron' },
249
+ { name: 'Data/ETL (@hazeljs/data)', value: '@hazeljs/data' },
250
+ { name: 'Service Discovery (@hazeljs/discovery)', value: '@hazeljs/discovery' },
251
+ { name: 'Event Emitter (@hazeljs/event-emitter)', value: '@hazeljs/event-emitter' },
252
+ { name: 'API Gateway (@hazeljs/gateway)', value: '@hazeljs/gateway' },
253
+ { name: 'GraphQL (@hazeljs/graphql)', value: '@hazeljs/graphql' },
254
+ { name: 'gRPC (@hazeljs/grpc)', value: '@hazeljs/grpc' },
255
+ { name: 'Kafka (@hazeljs/kafka)', value: '@hazeljs/kafka' },
256
+ { name: 'Messaging - WhatsApp/Telegram (@hazeljs/messaging)', value: '@hazeljs/messaging' },
257
+ { name: 'Machine Learning (@hazeljs/ml)', value: '@hazeljs/ml' },
258
+ { name: 'MCP - Model Context Protocol (@hazeljs/mcp)', value: '@hazeljs/mcp' },
259
+ { name: 'PDF to Audio (@hazeljs/pdf-to-audio)', value: '@hazeljs/pdf-to-audio' },
260
+ { name: 'Prompts - typed templates (@hazeljs/prompts)', value: '@hazeljs/prompts' },
261
+ { name: 'Prisma ORM (@hazeljs/prisma)', value: '@hazeljs/prisma' },
262
+ { name: 'TypeORM (@hazeljs/typeorm)', value: '@hazeljs/typeorm' },
263
+ { name: 'Queue/BullMQ (@hazeljs/queue)', value: '@hazeljs/queue' },
264
+ { name: 'RAG/Vector Search (@hazeljs/rag)', value: '@hazeljs/rag' },
265
+ { name: 'Resilience - Circuit Breaker (@hazeljs/resilience)', value: '@hazeljs/resilience' },
266
+ { name: 'Serverless (@hazeljs/serverless)', value: '@hazeljs/serverless' },
267
+ { name: 'Swagger/OpenAPI (@hazeljs/swagger)', value: '@hazeljs/swagger' },
268
+ { name: 'WebSocket (@hazeljs/websocket)', value: '@hazeljs/websocket' },
269
+ ],
270
+ },
271
+ ]);
272
+ projectConfig = { ...projectConfig, ...answers };
273
+ }
274
+ const destPath = path_1.default.join(process.cwd(), options.dest || '.', appName);
275
+ console.log(chalk_1.default.blue('\n📦 Creating new HazelJS project...\n'));
276
+ console.log(chalk_1.default.gray(`Project: ${projectConfig.name}`));
277
+ console.log(chalk_1.default.gray(`Location: ${destPath}\n`));
278
+ // Check if destination exists
279
+ if (fs_1.default.existsSync(destPath)) {
280
+ console.error(chalk_1.default.red(`✗ Destination already exists: ${destPath}`));
281
+ process.exit(1);
282
+ }
283
+ // Use local template
284
+ const templatePath = path_1.default.join(__dirname, '../../@template');
285
+ if (fs_1.default.existsSync(templatePath)) {
286
+ console.log(chalk_1.default.blue('📋 Copying template files...'));
287
+ copyRecursiveSync(templatePath, destPath);
288
+ // Update package.json
289
+ updatePackageJson(destPath, projectConfig.name, projectConfig.description);
290
+ console.log(chalk_1.default.green('✓ Template files copied'));
291
+ }
292
+ else {
293
+ console.log(chalk_1.default.yellow('⚠ Local template not found, creating basic structure...'));
294
+ // Create basic structure
295
+ fs_1.default.mkdirSync(destPath, { recursive: true });
296
+ fs_1.default.mkdirSync(path_1.default.join(destPath, 'src'), { recursive: true });
297
+ // Create package.json
298
+ const packageJson = {
299
+ name: projectConfig.name,
300
+ version: '0.1.0',
301
+ description: projectConfig.description,
302
+ main: 'dist/index.js',
303
+ scripts: {
304
+ build: 'tsc',
305
+ start: 'node dist/index.js',
306
+ dev: 'ts-node-dev --respawn --transpile-only src/index.ts',
307
+ test: 'jest',
308
+ lint: 'eslint "src/**/*.ts"',
309
+ 'lint:fix': 'eslint "src/**/*.ts" --fix',
310
+ format: 'prettier --write "src/**/*.ts"',
311
+ },
312
+ dependencies: {
313
+ '@hazeljs/core': '^0.2.0',
314
+ 'reflect-metadata': '^0.2.2',
315
+ },
316
+ devDependencies: {
317
+ '@types/jest': '^29.5.12',
318
+ '@types/node': '^20.0.0',
319
+ '@typescript-eslint/eslint-plugin': '^8.18.2',
320
+ '@typescript-eslint/parser': '^8.18.2',
321
+ 'eslint': '^8.56.0',
322
+ 'eslint-config-prettier': '^9.1.0',
323
+ 'eslint-plugin-prettier': '^5.1.3',
324
+ 'jest': '^29.7.0',
325
+ 'prettier': '^3.2.5',
326
+ 'ts-jest': '^29.1.2',
327
+ 'ts-node-dev': '^2.0.0',
328
+ 'typescript': '^5.3.3',
329
+ },
330
+ author: projectConfig.author,
331
+ license: projectConfig.license,
332
+ };
333
+ fs_1.default.writeFileSync(path_1.default.join(destPath, 'package.json'), JSON.stringify(packageJson, null, 2));
334
+ // Create basic index.ts
335
+ const indexContent = `import 'reflect-metadata';
336
+ import { HazelApp, HazelModule, Controller, Get } from '@hazeljs/core';
337
+
338
+ @Controller('/')
339
+ export class AppController {
340
+ @Get()
341
+ hello() {
342
+ return { message: 'Hello from HazelJS!' };
343
+ }
344
+ }
345
+
346
+ @HazelModule({
347
+ controllers: [AppController],
348
+ })
349
+ export class AppModule {}
350
+
351
+ async function bootstrap() {
352
+ const app = new HazelApp(AppModule);
353
+
354
+ app.enableCors({
355
+ origin: '*',
356
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
357
+ });
358
+
359
+ const port = parseInt(process.env.PORT || '3000', 10);
360
+ await app.listen(port);
361
+ }
362
+
363
+ bootstrap();
364
+ `;
365
+ fs_1.default.writeFileSync(path_1.default.join(destPath, 'src', 'index.ts'), indexContent);
366
+ // Create tsconfig.json
367
+ const tsConfig = {
368
+ compilerOptions: {
369
+ target: 'ES2020',
370
+ module: 'commonjs',
371
+ lib: ['ES2020'],
372
+ outDir: './dist',
373
+ rootDir: './src',
374
+ strict: true,
375
+ esModuleInterop: true,
376
+ skipLibCheck: true,
377
+ forceConsistentCasingInFileNames: true,
378
+ experimentalDecorators: true,
379
+ emitDecoratorMetadata: true,
380
+ },
381
+ include: ['src/**/*'],
382
+ exclude: ['node_modules', 'dist'],
383
+ };
384
+ fs_1.default.writeFileSync(path_1.default.join(destPath, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
385
+ console.log(chalk_1.default.green('✓ Basic structure created'));
386
+ }
387
+ // Initialize git
388
+ if (!options.skipGit) {
389
+ try {
390
+ console.log(chalk_1.default.blue('\n📝 Initializing git repository...'));
391
+ (0, child_process_1.execSync)('git init', { cwd: destPath, stdio: 'ignore' });
392
+ // Create .gitignore
393
+ const gitignore = `node_modules/
394
+ dist/
395
+ .env
396
+ .DS_Store
397
+ coverage/
398
+ *.log
399
+ `;
400
+ fs_1.default.writeFileSync(path_1.default.join(destPath, '.gitignore'), gitignore);
401
+ console.log(chalk_1.default.green('✓ Git initialized'));
402
+ }
403
+ catch {
404
+ console.log(chalk_1.default.yellow('⚠ Git initialization skipped'));
405
+ }
406
+ }
407
+ // Install dependencies
408
+ if (!options.skipInstall) {
409
+ console.log(chalk_1.default.blue('\n📦 Installing dependencies...\n'));
410
+ try {
411
+ (0, child_process_1.execSync)('npm install', { cwd: destPath, stdio: 'inherit' });
412
+ // Install additional packages
413
+ if (projectConfig.packages.length > 0) {
414
+ console.log(chalk_1.default.blue('\n📦 Installing additional packages...\n'));
415
+ (0, child_process_1.execSync)(`npm install ${projectConfig.packages.join(' ')}`, {
416
+ cwd: destPath,
417
+ stdio: 'inherit',
418
+ });
419
+ }
420
+ console.log(chalk_1.default.green('\n✓ Dependencies installed'));
421
+ }
422
+ catch {
423
+ console.log(chalk_1.default.yellow('\n⚠ Dependency installation failed'));
424
+ console.log(chalk_1.default.gray('You can install them manually with: npm install'));
425
+ }
426
+ }
427
+ // Scaffold boilerplate for selected packages
428
+ if (projectConfig.packages.length > 0) {
429
+ console.log(chalk_1.default.blue('\n📝 Scaffolding boilerplate for selected packages...\n'));
430
+ scaffoldPackageBoilerplate(destPath, projectConfig.packages);
431
+ }
432
+ // Success message
433
+ console.log(chalk_1.default.green.bold('\n✨ Project created successfully!\n'));
434
+ console.log(chalk_1.default.gray('Next steps:'));
435
+ console.log(chalk_1.default.gray(` cd ${appName}`));
436
+ if (options.skipInstall) {
437
+ console.log(chalk_1.default.gray(' npm install'));
438
+ }
439
+ console.log(chalk_1.default.gray(' npm run dev'));
440
+ console.log(chalk_1.default.gray('\nDocumentation: https://hazeljs.com/docs'));
441
+ console.log(chalk_1.default.gray('Discord: https://discord.com/channels/1448263814238965833/1448263814859456575\n'));
442
+ }
443
+ catch (error) {
444
+ console.error(chalk_1.default.red('\n✗ Failed to create project:'), error);
445
+ process.exit(1);
446
+ }
447
+ });
448
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateAuth(command: Command): void;
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateAuth = generateAuth;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const generator_1 = require("../utils/generator");
11
+ const AUTH_MODULE_TEMPLATE = `import { HazelModule } from '@hazeljs/core';
12
+ import { AuthController } from './auth.controller';
13
+ import { AuthService } from './auth.service';
14
+ import { JwtAuthGuard } from './jwt-auth.guard';
15
+
16
+ @HazelModule({
17
+ controllers: [AuthController],
18
+ providers: [AuthService, JwtAuthGuard],
19
+ exports: [AuthService, JwtAuthGuard],
20
+ })
21
+ export class AuthModule {}
22
+ `;
23
+ const AUTH_SERVICE_TEMPLATE = `import { Service, BadRequestError, UnauthorizedError } from '@hazeljs/core';
24
+ import { JwtService } from '@hazeljs/auth';
25
+ import { RegisterDto } from './dto/register.dto';
26
+ import { LoginDto } from './dto/login.dto';
27
+
28
+ @Service()
29
+ export class AuthService {
30
+ constructor(
31
+ private readonly jwtService: JwtService,
32
+ ) {}
33
+
34
+ async register(registerDto: RegisterDto) {
35
+ // TODO: Check if user already exists in your database
36
+
37
+ // TODO: Hash the password (e.g., with bcryptjs)
38
+ // const hashedPassword = await bcrypt.hash(registerDto.password, 10);
39
+
40
+ // TODO: Create the user in your database
41
+ const user = {
42
+ id: Date.now().toString(),
43
+ name: registerDto.name,
44
+ email: registerDto.email,
45
+ };
46
+
47
+ const accessToken = this.jwtService.sign({
48
+ sub: user.id,
49
+ email: user.email,
50
+ });
51
+
52
+ return { user, accessToken };
53
+ }
54
+
55
+ async login(loginDto: LoginDto) {
56
+ // TODO: Find user by email in your database
57
+ // TODO: Verify password with bcrypt.compare()
58
+
59
+ const user = { id: '1', name: 'User', email: loginDto.email };
60
+
61
+ const accessToken = this.jwtService.sign({
62
+ sub: user.id,
63
+ email: user.email,
64
+ });
65
+
66
+ return { user, accessToken };
67
+ }
68
+ }
69
+ `;
70
+ const AUTH_CONTROLLER_TEMPLATE = `import { Controller, Post, Body } from '@hazeljs/core';
71
+ import { AuthService } from './auth.service';
72
+ import { RegisterDto } from './dto/register.dto';
73
+ import { LoginDto } from './dto/login.dto';
74
+
75
+ @Controller('/auth')
76
+ export class AuthController {
77
+ constructor(private readonly authService: AuthService) {}
78
+
79
+ @Post('/register')
80
+ async register(@Body() registerDto: RegisterDto) {
81
+ return this.authService.register(registerDto);
82
+ }
83
+
84
+ @Post('/login')
85
+ async login(@Body() loginDto: LoginDto) {
86
+ return this.authService.login(loginDto);
87
+ }
88
+ }
89
+ `;
90
+ const JWT_GUARD_TEMPLATE = `import { Injectable, type CanActivate, type ExecutionContext, UnauthorizedError } from '@hazeljs/core';
91
+ import { JwtService } from '@hazeljs/auth';
92
+
93
+ @Injectable()
94
+ export class JwtAuthGuard implements CanActivate {
95
+ constructor(private readonly jwtService: JwtService) {}
96
+
97
+ async canActivate(context: ExecutionContext): Promise<boolean> {
98
+ const request = context.switchToHttp().getRequest();
99
+ const authHeader = request.headers?.authorization;
100
+
101
+ if (!authHeader) {
102
+ throw new UnauthorizedError('Missing Authorization header');
103
+ }
104
+
105
+ const [type, token] = authHeader.split(' ');
106
+ if (type !== 'Bearer' || !token) {
107
+ throw new UnauthorizedError('Invalid Authorization header');
108
+ }
109
+
110
+ try {
111
+ const payload = this.jwtService.verify(token);
112
+ (request as any).user = payload;
113
+ return true;
114
+ } catch {
115
+ throw new UnauthorizedError('Invalid or expired token');
116
+ }
117
+ }
118
+ }
119
+ `;
120
+ const REGISTER_DTO_TEMPLATE = `import { IsString, IsEmail, IsNotEmpty, MinLength } from 'class-validator';
121
+
122
+ export class RegisterDto {
123
+ @IsString()
124
+ @IsNotEmpty()
125
+ name: string;
126
+
127
+ @IsEmail()
128
+ @IsNotEmpty()
129
+ email: string;
130
+
131
+ @IsString()
132
+ @MinLength(6)
133
+ password: string;
134
+ }
135
+ `;
136
+ const LOGIN_DTO_TEMPLATE = `import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
137
+
138
+ export class LoginDto {
139
+ @IsEmail()
140
+ @IsNotEmpty()
141
+ email: string;
142
+
143
+ @IsString()
144
+ @IsNotEmpty()
145
+ password: string;
146
+ }
147
+ `;
148
+ function generateAuth(command) {
149
+ command
150
+ .command('auth')
151
+ .description('Generate an auth module with JWT guard, service, controller, and DTOs')
152
+ .option('-p, --path <path>', 'Specify the path', 'src/auth')
153
+ .option('--dry-run', 'Preview files without writing them')
154
+ .action((options) => {
155
+ const basePath = path_1.default.join(process.cwd(), options.path || 'src/auth');
156
+ const data = {};
157
+ const files = [
158
+ { file: 'auth.module.ts', template: AUTH_MODULE_TEMPLATE },
159
+ { file: 'auth.service.ts', template: AUTH_SERVICE_TEMPLATE },
160
+ { file: 'auth.controller.ts', template: AUTH_CONTROLLER_TEMPLATE },
161
+ { file: 'jwt-auth.guard.ts', template: JWT_GUARD_TEMPLATE },
162
+ { file: 'dto/register.dto.ts', template: REGISTER_DTO_TEMPLATE },
163
+ { file: 'dto/login.dto.ts', template: LOGIN_DTO_TEMPLATE },
164
+ ];
165
+ try {
166
+ for (const { file, template } of files) {
167
+ const filePath = path_1.default.join(basePath, file);
168
+ if (options.dryRun) {
169
+ console.log(chalk_1.default.blue(`[dry-run] Would create ${filePath}`));
170
+ continue;
171
+ }
172
+ const dir = path_1.default.dirname(filePath);
173
+ if (!fs_1.default.existsSync(dir)) {
174
+ fs_1.default.mkdirSync(dir, { recursive: true });
175
+ }
176
+ fs_1.default.writeFileSync(filePath, (0, generator_1.renderTemplate)(template, data));
177
+ console.log(chalk_1.default.green(`\u2713 Generated ${filePath}`));
178
+ }
179
+ if (!options.dryRun) {
180
+ console.log(chalk_1.default.blue('\n\uD83D\uDD10 Auth module generated successfully!'));
181
+ console.log(chalk_1.default.gray('\nNext steps:'));
182
+ console.log(chalk_1.default.gray(' 1. Import AuthModule in your app module'));
183
+ console.log(chalk_1.default.gray(' 2. Configure JwtModule.forRoot() in your app module:'));
184
+ console.log(chalk_1.default.gray(' JwtModule.forRoot({ secret: "your-secret", expiresIn: "1d" })'));
185
+ console.log(chalk_1.default.gray(' 3. Install bcryptjs: npm install bcryptjs @types/bcryptjs'));
186
+ console.log(chalk_1.default.gray(' 4. Implement database integration in AuthService'));
187
+ }
188
+ }
189
+ catch (error) {
190
+ console.error(chalk_1.default.red('Error generating auth module:'), error);
191
+ process.exit(1);
192
+ }
193
+ });
194
+ }
@@ -0,0 +1 @@
1
+ export {};