fragment-ts 1.0.0

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 (123) hide show
  1. package/.env.example +0 -0
  2. package/base.ts +1810 -0
  3. package/base2.ts +968 -0
  4. package/bin/frg.ts +5 -0
  5. package/config/fragment.lock.yaml +0 -0
  6. package/config/fragment.yaml +0 -0
  7. package/dist/app.d.ts +15 -0
  8. package/dist/app.js +90 -0
  9. package/dist/auth/auth.controller.d.ts +10 -0
  10. package/dist/auth/auth.controller.js +87 -0
  11. package/dist/auth/auth.middleware.d.ts +2 -0
  12. package/dist/auth/auth.middleware.js +24 -0
  13. package/dist/auth/auth.service.d.ts +20 -0
  14. package/dist/auth/auth.service.js +143 -0
  15. package/dist/auth/dto/login.dto.d.ts +9 -0
  16. package/dist/auth/dto/login.dto.js +2 -0
  17. package/dist/cli/cli.d.ts +12 -0
  18. package/dist/cli/cli.js +186 -0
  19. package/dist/cli/commands/build.command.d.ts +3 -0
  20. package/dist/cli/commands/build.command.js +23 -0
  21. package/dist/cli/commands/config.command.d.ts +6 -0
  22. package/dist/cli/commands/config.command.js +284 -0
  23. package/dist/cli/commands/generate.command.d.ts +8 -0
  24. package/dist/cli/commands/generate.command.js +180 -0
  25. package/dist/cli/commands/init.command.d.ts +7 -0
  26. package/dist/cli/commands/init.command.js +380 -0
  27. package/dist/cli/commands/migrate.command.d.ts +7 -0
  28. package/dist/cli/commands/migrate.command.js +116 -0
  29. package/dist/cli/commands/serve.command.d.ts +6 -0
  30. package/dist/cli/commands/serve.command.js +31 -0
  31. package/dist/cli/templates/controller.template.d.ts +1 -0
  32. package/dist/cli/templates/controller.template.js +52 -0
  33. package/dist/cli/templates/entity.template.d.ts +1 -0
  34. package/dist/cli/templates/entity.template.js +23 -0
  35. package/dist/cli/templates/repository.template.d.ts +1 -0
  36. package/dist/cli/templates/repository.template.js +43 -0
  37. package/dist/cli/templates/service.template.d.ts +1 -0
  38. package/dist/cli/templates/service.template.js +43 -0
  39. package/dist/cli/utils/file-generator.d.ts +9 -0
  40. package/dist/cli/utils/file-generator.js +67 -0
  41. package/dist/cli/utils/logger.d.ts +14 -0
  42. package/dist/cli/utils/logger.js +49 -0
  43. package/dist/controllers/health.controller.d.ts +13 -0
  44. package/dist/controllers/health.controller.js +50 -0
  45. package/dist/core/config/config-loader.d.ts +31 -0
  46. package/dist/core/config/config-loader.js +98 -0
  47. package/dist/core/container/di-container.d.ts +9 -0
  48. package/dist/core/container/di-container.js +37 -0
  49. package/dist/core/decorators/auth-guard.decorator.d.ts +3 -0
  50. package/dist/core/decorators/auth-guard.decorator.js +18 -0
  51. package/dist/core/decorators/autowire.decorator.d.ts +3 -0
  52. package/dist/core/decorators/autowire.decorator.js +17 -0
  53. package/dist/core/decorators/controller.decorator.d.ts +4 -0
  54. package/dist/core/decorators/controller.decorator.js +16 -0
  55. package/dist/core/decorators/injectable.decorator.d.ts +3 -0
  56. package/dist/core/decorators/injectable.decorator.js +14 -0
  57. package/dist/core/decorators/middleware.decorator.d.ts +3 -0
  58. package/dist/core/decorators/middleware.decorator.js +20 -0
  59. package/dist/core/decorators/repository.decorator.d.ts +1 -0
  60. package/dist/core/decorators/repository.decorator.js +7 -0
  61. package/dist/core/decorators/route.decorator.d.ts +14 -0
  62. package/dist/core/decorators/route.decorator.js +32 -0
  63. package/dist/core/decorators/service.decorator.d.ts +1 -0
  64. package/dist/core/decorators/service.decorator.js +7 -0
  65. package/dist/core/openai/openai-client.d.ts +12 -0
  66. package/dist/core/openai/openai-client.js +93 -0
  67. package/dist/database/data-source.d.ts +4 -0
  68. package/dist/database/data-source.js +26 -0
  69. package/dist/entities/session.entity.d.ts +9 -0
  70. package/dist/entities/session.entity.js +45 -0
  71. package/dist/entities/user.entity.d.ts +10 -0
  72. package/dist/entities/user.entity.js +48 -0
  73. package/dist/middlewares/logging.middleware.d.ts +2 -0
  74. package/dist/middlewares/logging.middleware.js +28 -0
  75. package/dist/repositories/session.repository.d.ts +9 -0
  76. package/dist/repositories/session.repository.js +50 -0
  77. package/dist/repositories/user.repository.d.ts +10 -0
  78. package/dist/repositories/user.repository.js +43 -0
  79. package/dist/server.d.ts +1 -0
  80. package/dist/server.js +30 -0
  81. package/dist/services/health.service.d.ts +13 -0
  82. package/dist/services/health.service.js +44 -0
  83. package/package.json +46 -0
  84. package/readme.md +120 -0
  85. package/src/app.ts +121 -0
  86. package/src/auth/auth.controller.ts +52 -0
  87. package/src/auth/auth.middleware.ts +27 -0
  88. package/src/auth/auth.service.ts +110 -0
  89. package/src/auth/dto/login.dto.ts +11 -0
  90. package/src/cli/cli.ts +212 -0
  91. package/src/cli/commands/build.command.ts +24 -0
  92. package/src/cli/commands/config.command.ts +280 -0
  93. package/src/cli/commands/generate.command.ts +170 -0
  94. package/src/cli/commands/init.command.ts +395 -0
  95. package/src/cli/commands/migrate.command.ts +118 -0
  96. package/src/cli/commands/serve.command.ts +37 -0
  97. package/src/cli/templates/controller.template.ts +51 -0
  98. package/src/cli/templates/entity.template.ts +22 -0
  99. package/src/cli/templates/repository.template.ts +42 -0
  100. package/src/cli/templates/service.template.ts +42 -0
  101. package/src/cli/utils/file-generator.ts +37 -0
  102. package/src/cli/utils/logger.ts +52 -0
  103. package/src/controllers/health.controller.ts +24 -0
  104. package/src/core/config/config-loader.ts +98 -0
  105. package/src/core/container/di-container.ts +43 -0
  106. package/src/core/decorators/auth-guard.decorator.ts +15 -0
  107. package/src/core/decorators/autowire.decorator.ts +18 -0
  108. package/src/core/decorators/controller.decorator.ts +15 -0
  109. package/src/core/decorators/injectable.decorator.ts +13 -0
  110. package/src/core/decorators/middleware.decorator.ts +18 -0
  111. package/src/core/decorators/repository.decorator.ts +6 -0
  112. package/src/core/decorators/route.decorator.ts +33 -0
  113. package/src/core/decorators/service.decorator.ts +6 -0
  114. package/src/core/openai/openai-client.ts +99 -0
  115. package/src/database/data-source.ts +29 -0
  116. package/src/entities/session.entity.ts +25 -0
  117. package/src/entities/user.entity.ts +27 -0
  118. package/src/middlewares/logging.middleware.ts +28 -0
  119. package/src/repositories/session.repository.ts +42 -0
  120. package/src/repositories/user.repository.ts +37 -0
  121. package/src/server.ts +32 -0
  122. package/src/services/health.service.ts +29 -0
  123. package/tsconfig.json +20 -0
package/src/app.ts ADDED
@@ -0,0 +1,121 @@
1
+
2
+ import express, { Express, Request, Response, NextFunction } from 'express';
3
+ import { DIContainer } from './core/container/di-container';
4
+ import { ConfigLoader } from './core/config/config-loader';
5
+ import { initializeDataSource, AppDataSource } from './database/data-source';
6
+ import { loggingMiddleware } from './middlewares/logging.middleware';
7
+ import { authMiddleware } from './auth/auth.middleware';
8
+ import {
9
+ CONTROLLER_METADATA,
10
+ CONTROLLER_PATH
11
+ } from './core/decorators/controller.decorator';
12
+ import {
13
+ ROUTE_METADATA
14
+ } from './core/decorators/route.decorator';
15
+ import {
16
+ AUTH_GUARD_METADATA
17
+ } from './core/decorators/auth-guard.decorator';
18
+ import {
19
+ MIDDLEWARE_METADATA
20
+ } from './core/decorators/middleware.decorator';
21
+
22
+ // Import all controllers, services, repositories
23
+ import './controllers/health.controller';
24
+ import './auth/auth.controller';
25
+ import './services/health.service';
26
+ import './repositories/user.repository';
27
+ import './repositories/session.repository';
28
+ import './auth/auth.service';
29
+ import './core/openai/openai-client';
30
+
31
+ export class FragmentApplication {
32
+ private app: Express;
33
+
34
+ constructor() {
35
+ this.app = express();
36
+ }
37
+
38
+ async initialize(): Promise<Express> {
39
+ // Load configuration
40
+ ConfigLoader.load(true);
41
+
42
+ // Initialize database
43
+ const dataSource = initializeDataSource();
44
+ await dataSource.initialize();
45
+ console.log('✅ Database connected');
46
+
47
+ // Middleware
48
+ this.app.use(express.json());
49
+ this.app.use(express.urlencoded({ extended: true }));
50
+ this.app.use(loggingMiddleware);
51
+
52
+ // Register all controllers
53
+ this.registerControllers();
54
+
55
+ // Error handling
56
+ this.app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
57
+ console.error(err.stack);
58
+ res.status(500).json({ error: 'Internal server error' });
59
+ });
60
+
61
+ return this.app;
62
+ }
63
+
64
+ private registerControllers(): void {
65
+ const registeredClasses = DIContainer.getRegisteredClasses();
66
+
67
+ registeredClasses.forEach((controllerClass) => {
68
+ const isController = Reflect.getMetadata(CONTROLLER_METADATA, controllerClass);
69
+ if (!isController) return;
70
+
71
+ const basePath = Reflect.getMetadata(CONTROLLER_PATH, controllerClass) || '';
72
+ const routes = Reflect.getMetadata(ROUTE_METADATA, controllerClass) || [];
73
+ const classMiddlewares = Reflect.getMetadata(MIDDLEWARE_METADATA, controllerClass) || [];
74
+ const classAuthGuard = Reflect.getMetadata(AUTH_GUARD_METADATA, controllerClass);
75
+
76
+ const controllerInstance = DIContainer.resolve(controllerClass) as any;
77
+
78
+ routes.forEach((route: any) => {
79
+ const fullPath = basePath + route.path;
80
+ const handler = controllerInstance[route.handlerName].bind(controllerInstance);
81
+
82
+ const middlewares: any[] = [...classMiddlewares];
83
+
84
+ const methodAuthGuard = Reflect.getMetadata(
85
+ AUTH_GUARD_METADATA,
86
+ controllerClass,
87
+ route.handlerName
88
+ );
89
+ if (classAuthGuard || methodAuthGuard) {
90
+ middlewares.push(authMiddleware);
91
+ }
92
+
93
+ const methodMiddlewares = Reflect.getMetadata(
94
+ MIDDLEWARE_METADATA,
95
+ controllerClass,
96
+ route.handlerName
97
+ ) || [];
98
+ middlewares.push(...methodMiddlewares);
99
+
100
+ const asyncHandler = async (req: Request, res: Response, next: NextFunction) => {
101
+ try {
102
+ const result = await handler(req, res, next);
103
+ if (result && !res.headersSent) {
104
+ res.json(result);
105
+ }
106
+ } catch (error) {
107
+ next(error);
108
+ }
109
+ };
110
+
111
+ (this.app as any)[route.method](fullPath, ...middlewares, asyncHandler);
112
+
113
+ console.log(`📍 ${route.method.toUpperCase().padEnd(6)} ${fullPath}`);
114
+ });
115
+ });
116
+ }
117
+
118
+ getExpressApp(): Express {
119
+ return this.app;
120
+ }
121
+ }
@@ -0,0 +1,52 @@
1
+
2
+ import { Controller } from '../core/decorators/controller.decorator';
3
+ import { Post, Get } from '../core/decorators/route.decorator';
4
+ import { Injectable } from '../core/decorators/injectable.decorator';
5
+ import { Autowire } from '../core/decorators/autowire.decorator';
6
+ import { AuthGuard } from '../core/decorators/auth-guard.decorator';
7
+ import { AuthService } from './auth.service';
8
+ import { Request, Response } from 'express';
9
+
10
+ @Controller('/api/auth')
11
+ @Injectable()
12
+ export class AuthController {
13
+ constructor(
14
+ @Autowire() private authService: AuthService
15
+ ) {}
16
+
17
+ @Post('/register')
18
+ async register(req: Request, res: Response) {
19
+ try {
20
+ const result = await this.authService.register(req.body);
21
+ return res.json(result);
22
+ } catch (error: any) {
23
+ return res.status(400).json({ error: error.message });
24
+ }
25
+ }
26
+
27
+ @Post('/login')
28
+ async login(req: Request, res: Response) {
29
+ try {
30
+ const result = await this.authService.login(req.body);
31
+ return res.json(result);
32
+ } catch (error: any) {
33
+ return res.status(401).json({ error: error.message });
34
+ }
35
+ }
36
+
37
+ @Post('/logout')
38
+ @AuthGuard()
39
+ async logout(req: Request, res: Response) {
40
+ const token = req.headers.authorization?.replace('Bearer ', '');
41
+ if (token) {
42
+ await this.authService.logout(token);
43
+ }
44
+ return res.json({ message: 'Logged out successfully' });
45
+ }
46
+
47
+ @Get('/me')
48
+ @AuthGuard()
49
+ async getCurrentUser(req: Request, res: Response) {
50
+ return res.json({ user: (req as any).user });
51
+ }
52
+ }
@@ -0,0 +1,27 @@
1
+
2
+ import { Request, Response, NextFunction } from 'express';
3
+ import { DIContainer } from '../core/container/di-container';
4
+ import { AuthService } from './auth.service';
5
+
6
+ export async function authMiddleware(req: Request, res: Response, next: NextFunction) {
7
+ const authHeader = req.headers.authorization;
8
+
9
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
10
+ return res.status(401).json({ error: 'Unauthorized' });
11
+ }
12
+
13
+ const token = authHeader.replace('Bearer ', '');
14
+ const authService = DIContainer.resolve<AuthService>(AuthService);
15
+
16
+ try {
17
+ const user = await authService.validateToken(token);
18
+ if (!user) {
19
+ return res.status(401).json({ error: 'Invalid token' });
20
+ }
21
+
22
+ (req as any).user = user;
23
+ next();
24
+ } catch (error) {
25
+ return res.status(401).json({ error: 'Unauthorized' });
26
+ }
27
+ }
@@ -0,0 +1,110 @@
1
+
2
+ import * as crypto from 'crypto';
3
+ import * as bcrypt from 'bcrypt';
4
+ import { Service } from '../core/decorators/service.decorator';
5
+ import { Autowire } from '../core/decorators/autowire.decorator';
6
+ import { UserRepository } from '../repositories/user.repository';
7
+ import { SessionRepository } from '../repositories/session.repository';
8
+ import { LoginDTO, RegisterDTO } from './dto/login.dto';
9
+ import { ConfigLoader } from '../core/config/config-loader';
10
+
11
+ @Service()
12
+ export class AuthService {
13
+ constructor(
14
+ @Autowire() private userRepository: UserRepository,
15
+ @Autowire() private sessionRepository: SessionRepository
16
+ ) {}
17
+
18
+ async register(dto: RegisterDTO): Promise<{ user: any; token: string }> {
19
+ const existingUser = await this.userRepository.findByEmail(dto.email);
20
+ if (existingUser) {
21
+ throw new Error('User already exists');
22
+ }
23
+
24
+ const passwordHash = await bcrypt.hash(dto.password, 10);
25
+ const user = await this.userRepository.create({
26
+ name: dto.name,
27
+ email: dto.email,
28
+ passwordHash
29
+ });
30
+
31
+ const token = await this.createSession(user.id);
32
+
33
+ return {
34
+ user: { id: user.id, name: user.name, email: user.email },
35
+ token
36
+ };
37
+ }
38
+
39
+ async login(dto: LoginDTO): Promise<{ user: any; token: string }> {
40
+ const user = await this.userRepository.findByEmail(dto.email);
41
+ if (!user) {
42
+ throw new Error('Invalid credentials');
43
+ }
44
+
45
+ const isValidPassword = await bcrypt.compare(dto.password, user.passwordHash);
46
+ if (!isValidPassword) {
47
+ throw new Error('Invalid credentials');
48
+ }
49
+
50
+ const token = await this.createSession(user.id);
51
+
52
+ return {
53
+ user: { id: user.id, name: user.name, email: user.email },
54
+ token
55
+ };
56
+ }
57
+
58
+ async logout(token: string): Promise<void> {
59
+ await this.sessionRepository.deleteByToken(token);
60
+ }
61
+
62
+ async validateToken(token: string): Promise<any> {
63
+ const session = await this.sessionRepository.findByToken(token);
64
+ if (!session) {
65
+ return null;
66
+ }
67
+
68
+ return {
69
+ id: session.user.id,
70
+ name: session.user.name,
71
+ email: session.user.email
72
+ };
73
+ }
74
+
75
+ private async createSession(userId: number): Promise<string> {
76
+ const token = crypto.randomBytes(32).toString('hex');
77
+ const config = ConfigLoader.get();
78
+
79
+ // Parse token expiry (e.g., "7d" = 7 days)
80
+ const expiryMs = this.parseExpiry(config.auth.tokenExpiry);
81
+ const expiresAt = new Date(Date.now() + expiryMs);
82
+
83
+ await this.sessionRepository.create({
84
+ token,
85
+ userId,
86
+ expiresAt
87
+ });
88
+
89
+ return token;
90
+ }
91
+
92
+ private parseExpiry(expiry: string): number {
93
+ const match = expiry.match(/^(\d+)([dhms])$/);
94
+ if (!match) {
95
+ return 7 * 24 * 60 * 60 * 1000; // default 7 days
96
+ }
97
+
98
+ const value = parseInt(match[1]);
99
+ const unit = match[2];
100
+
101
+ const multipliers: { [key: string]: number } = {
102
+ 's': 1000,
103
+ 'm': 60 * 1000,
104
+ 'h': 60 * 60 * 1000,
105
+ 'd': 24 * 60 * 60 * 1000
106
+ };
107
+
108
+ return value * multipliers[unit];
109
+ }
110
+ }
@@ -0,0 +1,11 @@
1
+
2
+ export interface LoginDTO {
3
+ email: string;
4
+ password: string;
5
+ }
6
+
7
+ export interface RegisterDTO {
8
+ name: string;
9
+ email: string;
10
+ password: string;
11
+ }
package/src/cli/cli.ts ADDED
@@ -0,0 +1,212 @@
1
+
2
+ import chalk from 'chalk';
3
+ import { Command } from 'commander';
4
+ import { InitCommand } from './commands/init.command';
5
+ import { GenerateCommand } from './commands/generate.command';
6
+ import { ConfigCommand } from './commands/config.command';
7
+ import { ServeCommand } from './commands/serve.command';
8
+ import { BuildCommand } from './commands/build.command';
9
+ import { MigrateCommand } from './commands/migrate.command';
10
+ import { CLILogger } from './utils/logger';
11
+
12
+ export class CLI {
13
+ private program: Command;
14
+ private initCommand: InitCommand;
15
+ private generateCommand: GenerateCommand;
16
+ private configCommand: ConfigCommand;
17
+ private serveCommand: ServeCommand;
18
+ private buildCommand: BuildCommand;
19
+ private migrateCommand: MigrateCommand;
20
+
21
+ constructor() {
22
+ this.program = new Command();
23
+ this.initCommand = new InitCommand();
24
+ this.generateCommand = new GenerateCommand();
25
+ this.configCommand = new ConfigCommand();
26
+ this.serveCommand = new ServeCommand();
27
+ this.buildCommand = new BuildCommand();
28
+ this.migrateCommand = new MigrateCommand();
29
+
30
+ this.setupCommands();
31
+ }
32
+
33
+ private setupCommands(): void {
34
+ this.program
35
+ .name('frg')
36
+ .description('Fragment Framework CLI - Build powerful TypeScript backends')
37
+ .version('1.0.0');
38
+
39
+ // ASCII Art Banner
40
+ this.program
41
+ .addHelpText('beforeAll', () => {
42
+ return chalk.cyan(`
43
+ ╔═══════════════════════════════════════════════════════════╗
44
+ ║ ║
45
+ ║ ███████╗██████╗ █████╗ ██████╗ ███╗ ███╗███████╗ ║
46
+ ║ ██╔════╝██╔══██╗██╔══██╗██╔════╝ ████╗ ████║██╔════╝ ║
47
+ ║ █████╗ ██████╔╝███████║██║ ███╗██╔████╔██║█████╗ ║
48
+ ║ ██╔══╝ ██╔══██╗██╔══██║██║ ██║██║╚██╔╝██║██╔══╝ ║
49
+ ║ ██║ ██║ ██║██║ ██║╚██████╔╝██║ ╚═╝ ██║███████╗ ║
50
+ ║ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ║
51
+ ║ ║
52
+ ║ TypeScript Backend Framework (v1.0.0) ║
53
+ ╚═══════════════════════════════════════════════════════════╝
54
+ `);
55
+ });
56
+
57
+ // Init command
58
+ this.program
59
+ .command('init [project-name]')
60
+ .description('Initialize a new Fragment project')
61
+ .action(async (projectName) => {
62
+ await this.initCommand.execute(projectName);
63
+ });
64
+
65
+ // Generate commands
66
+ const generate = this.program
67
+ .command('generate')
68
+ .alias('g')
69
+ .description('Generate application components');
70
+
71
+ generate
72
+ .command('controller [name]')
73
+ .alias('c')
74
+ .description('Generate a new controller')
75
+ .action(async (name) => {
76
+ await this.generateCommand.execute('controller', name);
77
+ });
78
+
79
+ generate
80
+ .command('service [name]')
81
+ .alias('s')
82
+ .description('Generate a new service')
83
+ .action(async (name) => {
84
+ await this.generateCommand.execute('service', name);
85
+ });
86
+
87
+ generate
88
+ .command('repository [name]')
89
+ .alias('r')
90
+ .description('Generate a new repository')
91
+ .action(async (name) => {
92
+ await this.generateCommand.execute('repository', name);
93
+ });
94
+
95
+ generate
96
+ .command('entity [name]')
97
+ .alias('e')
98
+ .description('Generate a new entity')
99
+ .action(async (name) => {
100
+ await this.generateCommand.execute('entity', name);
101
+ });
102
+
103
+ generate
104
+ .command('resource [name]')
105
+ .alias('res')
106
+ .description('Generate a complete resource (controller, service, repository, entity)')
107
+ .action(async (name) => {
108
+ await this.generateCommand.execute('resource', name);
109
+ });
110
+
111
+ // Config commands
112
+ const config = this.program
113
+ .command('config')
114
+ .description('Configure Fragment application');
115
+
116
+ config
117
+ .command('ai')
118
+ .description('Configure OpenAI integration')
119
+ .action(async () => {
120
+ await this.configCommand.execute('ai');
121
+ });
122
+
123
+ config
124
+ .command('db')
125
+ .alias('database')
126
+ .description('Configure database connection')
127
+ .action(async () => {
128
+ await this.configCommand.execute('db');
129
+ });
130
+
131
+ config
132
+ .command('show')
133
+ .description('Show current configuration')
134
+ .action(async () => {
135
+ await this.configCommand.execute('show');
136
+ });
137
+
138
+ // Serve command
139
+ this.program
140
+ .command('serve')
141
+ .alias('dev')
142
+ .description('Start development server')
143
+ .option('-p, --port <port>', 'Port number', parseInt)
144
+ .option('--no-watch', 'Disable file watching')
145
+ .action(async (options) => {
146
+ await this.serveCommand.execute(options);
147
+ });
148
+
149
+ // Build command
150
+ this.program
151
+ .command('build')
152
+ .description('Build application for production')
153
+ .action(async () => {
154
+ await this.buildCommand.execute();
155
+ });
156
+
157
+ // Migrate commands
158
+ const migrate = this.program
159
+ .command('migrate')
160
+ .alias('migration')
161
+ .description('Database migration commands');
162
+
163
+ migrate
164
+ .command('run')
165
+ .description('Run pending migrations')
166
+ .action(async () => {
167
+ await this.migrateCommand.execute('run');
168
+ });
169
+
170
+ migrate
171
+ .command('generate')
172
+ .alias('create')
173
+ .description('Generate a new migration')
174
+ .action(async () => {
175
+ await this.migrateCommand.execute('generate');
176
+ });
177
+
178
+ migrate
179
+ .command('revert')
180
+ .description('Revert last migration')
181
+ .action(async () => {
182
+ await this.migrateCommand.execute('revert');
183
+ });
184
+
185
+ migrate
186
+ .command('show')
187
+ .alias('status')
188
+ .description('Show migration status')
189
+ .action(async () => {
190
+ await this.migrateCommand.execute('show');
191
+ });
192
+
193
+ // Info command
194
+ this.program
195
+ .command('info')
196
+ .description('Display Fragment CLI information')
197
+ .action(() => {
198
+ CLILogger.box('Fragment Framework CLI', [
199
+ 'Version: 1.0.0',
200
+ 'TypeScript Backend Framework',
201
+ 'OOP + Decorators + DI',
202
+ '',
203
+ 'Documentation: https://fragment-framework.dev',
204
+ 'Repository: https://github.com/fragment/framework'
205
+ ]);
206
+ });
207
+ }
208
+
209
+ run(args: string[]): void {
210
+ this.program.parse(['node', 'frg', ...args]);
211
+ }
212
+ }
@@ -0,0 +1,24 @@
1
+
2
+ import { execSync } from 'child_process';
3
+ import { CLILogger } from '../utils/logger';
4
+
5
+ export class BuildCommand {
6
+ async execute(): Promise<void> {
7
+ CLILogger.title('🔨 Building Fragment Application');
8
+
9
+ const spinner = CLILogger.spinner('Compiling TypeScript...');
10
+
11
+ try {
12
+ execSync('tsc', { stdio: 'pipe' });
13
+ spinner.succeed('Build completed successfully');
14
+
15
+ CLILogger.success('Output directory: ./dist');
16
+ CLILogger.info('Run "node dist/server.js" to start the production server');
17
+
18
+ } catch (error: any) {
19
+ spinner.fail('Build failed');
20
+ CLILogger.error(error.message);
21
+ process.exit(1);
22
+ }
23
+ }
24
+ }