@hazeljs/cli 0.6.0 → 0.6.5
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-ai-native/package.json +1 -1
- package/README.md +22 -1
- package/cli-manifest.json +940 -0
- package/dist/commands/add.d.ts +9 -0
- package/dist/commands/add.js +9 -0
- package/dist/commands/generate-auth.d.ts +12 -0
- package/dist/commands/generate-auth.js +12 -0
- package/dist/commands/generate-crud.d.ts +12 -0
- package/dist/commands/generate-crud.js +12 -0
- package/dist/commands/generate-dto.d.ts +12 -0
- package/dist/commands/generate-dto.js +12 -0
- package/dist/commands/generate-module.d.ts +12 -0
- package/dist/commands/generate-module.js +12 -0
- package/dist/commands/generate-simple.d.ts +53 -6
- package/dist/commands/generate-simple.js +42 -386
- package/dist/commands/info.d.ts +12 -0
- package/dist/commands/info.js +12 -0
- package/dist/commands/templates.d.ts +34 -0
- package/dist/commands/templates.js +387 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +45 -1
- package/dist/utils/generator-registry.d.ts +5 -0
- package/dist/utils/generator-registry.js +5 -0
- package/dist/utils/packages-registry.d.ts +11 -2
- package/dist/utils/packages-registry.js +11 -2
- package/package.json +6 -4
|
@@ -5,390 +5,25 @@ exports.runSimpleGenerator = runSimpleGenerator;
|
|
|
5
5
|
exports.registerSimpleGenerators = registerSimpleGenerators;
|
|
6
6
|
exports.findSimpleGenerator = findSimpleGenerator;
|
|
7
7
|
const generator_1 = require("../utils/generator");
|
|
8
|
-
|
|
9
|
-
const CONTROLLER_TEMPLATE = `import { Controller, Get, Post, Body, Param, Delete, Put } from '@hazeljs/core';
|
|
10
|
-
import { {{className}}Service } from './{{fileName}}.service';
|
|
11
|
-
import { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';
|
|
12
|
-
import { Update{{className}}Dto } from './dto/update-{{fileName}}.dto';
|
|
13
|
-
|
|
14
|
-
@Controller('{{fileName}}')
|
|
15
|
-
export class {{className}}Controller {
|
|
16
|
-
constructor(private readonly {{camelName}}Service: {{className}}Service) {}
|
|
17
|
-
|
|
18
|
-
@Get()
|
|
19
|
-
findAll() {
|
|
20
|
-
return this.{{camelName}}Service.findAll();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
@Get(':id')
|
|
24
|
-
findOne(@Param('id') id: string) {
|
|
25
|
-
return this.{{camelName}}Service.findOne(id);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@Post()
|
|
29
|
-
create(@Body(Create{{className}}Dto) createDto: Create{{className}}Dto) {
|
|
30
|
-
return this.{{camelName}}Service.create(createDto);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
@Put(':id')
|
|
34
|
-
update(@Param('id') id: string, @Body(Update{{className}}Dto) updateDto: Update{{className}}Dto) {
|
|
35
|
-
return this.{{camelName}}Service.update(id, updateDto);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
@Delete(':id')
|
|
39
|
-
remove(@Param('id') id: string) {
|
|
40
|
-
return this.{{camelName}}Service.remove(id);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
`;
|
|
44
|
-
const SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
45
|
-
|
|
46
|
-
@Service()
|
|
47
|
-
export class {{className}}Service {
|
|
48
|
-
constructor() {}
|
|
49
|
-
|
|
50
|
-
async findAll() {
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async findOne(id: string) {
|
|
55
|
-
return { id };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async create(createDto: any) {
|
|
59
|
-
return createDto;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async update(id: string, updateDto: any) {
|
|
63
|
-
return { id, ...updateDto };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async remove(id: string) {
|
|
67
|
-
return { id };
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
`;
|
|
71
|
-
const GUARD_TEMPLATE = `import { Injectable, type CanActivate, type ExecutionContext } from '@hazeljs/core';
|
|
72
|
-
|
|
73
|
-
@Injectable()
|
|
74
|
-
export class {{className}}Guard implements CanActivate {
|
|
75
|
-
canActivate(context: ExecutionContext): boolean {
|
|
76
|
-
const request = context.switchToHttp().getRequest();
|
|
77
|
-
// Add your guard logic here
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
`;
|
|
82
|
-
const INTERCEPTOR_TEMPLATE = `import { Injectable, Interceptor, type ExecutionContext } from '@hazeljs/core';
|
|
83
|
-
|
|
84
|
-
@Injectable()
|
|
85
|
-
export class {{className}}Interceptor implements Interceptor {
|
|
86
|
-
async intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {
|
|
87
|
-
// Pre-processing logic here (before handler execution)
|
|
88
|
-
const result = await next();
|
|
89
|
-
// Post-processing logic here (after handler execution)
|
|
90
|
-
return result;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
`;
|
|
94
|
-
const MIDDLEWARE_TEMPLATE = `import { Injectable, type MiddlewareHandler, type Request, type Response, type NextFunction } from '@hazeljs/core';
|
|
95
|
-
|
|
96
|
-
@Injectable()
|
|
97
|
-
export class {{className}}Middleware implements MiddlewareHandler {
|
|
98
|
-
use(req: Request, res: Response, next: NextFunction) {
|
|
99
|
-
// Add your middleware logic here
|
|
100
|
-
console.log(\`[{{className}}Middleware] \${req.method} \${req.url}\`);
|
|
101
|
-
|
|
102
|
-
// Continue to next middleware
|
|
103
|
-
next();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
`;
|
|
107
|
-
const PIPE_TEMPLATE = `import { type PipeTransform, type RequestContext } from '@hazeljs/core';
|
|
108
|
-
|
|
109
|
-
export class {{className}}Pipe implements PipeTransform {
|
|
110
|
-
transform(value: unknown, context: RequestContext): unknown {
|
|
111
|
-
// Transform logic here
|
|
112
|
-
return value;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
`;
|
|
116
|
-
const EXCEPTION_FILTER_TEMPLATE = `import { Catch, type ExceptionFilter, type ArgumentsHost, HttpError, logger } from '@hazeljs/core';
|
|
117
|
-
|
|
118
|
-
@Catch(HttpError)
|
|
119
|
-
export class {{className}}ExceptionFilter implements ExceptionFilter<HttpError> {
|
|
120
|
-
catch(exception: HttpError, host: ArgumentsHost): void {
|
|
121
|
-
const ctx = host.switchToHttp();
|
|
122
|
-
const response = ctx.getResponse();
|
|
123
|
-
const request = ctx.getRequest();
|
|
124
|
-
|
|
125
|
-
const status = exception.statusCode || 500;
|
|
126
|
-
const message = exception.message || 'Internal server error';
|
|
127
|
-
|
|
128
|
-
logger.error(\`[\${request.method}] \${request.url} - \${message} (\${status})\`);
|
|
129
|
-
|
|
130
|
-
response.status(status).json({
|
|
131
|
-
statusCode: status,
|
|
132
|
-
message,
|
|
133
|
-
timestamp: new Date().toISOString(),
|
|
134
|
-
path: request.url,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
`;
|
|
139
|
-
const REPOSITORY_TEMPLATE = `import { Repository, BaseRepository, PrismaService } from '@hazeljs/prisma';
|
|
140
|
-
|
|
141
|
-
// @Repository implies @Injectable() — no need for both decorators
|
|
142
|
-
@Repository({ model: '{{modelName}}' })
|
|
143
|
-
export class {{className}}Repository extends BaseRepository<any> {
|
|
144
|
-
constructor(prisma: PrismaService) {
|
|
145
|
-
super(prisma, '{{modelName}}');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Add custom repository methods here
|
|
149
|
-
async findByName(name: string) {
|
|
150
|
-
return this.findMany({ where: { name } });
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
`;
|
|
154
|
-
const WEBSOCKET_GATEWAY_TEMPLATE = `import { Realtime, OnConnect, OnDisconnect, OnMessage, Subscribe, Client, Data, WebSocketClient } from '@hazeljs/websocket';
|
|
155
|
-
|
|
156
|
-
@Realtime('/{{fileName}}')
|
|
157
|
-
export class {{className}}Gateway {
|
|
158
|
-
@OnConnect()
|
|
159
|
-
handleConnection(@Client() client: WebSocketClient) {
|
|
160
|
-
console.log('Client connected:', client.id);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
@OnDisconnect()
|
|
164
|
-
handleDisconnect(@Client() client: WebSocketClient) {
|
|
165
|
-
console.log('Client disconnected:', client.id);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
@Subscribe('message')
|
|
169
|
-
@OnMessage('message')
|
|
170
|
-
handleMessage(@Client() client: WebSocketClient, @Data() data: unknown) {
|
|
171
|
-
console.log('Message received from', client.id, ':', data);
|
|
172
|
-
// Handle message logic here
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
`;
|
|
176
|
-
const AI_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
177
|
-
import { AIService, AIFunction, AIPrompt } from '@hazeljs/ai';
|
|
178
|
-
|
|
179
|
-
@Service()
|
|
180
|
-
export class {{className}}AIService {
|
|
181
|
-
constructor(private readonly aiService: AIService) {}
|
|
182
|
-
|
|
183
|
-
@AIFunction({
|
|
184
|
-
provider: 'openai',
|
|
185
|
-
model: 'gpt-4',
|
|
186
|
-
streaming: false,
|
|
187
|
-
})
|
|
188
|
-
async {{camelName}}Task(@AIPrompt() prompt: string): Promise<unknown> {
|
|
189
|
-
const result = await this.aiService.complete({
|
|
190
|
-
provider: 'openai',
|
|
191
|
-
model: 'gpt-4',
|
|
192
|
-
messages: [{ role: 'user', content: prompt }],
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
return result;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
`;
|
|
199
|
-
const AGENT_TEMPLATE = `import { Agent, Tool } from '@hazeljs/agent';
|
|
200
|
-
|
|
201
|
-
@Agent({
|
|
202
|
-
name: '{{fileName}}',
|
|
203
|
-
description: '{{description}}',
|
|
204
|
-
systemPrompt: 'You are a helpful {{className}} agent.',
|
|
205
|
-
enableMemory: true,
|
|
206
|
-
enableRAG: true,
|
|
207
|
-
})
|
|
208
|
-
export class {{className}}Agent {
|
|
209
|
-
@Tool({
|
|
210
|
-
description: 'Example tool for {{fileName}}',
|
|
211
|
-
parameters: [
|
|
212
|
-
{
|
|
213
|
-
name: 'input',
|
|
214
|
-
type: 'string',
|
|
215
|
-
description: 'Input parameter',
|
|
216
|
-
required: true,
|
|
217
|
-
},
|
|
218
|
-
],
|
|
219
|
-
})
|
|
220
|
-
async exampleTool(input: { input: string }): Promise<{ result: string }> {
|
|
221
|
-
// Implement your tool logic here
|
|
222
|
-
return {
|
|
223
|
-
result: \`Processed: \${input.input}\`,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
`;
|
|
228
|
-
const CACHE_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
229
|
-
import { CacheService, Cacheable, CacheEvict } from '@hazeljs/cache';
|
|
230
|
-
|
|
231
|
-
@Service()
|
|
232
|
-
export class {{className}}CacheService {
|
|
233
|
-
constructor(private readonly cacheService: CacheService) {}
|
|
234
|
-
|
|
235
|
-
@Cacheable({ key: '{{fileName}}:all', ttl: 60 })
|
|
236
|
-
async findAll() {
|
|
237
|
-
// This result will be cached for 60 seconds
|
|
238
|
-
return [];
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
@Cacheable({ key: '{{fileName}}:{{=<% %>=}}#{id}<%={{ }}=%>', ttl: 300 })
|
|
242
|
-
async findOne(id: string) {
|
|
243
|
-
// This result will be cached for 5 minutes
|
|
244
|
-
return { id };
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
@CacheEvict({ key: '{{fileName}}:all' })
|
|
248
|
-
async create(data: any) {
|
|
249
|
-
// Creating a new item evicts the list cache
|
|
250
|
-
return data;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
async clearAll() {
|
|
254
|
-
await this.cacheService.clear();
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
`;
|
|
258
|
-
const CRON_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
259
|
-
import { Cron, CronExpression } from '@hazeljs/cron';
|
|
260
|
-
|
|
261
|
-
@Service()
|
|
262
|
-
export class {{className}}CronService {
|
|
263
|
-
@Cron(CronExpression.EVERY_MINUTE)
|
|
264
|
-
handleEveryMinute() {
|
|
265
|
-
console.log('[{{className}}Cron] Running every minute...');
|
|
266
|
-
// Add your cron job logic here
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
@Cron('0 0 * * *') // Every day at midnight
|
|
270
|
-
handleDaily() {
|
|
271
|
-
console.log('[{{className}}Cron] Running daily task...');
|
|
272
|
-
// Add your daily task logic here
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
@Cron(CronExpression.EVERY_HOUR)
|
|
276
|
-
handleHourly() {
|
|
277
|
-
console.log('[{{className}}Cron] Running hourly cleanup...');
|
|
278
|
-
// Add your hourly task logic here
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
`;
|
|
282
|
-
const RAG_SERVICE_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
283
|
-
import { RAGPipeline, MemoryVectorStore } from '@hazeljs/rag';
|
|
284
|
-
|
|
285
|
-
@Service()
|
|
286
|
-
export class {{className}}RagService {
|
|
287
|
-
private pipeline: RAGPipeline;
|
|
288
|
-
|
|
289
|
-
constructor() {
|
|
290
|
-
// Initialize with a memory vector store (swap for Pinecone, Qdrant, etc. in production)
|
|
291
|
-
const vectorStore = new MemoryVectorStore();
|
|
292
|
-
|
|
293
|
-
this.pipeline = new RAGPipeline({
|
|
294
|
-
vectorStore,
|
|
295
|
-
topK: 5,
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
async addDocument(content: string, metadata?: Record<string, unknown>) {
|
|
300
|
-
// Add a document to the vector store for retrieval
|
|
301
|
-
await this.pipeline.addDocument({
|
|
302
|
-
content,
|
|
303
|
-
metadata: metadata || {},
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
async query(question: string) {
|
|
308
|
-
// Retrieve relevant documents and generate a response
|
|
309
|
-
const results = await this.pipeline.query(question);
|
|
310
|
-
return results;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
`;
|
|
314
|
-
const DISCOVERY_TEMPLATE = `import { Service } from '@hazeljs/core';
|
|
315
|
-
import { ServiceRegistry, DiscoveryClient } from '@hazeljs/discovery';
|
|
316
|
-
|
|
317
|
-
@Service()
|
|
318
|
-
export class {{className}}DiscoveryService {
|
|
319
|
-
constructor(
|
|
320
|
-
private readonly registry: ServiceRegistry,
|
|
321
|
-
private readonly client: DiscoveryClient,
|
|
322
|
-
) {}
|
|
323
|
-
|
|
324
|
-
async registerService() {
|
|
325
|
-
await this.registry.register({
|
|
326
|
-
name: '{{fileName}}-service',
|
|
327
|
-
host: 'localhost',
|
|
328
|
-
port: 3000,
|
|
329
|
-
metadata: {
|
|
330
|
-
version: '1.0.0',
|
|
331
|
-
},
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
async discoverService(serviceName: string) {
|
|
336
|
-
const instances = await this.client.getInstances(serviceName);
|
|
337
|
-
return instances;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
`;
|
|
341
|
-
const CONFIG_TEMPLATE = `import { HazelModule } from '@hazeljs/core';
|
|
342
|
-
import { ConfigModule, ConfigService } from '@hazeljs/config';
|
|
343
|
-
|
|
344
|
-
// Import ConfigModule.forRoot() in your app module:
|
|
345
|
-
//
|
|
346
|
-
// @HazelModule({
|
|
347
|
-
// imports: [
|
|
348
|
-
// ConfigModule.forRoot({
|
|
349
|
-
// envFilePath: '.env',
|
|
350
|
-
// }),
|
|
351
|
-
// ],
|
|
352
|
-
// })
|
|
353
|
-
//
|
|
354
|
-
// Then inject ConfigService wherever you need it:
|
|
355
|
-
//
|
|
356
|
-
// constructor(private readonly config: ConfigService) {}
|
|
357
|
-
//
|
|
358
|
-
// Usage:
|
|
359
|
-
// this.config.get('DATABASE_URL');
|
|
360
|
-
// this.config.get('PORT', '3000'); // with default value
|
|
361
|
-
|
|
362
|
-
export { ConfigModule, ConfigService };
|
|
363
|
-
`;
|
|
364
|
-
const SERVERLESS_LAMBDA_TEMPLATE = `import { createLambdaHandler } from '@hazeljs/serverless';
|
|
365
|
-
import { AppModule } from './app.module';
|
|
366
|
-
|
|
367
|
-
export const handler = createLambdaHandler(AppModule);
|
|
368
|
-
`;
|
|
369
|
-
const SERVERLESS_CLOUD_FUNCTION_TEMPLATE = `import { createCloudFunctionHandler } from '@hazeljs/serverless';
|
|
370
|
-
import { AppModule } from './app.module';
|
|
371
|
-
|
|
372
|
-
export const handler = createCloudFunctionHandler(AppModule);
|
|
373
|
-
`;
|
|
8
|
+
const templates_1 = require("./templates");
|
|
374
9
|
exports.SIMPLE_GENERATORS = [
|
|
375
|
-
{ type: 'controller', description: 'REST controller', suffix: 'controller', template: CONTROLLER_TEMPLATE, alias: 'c', nameRequired: true },
|
|
376
|
-
{ type: 'service', description: 'Service class', suffix: 'service', template: SERVICE_TEMPLATE, alias: 's', nameRequired: true },
|
|
377
|
-
{ type: 'guard', description: 'Guard (e.g. auth)', suffix: 'guard', template: GUARD_TEMPLATE, alias: 'gu', nameRequired: true },
|
|
378
|
-
{ type: 'interceptor', description: 'Interceptor', suffix: 'interceptor', template: INTERCEPTOR_TEMPLATE, alias: 'i', nameRequired: true },
|
|
379
|
-
{ type: 'middleware', description: 'Middleware', suffix: 'middleware', template: MIDDLEWARE_TEMPLATE, alias: 'mw', defaultPath: 'src/middleware', nameRequired: true, nextSteps: ['Import the middleware in your module or apply it globally.'] },
|
|
380
|
-
{ type: 'pipe', description: 'Validation/transform pipe', suffix: 'pipe', template: PIPE_TEMPLATE, nameRequired: true },
|
|
381
|
-
{ type: 'filter', description: 'Exception filter', suffix: 'filter', template: EXCEPTION_FILTER_TEMPLATE, alias: 'f', nameRequired: true },
|
|
382
|
-
{ type: 'repository', description: 'Prisma repository', suffix: 'repository', template: REPOSITORY_TEMPLATE, alias: 'repo', nameRequired: true },
|
|
383
|
-
{ type: 'gateway', description: 'WebSocket gateway', suffix: 'gateway', template: WEBSOCKET_GATEWAY_TEMPLATE, alias: 'ws', nameRequired: true },
|
|
384
|
-
{ type: 'ai-service', description: 'AI service with decorators', suffix: 'ai-service', template: AI_SERVICE_TEMPLATE, alias: 'ai', nameRequired: true },
|
|
385
|
-
{ type: 'agent', description: 'AI agent with @Agent and @Tool', suffix: 'agent', template: AGENT_TEMPLATE, nameRequired: true, extraData: (name) => ({ description: `A ${name} agent` }) },
|
|
386
|
-
{ type: 'cache', description: 'Cache service with decorators', suffix: 'cache', template: CACHE_SERVICE_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/cache', 'Add CacheModule to your module imports', 'Configure the cache strategy (memory, redis, or multi-tier)'] },
|
|
387
|
-
{ type: 'cron', description: 'Cron/scheduled job service', suffix: 'cron', template: CRON_SERVICE_TEMPLATE, alias: 'job', nameRequired: true, nextSteps: ['npm install @hazeljs/cron', 'Add CronModule to your module imports', 'Register this service as a provider'] },
|
|
388
|
-
{ type: 'rag', description: 'RAG (Retrieval-Augmented Generation) service', suffix: 'rag', template: RAG_SERVICE_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/rag', 'Register this service as a provider in your module', 'Configure your embedding provider and vector store'] },
|
|
389
|
-
{ type: 'discovery', description: 'Service discovery setup', suffix: 'discovery', template: DISCOVERY_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/discovery', 'Register this service as a provider in your module', 'Configure your discovery backend (memory, redis, consul, or kubernetes)'] },
|
|
390
|
-
{ type: 'config', description: 'Config module setup', suffix: 'config', template: CONFIG_TEMPLATE, nameRequired: false, nextSteps: ['npm install @hazeljs/config', 'Add ConfigModule.forRoot({ envFilePath: ".env" }) to your app module imports', 'Create a .env file in your project root'] },
|
|
391
|
-
{ type: 'serverless', description: 'Serverless handler (Lambda or Cloud Function)', suffix: 'handler', template: SERVERLESS_LAMBDA_TEMPLATE, alias: 'sls', nameRequired: true, extraOptions: ['platform'] },
|
|
10
|
+
{ type: 'controller', description: 'REST controller', suffix: 'controller', template: templates_1.CONTROLLER_TEMPLATE, alias: 'c', nameRequired: true },
|
|
11
|
+
{ type: 'service', description: 'Service class', suffix: 'service', template: templates_1.SERVICE_TEMPLATE, alias: 's', nameRequired: true },
|
|
12
|
+
{ type: 'guard', description: 'Guard (e.g. auth)', suffix: 'guard', template: templates_1.GUARD_TEMPLATE, alias: 'gu', nameRequired: true },
|
|
13
|
+
{ type: 'interceptor', description: 'Interceptor', suffix: 'interceptor', template: templates_1.INTERCEPTOR_TEMPLATE, alias: 'i', nameRequired: true },
|
|
14
|
+
{ type: 'middleware', description: 'Middleware', suffix: 'middleware', template: templates_1.MIDDLEWARE_TEMPLATE, alias: 'mw', defaultPath: 'src/middleware', nameRequired: true, nextSteps: ['Import the middleware in your module or apply it globally.'] },
|
|
15
|
+
{ type: 'pipe', description: 'Validation/transform pipe', suffix: 'pipe', template: templates_1.PIPE_TEMPLATE, nameRequired: true },
|
|
16
|
+
{ type: 'filter', description: 'Exception filter', suffix: 'filter', template: templates_1.EXCEPTION_FILTER_TEMPLATE, alias: 'f', nameRequired: true },
|
|
17
|
+
{ type: 'repository', description: 'Prisma repository', suffix: 'repository', template: templates_1.REPOSITORY_TEMPLATE, alias: 'repo', nameRequired: true },
|
|
18
|
+
{ type: 'gateway', description: 'WebSocket gateway', suffix: 'gateway', template: templates_1.WEBSOCKET_GATEWAY_TEMPLATE, alias: 'ws', nameRequired: true },
|
|
19
|
+
{ type: 'ai-service', description: 'AI service with decorators', suffix: 'ai-service', template: templates_1.AI_SERVICE_TEMPLATE, alias: 'ai', nameRequired: true },
|
|
20
|
+
{ type: 'agent', description: 'AI agent with @Agent and @Tool', suffix: 'agent', template: templates_1.AGENT_TEMPLATE, nameRequired: true, extraData: (name) => ({ description: `A ${name} agent` }) },
|
|
21
|
+
{ type: 'cache', description: 'Cache service with decorators', suffix: 'cache', template: templates_1.CACHE_SERVICE_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/cache', 'Add CacheModule to your module imports', 'Configure the cache strategy (memory, redis, or multi-tier)'] },
|
|
22
|
+
{ type: 'cron', description: 'Cron/scheduled job service', suffix: 'cron', template: templates_1.CRON_SERVICE_TEMPLATE, alias: 'job', nameRequired: true, nextSteps: ['npm install @hazeljs/cron', 'Add CronModule to your module imports', 'Register this service as a provider'] },
|
|
23
|
+
{ type: 'rag', description: 'RAG (Retrieval-Augmented Generation) service', suffix: 'rag', template: templates_1.RAG_SERVICE_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/rag', 'Register this service as a provider in your module', 'Configure your embedding provider and vector store'] },
|
|
24
|
+
{ type: 'discovery', description: 'Service discovery setup', suffix: 'discovery', template: templates_1.DISCOVERY_TEMPLATE, nameRequired: true, nextSteps: ['npm install @hazeljs/discovery', 'Register this service as a provider in your module', 'Configure your discovery backend (memory, redis, consul, or kubernetes)'] },
|
|
25
|
+
{ type: 'config', description: 'Config module setup', suffix: 'config', template: templates_1.CONFIG_TEMPLATE, nameRequired: false, nextSteps: ['npm install @hazeljs/config', 'Add ConfigModule.forRoot({ envFilePath: ".env" }) to your app module imports', 'Create a .env file in your project root'] },
|
|
26
|
+
{ type: 'serverless', description: 'Serverless handler (Lambda or Cloud Function)', suffix: 'handler', template: templates_1.SERVERLESS_LAMBDA_TEMPLATE, alias: 'sls', nameRequired: true, extraOptions: ['platform'] },
|
|
392
27
|
];
|
|
393
28
|
// ── Runner factory ───────────────────────────────────────────────────────────
|
|
394
29
|
class SimpleGenerator extends generator_1.Generator {
|
|
@@ -402,11 +37,19 @@ class SimpleGenerator extends generator_1.Generator {
|
|
|
402
37
|
return this._template;
|
|
403
38
|
}
|
|
404
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Execute a simple generator given its config, a name, and CLI options.
|
|
42
|
+
*
|
|
43
|
+
* @param config - The SimpleGeneratorConfig entry (from SIMPLE_GENERATORS)
|
|
44
|
+
* @param name - User-provided name (e.g. 'users') — used for file and class names
|
|
45
|
+
* @param options - Standard CLI options (--path, --dry-run, --json, --platform)
|
|
46
|
+
* @returns A GenerateResult with created file paths and optional next steps
|
|
47
|
+
*/
|
|
405
48
|
async function runSimpleGenerator(config, name, options) {
|
|
406
49
|
// Handle serverless platform option
|
|
407
50
|
let template = config.template;
|
|
408
51
|
if (config.type === 'serverless' && options.platform === 'cloud-function') {
|
|
409
|
-
template = SERVERLESS_CLOUD_FUNCTION_TEMPLATE;
|
|
52
|
+
template = templates_1.SERVERLESS_CLOUD_FUNCTION_TEMPLATE;
|
|
410
53
|
}
|
|
411
54
|
const generator = new SimpleGenerator(config.suffix, template);
|
|
412
55
|
const effectiveName = config.nameRequired ? name : (name || 'app');
|
|
@@ -421,7 +64,15 @@ async function runSimpleGenerator(config, name, options) {
|
|
|
421
64
|
}
|
|
422
65
|
return result;
|
|
423
66
|
}
|
|
424
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Register all simple generators as sub-commands of the `hazel generate` command.
|
|
69
|
+
*
|
|
70
|
+
* Iterates over SIMPLE_GENERATORS and creates a Commander sub-command for each,
|
|
71
|
+
* wiring up aliases, options (--path, --dry-run, --json, plus any extraOptions),
|
|
72
|
+
* and the action handler that calls runSimpleGenerator.
|
|
73
|
+
*
|
|
74
|
+
* @param generateCommand - The Commander `generate` parent command to attach sub-commands to
|
|
75
|
+
*/
|
|
425
76
|
function registerSimpleGenerators(generateCommand) {
|
|
426
77
|
for (const config of exports.SIMPLE_GENERATORS) {
|
|
427
78
|
const cmdStr = config.nameRequired ? `${config.type} <name>` : config.type;
|
|
@@ -442,7 +93,12 @@ function registerSimpleGenerators(generateCommand) {
|
|
|
442
93
|
});
|
|
443
94
|
}
|
|
444
95
|
}
|
|
445
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Look up a SimpleGeneratorConfig by its type name (e.g. 'controller', 'agent').
|
|
98
|
+
*
|
|
99
|
+
* @param type - The generator type to find
|
|
100
|
+
* @returns The matching config, or undefined if no simple generator matches
|
|
101
|
+
*/
|
|
446
102
|
function findSimpleGenerator(type) {
|
|
447
103
|
return exports.SIMPLE_GENERATORS.find((g) => g.type === type);
|
|
448
104
|
}
|
package/dist/commands/info.d.ts
CHANGED
|
@@ -1,2 +1,14 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Register the `hazel info` command.
|
|
4
|
+
*
|
|
5
|
+
* Reads the current directory's package.json and displays:
|
|
6
|
+
* - Project name, version, description
|
|
7
|
+
* - Installed @hazeljs/* packages with versions
|
|
8
|
+
* - src/ directory listing
|
|
9
|
+
* - Node.js version, platform, architecture
|
|
10
|
+
* - Detected configuration files (tsconfig, .env, eslint, etc.)
|
|
11
|
+
*
|
|
12
|
+
* @param program - The root Commander program instance
|
|
13
|
+
*/
|
|
2
14
|
export declare function infoCommand(program: Command): void;
|
package/dist/commands/info.js
CHANGED
|
@@ -7,6 +7,18 @@ exports.infoCommand = infoCommand;
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
/**
|
|
11
|
+
* Register the `hazel info` command.
|
|
12
|
+
*
|
|
13
|
+
* Reads the current directory's package.json and displays:
|
|
14
|
+
* - Project name, version, description
|
|
15
|
+
* - Installed @hazeljs/* packages with versions
|
|
16
|
+
* - src/ directory listing
|
|
17
|
+
* - Node.js version, platform, architecture
|
|
18
|
+
* - Detected configuration files (tsconfig, .env, eslint, etc.)
|
|
19
|
+
*
|
|
20
|
+
* @param program - The root Commander program instance
|
|
21
|
+
*/
|
|
10
22
|
function infoCommand(program) {
|
|
11
23
|
program
|
|
12
24
|
.command('info')
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mustache templates for all simple (single-file) generators.
|
|
3
|
+
*
|
|
4
|
+
* Each template uses three standard variables provided by the Generator base class:
|
|
5
|
+
* - {{className}} — PascalCase name (e.g. "Users")
|
|
6
|
+
* - {{fileName}} — kebab-case name (e.g. "users")
|
|
7
|
+
* - {{camelName}} — camelCase name (e.g. "users")
|
|
8
|
+
*
|
|
9
|
+
* Some templates accept additional data via `extraData` in SimpleGeneratorConfig:
|
|
10
|
+
* - AGENT_TEMPLATE — {{description}}
|
|
11
|
+
* - REPOSITORY_TEMPLATE — {{modelName}} (defaults to fileName)
|
|
12
|
+
*
|
|
13
|
+
* Templates are imported by generate-simple.ts and referenced in the
|
|
14
|
+
* SIMPLE_GENERATORS config array. To add a new generator, create a template
|
|
15
|
+
* here and add a config entry in generate-simple.ts.
|
|
16
|
+
*/
|
|
17
|
+
export declare const CONTROLLER_TEMPLATE = "import { Controller, Get, Post, Body, Param, Delete, Put } from '@hazeljs/core';\nimport { {{className}}Service } from './{{fileName}}.service';\nimport { Create{{className}}Dto } from './dto/create-{{fileName}}.dto';\nimport { Update{{className}}Dto } from './dto/update-{{fileName}}.dto';\n\n@Controller('{{fileName}}')\nexport class {{className}}Controller {\n constructor(private readonly {{camelName}}Service: {{className}}Service) {}\n\n @Get()\n findAll() {\n return this.{{camelName}}Service.findAll();\n }\n\n @Get(':id')\n findOne(@Param('id') id: string) {\n return this.{{camelName}}Service.findOne(id);\n }\n\n @Post()\n create(@Body(Create{{className}}Dto) createDto: Create{{className}}Dto) {\n return this.{{camelName}}Service.create(createDto);\n }\n\n @Put(':id')\n update(@Param('id') id: string, @Body(Update{{className}}Dto) updateDto: Update{{className}}Dto) {\n return this.{{camelName}}Service.update(id, updateDto);\n }\n\n @Delete(':id')\n remove(@Param('id') id: string) {\n return this.{{camelName}}Service.remove(id);\n }\n}\n";
|
|
18
|
+
export declare const SERVICE_TEMPLATE = "import { Service } from '@hazeljs/core';\n\n@Service()\nexport class {{className}}Service {\n constructor() {}\n\n async findAll() {\n return [];\n }\n\n async findOne(id: string) {\n return { id };\n }\n\n async create(createDto: any) {\n return createDto;\n }\n\n async update(id: string, updateDto: any) {\n return { id, ...updateDto };\n }\n\n async remove(id: string) {\n return { id };\n }\n}\n";
|
|
19
|
+
export declare const GUARD_TEMPLATE = "import { Injectable, type CanActivate, type ExecutionContext } from '@hazeljs/core';\n\n@Injectable()\nexport class {{className}}Guard implements CanActivate {\n canActivate(context: ExecutionContext): boolean {\n const request = context.switchToHttp().getRequest();\n // Add your guard logic here\n return true;\n }\n}\n";
|
|
20
|
+
export declare const INTERCEPTOR_TEMPLATE = "import { Injectable, Interceptor, type ExecutionContext } from '@hazeljs/core';\n\n@Injectable()\nexport class {{className}}Interceptor implements Interceptor {\n async intercept(context: ExecutionContext, next: () => Promise<unknown>): Promise<unknown> {\n // Pre-processing logic here (before handler execution)\n const result = await next();\n // Post-processing logic here (after handler execution)\n return result;\n }\n}\n";
|
|
21
|
+
export declare const MIDDLEWARE_TEMPLATE = "import { Injectable, type MiddlewareHandler, type Request, type Response, type NextFunction } from '@hazeljs/core';\n\n@Injectable()\nexport class {{className}}Middleware implements MiddlewareHandler {\n use(req: Request, res: Response, next: NextFunction) {\n // Add your middleware logic here\n console.log(`[{{className}}Middleware] ${req.method} ${req.url}`);\n \n // Continue to next middleware\n next();\n }\n}\n";
|
|
22
|
+
export declare const PIPE_TEMPLATE = "import { type PipeTransform, type RequestContext } from '@hazeljs/core';\n\nexport class {{className}}Pipe implements PipeTransform {\n transform(value: unknown, context: RequestContext): unknown {\n // Transform logic here\n return value;\n }\n}\n";
|
|
23
|
+
export declare const EXCEPTION_FILTER_TEMPLATE = "import { Catch, type ExceptionFilter, type ArgumentsHost, HttpError, logger } from '@hazeljs/core';\n\n@Catch(HttpError)\nexport class {{className}}ExceptionFilter implements ExceptionFilter<HttpError> {\n catch(exception: HttpError, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse();\n const request = ctx.getRequest();\n\n const status = exception.statusCode || 500;\n const message = exception.message || 'Internal server error';\n\n logger.error(`[${request.method}] ${request.url} - ${message} (${status})`);\n\n response.status(status).json({\n statusCode: status,\n message,\n timestamp: new Date().toISOString(),\n path: request.url,\n });\n }\n}\n";
|
|
24
|
+
export declare const REPOSITORY_TEMPLATE = "import { Repository, BaseRepository, PrismaService } from '@hazeljs/prisma';\n\n// @Repository implies @Injectable() \u2014 no need for both decorators\n@Repository({ model: '{{modelName}}' })\nexport class {{className}}Repository extends BaseRepository<any> {\n constructor(prisma: PrismaService) {\n super(prisma, '{{modelName}}');\n }\n\n // Add custom repository methods here\n async findByName(name: string) {\n return this.findMany({ where: { name } });\n }\n}\n";
|
|
25
|
+
export declare const WEBSOCKET_GATEWAY_TEMPLATE = "import { Realtime, OnConnect, OnDisconnect, OnMessage, Subscribe, Client, Data, WebSocketClient } from '@hazeljs/websocket';\n\n@Realtime('/{{fileName}}')\nexport class {{className}}Gateway {\n @OnConnect()\n handleConnection(@Client() client: WebSocketClient) {\n console.log('Client connected:', client.id);\n }\n\n @OnDisconnect()\n handleDisconnect(@Client() client: WebSocketClient) {\n console.log('Client disconnected:', client.id);\n }\n\n @Subscribe('message')\n @OnMessage('message')\n handleMessage(@Client() client: WebSocketClient, @Data() data: unknown) {\n console.log('Message received from', client.id, ':', data);\n // Handle message logic here\n }\n}\n";
|
|
26
|
+
export declare const AI_SERVICE_TEMPLATE = "import { Service } from '@hazeljs/core';\nimport { AIService, AIFunction, AIPrompt } from '@hazeljs/ai';\n\n@Service()\nexport class {{className}}AIService {\n constructor(private readonly aiService: AIService) {}\n\n @AIFunction({\n provider: 'openai',\n model: 'gpt-4',\n streaming: false,\n })\n async {{camelName}}Task(@AIPrompt() prompt: string): Promise<unknown> {\n const result = await this.aiService.complete({\n provider: 'openai',\n model: 'gpt-4',\n messages: [{ role: 'user', content: prompt }],\n });\n\n return result;\n }\n}\n";
|
|
27
|
+
export declare const AGENT_TEMPLATE = "import { Agent, Tool } from '@hazeljs/agent';\n\n@Agent({\n name: '{{fileName}}',\n description: '{{description}}',\n systemPrompt: 'You are a helpful {{className}} agent.',\n enableMemory: true,\n enableRAG: true,\n})\nexport class {{className}}Agent {\n @Tool({\n description: 'Example tool for {{fileName}}',\n parameters: [\n {\n name: 'input',\n type: 'string',\n description: 'Input parameter',\n required: true,\n },\n ],\n })\n async exampleTool(input: { input: string }): Promise<{ result: string }> {\n // Implement your tool logic here\n return {\n result: `Processed: ${input.input}`,\n };\n }\n}\n";
|
|
28
|
+
export declare const CACHE_SERVICE_TEMPLATE = "import { Service } from '@hazeljs/core';\nimport { CacheService, Cacheable, CacheEvict } from '@hazeljs/cache';\n\n@Service()\nexport class {{className}}CacheService {\n constructor(private readonly cacheService: CacheService) {}\n\n @Cacheable({ key: '{{fileName}}:all', ttl: 60 })\n async findAll() {\n // This result will be cached for 60 seconds\n return [];\n }\n\n @Cacheable({ key: '{{fileName}}:{{=<% %>=}}#{id}<%={{ }}=%>', ttl: 300 })\n async findOne(id: string) {\n // This result will be cached for 5 minutes\n return { id };\n }\n\n @CacheEvict({ key: '{{fileName}}:all' })\n async create(data: any) {\n // Creating a new item evicts the list cache\n return data;\n }\n\n async clearAll() {\n await this.cacheService.clear();\n }\n}\n";
|
|
29
|
+
export declare const CRON_SERVICE_TEMPLATE = "import { Service } from '@hazeljs/core';\nimport { Cron, CronExpression } from '@hazeljs/cron';\n\n@Service()\nexport class {{className}}CronService {\n @Cron(CronExpression.EVERY_MINUTE)\n handleEveryMinute() {\n console.log('[{{className}}Cron] Running every minute...');\n // Add your cron job logic here\n }\n\n @Cron('0 0 * * *') // Every day at midnight\n handleDaily() {\n console.log('[{{className}}Cron] Running daily task...');\n // Add your daily task logic here\n }\n\n @Cron(CronExpression.EVERY_HOUR)\n handleHourly() {\n console.log('[{{className}}Cron] Running hourly cleanup...');\n // Add your hourly task logic here\n }\n}\n";
|
|
30
|
+
export declare const RAG_SERVICE_TEMPLATE = "import { Service } from '@hazeljs/core';\nimport { RAGPipeline, MemoryVectorStore } from '@hazeljs/rag';\n\n@Service()\nexport class {{className}}RagService {\n private pipeline: RAGPipeline;\n\n constructor() {\n // Initialize with a memory vector store (swap for Pinecone, Qdrant, etc. in production)\n const vectorStore = new MemoryVectorStore();\n\n this.pipeline = new RAGPipeline({\n vectorStore,\n topK: 5,\n });\n }\n\n async addDocument(content: string, metadata?: Record<string, unknown>) {\n // Add a document to the vector store for retrieval\n await this.pipeline.addDocument({\n content,\n metadata: metadata || {},\n });\n }\n\n async query(question: string) {\n // Retrieve relevant documents and generate a response\n const results = await this.pipeline.query(question);\n return results;\n }\n}\n";
|
|
31
|
+
export declare const DISCOVERY_TEMPLATE = "import { Service } from '@hazeljs/core';\nimport { ServiceRegistry, DiscoveryClient } from '@hazeljs/discovery';\n\n@Service()\nexport class {{className}}DiscoveryService {\n constructor(\n private readonly registry: ServiceRegistry,\n private readonly client: DiscoveryClient,\n ) {}\n\n async registerService() {\n await this.registry.register({\n name: '{{fileName}}-service',\n host: 'localhost',\n port: 3000,\n metadata: {\n version: '1.0.0',\n },\n });\n }\n\n async discoverService(serviceName: string) {\n const instances = await this.client.getInstances(serviceName);\n return instances;\n }\n}\n";
|
|
32
|
+
export declare const CONFIG_TEMPLATE = "import { HazelModule } from '@hazeljs/core';\nimport { ConfigModule, ConfigService } from '@hazeljs/config';\n\n// Import ConfigModule.forRoot() in your app module:\n//\n// @HazelModule({\n// imports: [\n// ConfigModule.forRoot({\n// envFilePath: '.env',\n// }),\n// ],\n// })\n//\n// Then inject ConfigService wherever you need it:\n//\n// constructor(private readonly config: ConfigService) {}\n//\n// Usage:\n// this.config.get('DATABASE_URL');\n// this.config.get('PORT', '3000'); // with default value\n\nexport { ConfigModule, ConfigService };\n";
|
|
33
|
+
export declare const SERVERLESS_LAMBDA_TEMPLATE = "import { createLambdaHandler } from '@hazeljs/serverless';\nimport { AppModule } from './app.module';\n\nexport const handler = createLambdaHandler(AppModule);\n";
|
|
34
|
+
export declare const SERVERLESS_CLOUD_FUNCTION_TEMPLATE = "import { createCloudFunctionHandler } from '@hazeljs/serverless';\nimport { AppModule } from './app.module';\n\nexport const handler = createCloudFunctionHandler(AppModule);\n";
|