@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.
- package/@template/.eslintrc.js +36 -0
- package/@template/.lintstagedrc +6 -0
- package/@template/README.md +61 -0
- package/@template/jest.config.js +28 -0
- package/@template/jest.setup.js +81 -0
- package/@template/package.json +34 -0
- package/@template/src/app.module.ts +7 -0
- package/@template/src/hello.controller.ts +9 -0
- package/@template/src/index.ts +18 -0
- package/@template/tsconfig.json +25 -0
- package/LICENSE +192 -0
- package/README.md +683 -0
- package/dist/commands/add.d.ts +2 -0
- package/dist/commands/add.js +176 -0
- package/dist/commands/add.test.d.ts +1 -0
- package/dist/commands/add.test.js +51 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/build.js +52 -0
- package/dist/commands/generate-agent.d.ts +2 -0
- package/dist/commands/generate-agent.js +58 -0
- package/dist/commands/generate-agent.test.d.ts +1 -0
- package/dist/commands/generate-agent.test.js +36 -0
- package/dist/commands/generate-ai-service.d.ts +2 -0
- package/dist/commands/generate-ai-service.js +48 -0
- package/dist/commands/generate-ai-service.test.d.ts +1 -0
- package/dist/commands/generate-ai-service.test.js +41 -0
- package/dist/commands/generate-app.d.ts +2 -0
- package/dist/commands/generate-app.js +448 -0
- package/dist/commands/generate-auth.d.ts +2 -0
- package/dist/commands/generate-auth.js +194 -0
- package/dist/commands/generate-auth.test.d.ts +1 -0
- package/dist/commands/generate-auth.test.js +48 -0
- package/dist/commands/generate-cache.d.ts +2 -0
- package/dist/commands/generate-cache.js +64 -0
- package/dist/commands/generate-cache.test.d.ts +1 -0
- package/dist/commands/generate-cache.test.js +36 -0
- package/dist/commands/generate-config.d.ts +2 -0
- package/dist/commands/generate-config.js +57 -0
- package/dist/commands/generate-config.test.d.ts +1 -0
- package/dist/commands/generate-config.test.js +35 -0
- package/dist/commands/generate-controller.d.ts +2 -0
- package/dist/commands/generate-controller.js +60 -0
- package/dist/commands/generate-controller.test.d.ts +1 -0
- package/dist/commands/generate-controller.test.js +48 -0
- package/dist/commands/generate-cron.d.ts +2 -0
- package/dist/commands/generate-cron.js +59 -0
- package/dist/commands/generate-cron.test.d.ts +1 -0
- package/dist/commands/generate-cron.test.js +42 -0
- package/dist/commands/generate-crud.d.ts +2 -0
- package/dist/commands/generate-crud.js +177 -0
- package/dist/commands/generate-crud.test.d.ts +1 -0
- package/dist/commands/generate-crud.test.js +52 -0
- package/dist/commands/generate-discovery.d.ts +2 -0
- package/dist/commands/generate-discovery.js +61 -0
- package/dist/commands/generate-discovery.test.d.ts +1 -0
- package/dist/commands/generate-discovery.test.js +36 -0
- package/dist/commands/generate-dto.d.ts +2 -0
- package/dist/commands/generate-dto.js +69 -0
- package/dist/commands/generate-dto.test.d.ts +1 -0
- package/dist/commands/generate-dto.test.js +44 -0
- package/dist/commands/generate-exception-filter.d.ts +2 -0
- package/dist/commands/generate-exception-filter.js +48 -0
- package/dist/commands/generate-exception-filter.test.d.ts +1 -0
- package/dist/commands/generate-exception-filter.test.js +43 -0
- package/dist/commands/generate-guard.d.ts +2 -0
- package/dist/commands/generate-guard.js +36 -0
- package/dist/commands/generate-guard.test.d.ts +1 -0
- package/dist/commands/generate-guard.test.js +41 -0
- package/dist/commands/generate-interceptor.d.ts +2 -0
- package/dist/commands/generate-interceptor.js +37 -0
- package/dist/commands/generate-interceptor.test.d.ts +1 -0
- package/dist/commands/generate-interceptor.test.js +41 -0
- package/dist/commands/generate-middleware.d.ts +2 -0
- package/dist/commands/generate-middleware.js +46 -0
- package/dist/commands/generate-middleware.test.d.ts +1 -0
- package/dist/commands/generate-middleware.test.js +41 -0
- package/dist/commands/generate-module.d.ts +2 -0
- package/dist/commands/generate-module.js +106 -0
- package/dist/commands/generate-module.test.d.ts +1 -0
- package/dist/commands/generate-module.test.js +54 -0
- package/dist/commands/generate-pipe.d.ts +2 -0
- package/dist/commands/generate-pipe.js +33 -0
- package/dist/commands/generate-pipe.test.d.ts +1 -0
- package/dist/commands/generate-pipe.test.js +35 -0
- package/dist/commands/generate-rag.d.ts +2 -0
- package/dist/commands/generate-rag.js +66 -0
- package/dist/commands/generate-rag.test.d.ts +1 -0
- package/dist/commands/generate-rag.test.js +35 -0
- package/dist/commands/generate-repository.d.ts +2 -0
- package/dist/commands/generate-repository.js +40 -0
- package/dist/commands/generate-repository.test.d.ts +1 -0
- package/dist/commands/generate-repository.test.js +41 -0
- package/dist/commands/generate-serverless-handler.d.ts +2 -0
- package/dist/commands/generate-serverless-handler.js +46 -0
- package/dist/commands/generate-serverless-handler.test.d.ts +1 -0
- package/dist/commands/generate-serverless-handler.test.js +42 -0
- package/dist/commands/generate-service.d.ts +2 -0
- package/dist/commands/generate-service.js +52 -0
- package/dist/commands/generate-service.test.d.ts +1 -0
- package/dist/commands/generate-service.test.js +41 -0
- package/dist/commands/generate-websocket-gateway.d.ts +2 -0
- package/dist/commands/generate-websocket-gateway.js +47 -0
- package/dist/commands/generate-websocket-gateway.test.d.ts +1 -0
- package/dist/commands/generate-websocket-gateway.test.js +41 -0
- package/dist/commands/info.d.ts +2 -0
- package/dist/commands/info.js +91 -0
- package/dist/commands/pdf-to-audio.d.ts +2 -0
- package/dist/commands/pdf-to-audio.js +170 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.js +61 -0
- package/dist/commands/test.d.ts +2 -0
- package/dist/commands/test.js +63 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +75 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +93 -0
- package/dist/utils/generator.d.ts +25 -0
- package/dist/utils/generator.js +107 -0
- package/dist/utils/generator.test.d.ts +1 -0
- package/dist/utils/generator.test.js +137 -0
- 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,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 {};
|