frontend-hamroun 1.2.17 → 1.2.18
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/bin/cli.js +167 -149
- package/package.json +6 -1
package/bin/cli.js
CHANGED
@@ -397,275 +397,293 @@ async function generateApiRoute(name, directory) {
|
|
397
397
|
const serverDeps = {
|
398
398
|
"express": "^4.18.2",
|
399
399
|
"cors": "^2.8.5",
|
400
|
-
|
400
|
+
"mongodb": "^5.7.0", // Add MongoDB support
|
401
401
|
"jsonwebtoken": "^9.0.2", // Add JWT support for auth
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
402
|
+
"bcryptjs": "^2.4.3" // Add password hashing support
|
403
|
+
};
|
404
|
+
|
405
|
+
const devDeps = {
|
406
406
|
"@types/express": "^4.17.17",
|
407
|
+
"@types/cors": "^2.8.13",
|
408
|
+
"@types/mongodb": "^4.0.7",
|
409
|
+
"@types/jsonwebtoken": "^9.0.3",
|
410
|
+
"@types/bcryptjs": "^2.4.4"
|
411
|
+
};
|
412
|
+
|
407
413
|
// Add dependencies if needed
|
408
414
|
pkg.dependencies = pkg.dependencies || {};
|
409
415
|
for (const [dep, version] of Object.entries(serverDeps)) {
|
410
416
|
if (!pkg.dependencies[dep]) {
|
411
417
|
pkg.dependencies[dep] = version;
|
412
418
|
needsUpdate = true;
|
413
|
-
}
|
414
|
-
}
|
415
|
-
|
419
|
+
}
|
420
|
+
}
|
421
|
+
|
416
422
|
// Add dev dependencies if needed
|
417
423
|
pkg.devDependencies = pkg.devDependencies || {};
|
418
424
|
for (const [dep, version] of Object.entries(devDeps)) {
|
419
425
|
if (!pkg.devDependencies[dep]) {
|
420
426
|
pkg.devDependencies[dep] = version;
|
421
427
|
needsUpdate = true;
|
422
|
-
}
|
423
|
-
}
|
424
|
-
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
425
431
|
// Add start script if it doesn't exist
|
426
|
-
pkg.scripts = pkg.scripts || {};
|
432
|
+
pkg.scripts = pkg.scripts || {};
|
427
433
|
if (!pkg.scripts.start) {
|
428
434
|
pkg.scripts.start = "node server.js";
|
429
435
|
needsUpdate = true;
|
430
436
|
}
|
431
|
-
|
432
|
-
// Save changes if needed
|
433
|
-
if (needsUpdate) {
|
437
|
+
|
438
|
+
// Save changes if needed
|
439
|
+
if (needsUpdate) {
|
434
440
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
435
441
|
console.log(chalk.green('Updated package.json with server dependencies'));
|
436
442
|
}
|
437
443
|
}
|
438
|
-
} catch (error) {
|
444
|
+
} catch (error) {
|
439
445
|
console.warn(chalk.yellow('Could not update package.json:', error.message));
|
440
|
-
}
|
441
|
-
}
|
442
|
-
|
446
|
+
}
|
447
|
+
}
|
448
|
+
|
443
449
|
spinner.success({ text: `API route ${chalk.green(name)} generated successfully!` });
|
444
|
-
|
445
|
-
console.log('\nFile created:');
|
450
|
+
|
451
|
+
console.log('\nFile created:');
|
446
452
|
console.log(chalk.cyan(` ${path.join(directory, routePath)}.ts`));
|
447
|
-
|
453
|
+
|
448
454
|
} catch (error) {
|
449
|
-
spinner.error({ text: 'Failed to generate API route' });
|
455
|
+
spinner.error({ text: 'Failed to generate API route' });
|
450
456
|
console.error(chalk.red(error));
|
451
|
-
process.exit(1);ile created:');
|
452
|
-
} console.log(chalk.cyan(` ${path.join(directory, routePath)}.ts`));
|
453
|
-
}
|
454
|
-
} catch (error) {
|
455
|
-
// Add a server template for Express generate API route' });
|
456
|
-
const SERVER_TEMPLATE = `import { server } from 'frontend-hamroun';
|
457
457
|
process.exit(1);
|
458
|
+
}
|
459
|
+
}
|
460
|
+
|
461
|
+
// Add a server template for Express
|
462
|
+
const SERVER_TEMPLATE = `import { server } from 'frontend-hamroun';
|
463
|
+
|
458
464
|
async function startServer() {
|
459
465
|
try {
|
460
466
|
// Dynamically import server module
|
461
467
|
const { Server } = await server.getServer();
|
462
|
-
|
468
|
+
|
463
469
|
// Create and configure the server
|
464
|
-
const app = new Server({
|
470
|
+
const app = new Server({
|
465
471
|
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
|
466
|
-
apiDir: './api',
|
467
|
-
staticDir: './public',
|
472
|
+
apiDir: './api',
|
473
|
+
staticDir: './public',
|
468
474
|
|
469
|
-
// Enable
|
470
|
-
enableCors: true,
|
471
|
-
corsOptions: {
|
475
|
+
// Enable CORS
|
476
|
+
enableCors: true,
|
477
|
+
corsOptions: {
|
472
478
|
origin: process.env.CORS_ORIGIN || '*', // Set to specific domain in production
|
473
|
-
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
479
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
474
480
|
allowedHeaders: ['Content-Type', 'Authorization']
|
475
|
-
},
|
481
|
+
},
|
482
|
+
|
483
|
+
// Uncomment to enable database
|
476
484
|
/*
|
477
|
-
|
478
|
-
/*url: process.env.DATABASE_URL || 'mongodb://localhost:27017/my_app',
|
479
|
-
db: { 'mongodb'
|
485
|
+
db: {
|
480
486
|
// MongoDB
|
481
487
|
url: process.env.MONGODB_URL || 'mongodb://localhost:27017/my_app',
|
482
488
|
type: 'mongodb'
|
483
|
-
|
484
|
-
// MySQL
|
485
|
-
// url: process.env.MYSQL_URL || 'mysql://user:password@localhost:3306/my_db',
|
486
|
-
// type: 'mysql'
|
487
|
-
|
488
|
-
// PostgreSQL
|
489
|
+
|
490
|
+
// MySQL
|
491
|
+
// url: process.env.MYSQL_URL || 'mysql://user:password@localhost:3306/my_db',
|
492
|
+
// type: 'mysql'
|
493
|
+
|
494
|
+
// PostgreSQL
|
489
495
|
// url: process.env.POSTGRES_URL || 'postgres://user:password@localhost:5432/my_db',
|
490
496
|
// type: 'postgres'
|
491
497
|
},
|
492
498
|
*/
|
493
499
|
|
494
500
|
// Uncomment to enable authentication
|
495
|
-
/*
|
496
|
-
auth: {
|
501
|
+
/*
|
502
|
+
auth: {
|
497
503
|
secret: process.env.JWT_SECRET || 'your-secret-key',
|
498
|
-
expiresIn: '7d'
|
504
|
+
expiresIn: '7d'
|
499
505
|
}
|
500
|
-
*/
|
501
|
-
});
|
502
|
-
|
503
|
-
// Connect to database if configured
|
504
|
-
if (app.getDatabase()) {
|
505
|
-
await app.getDatabase().connect();
|
506
|
-
console.log('Connected to database');
|
506
|
+
*/
|
507
|
+
});
|
508
|
+
|
509
|
+
// Connect to database if configured
|
510
|
+
if (app.getDatabase()) {
|
511
|
+
await app.getDatabase().connect();
|
512
|
+
console.log('Connected to database');
|
507
513
|
}
|
508
514
|
|
509
515
|
// Start the server
|
510
|
-
await app.start();
|
516
|
+
await app.start();
|
511
517
|
|
512
518
|
console.log('Server running at http://localhost:' +
|
513
|
-
(process.env.PORT || 3000));
|
514
|
-
|
519
|
+
(process.env.PORT || 3000));
|
520
|
+
|
515
521
|
// Handle graceful shutdown
|
516
522
|
process.on('SIGINT', async () => {
|
517
|
-
console.log('Shutting down server...');
|
518
|
-
if (app.getDatabase()) {
|
523
|
+
console.log('Shutting down server...');
|
524
|
+
if (app.getDatabase()) {
|
519
525
|
await app.getDatabase().disconnect();
|
520
526
|
console.log('Database connection closed');
|
521
|
-
}
|
522
|
-
await app.stop();
|
523
|
-
console.log('Server stopped');
|
524
|
-
process.exit(0)
|
527
|
+
}
|
528
|
+
await app.stop();
|
529
|
+
console.log('Server stopped');
|
530
|
+
process.exit(0);
|
525
531
|
});
|
526
|
-
} catch (error) {
|
527
|
-
console.error('Failed to start server:', error);
|
528
|
-
process.exit(1);
|
532
|
+
} catch (error) {
|
533
|
+
console.error('Failed to start server:', error);
|
534
|
+
process.exit(1);
|
529
535
|
}
|
530
|
-
}
|
531
|
-
|
536
|
+
}
|
537
|
+
|
532
538
|
startServer();
|
533
539
|
`;
|
534
|
-
|
540
|
+
|
535
541
|
async function addDockerfile(isSSR) {
|
536
|
-
const spinner = createSpinner('Adding Dockerfile...').start();
|
542
|
+
const spinner = createSpinner('Adding Dockerfile...').start();
|
537
543
|
|
538
544
|
try {
|
539
545
|
const dockerContent = isSSR ? SSR_DOCKERFILE_TEMPLATE : DOCKERFILE_TEMPLATE;
|
540
546
|
const targetPath = path.join(process.cwd(), 'Dockerfile');
|
541
|
-
|
547
|
+
|
542
548
|
// Check if Dockerfile already exists
|
543
|
-
if (await fs.pathExists(targetPath)) {
|
544
|
-
spinner.stop();
|
545
|
-
const { overwrite } = await inquirer.prompt([{
|
546
|
-
type: 'confirm',
|
547
|
-
name: 'overwrite',
|
548
|
-
message: 'Dockerfile already exists. Overwrite?',
|
549
|
+
if (await fs.pathExists(targetPath)) {
|
550
|
+
spinner.stop();
|
551
|
+
const { overwrite } = await inquirer.prompt([{
|
552
|
+
type: 'confirm',
|
553
|
+
name: 'overwrite',
|
554
|
+
message: 'Dockerfile already exists. Overwrite?',
|
549
555
|
default: false
|
550
|
-
}]);
|
556
|
+
}]);
|
551
557
|
|
552
558
|
if (!overwrite) {
|
553
559
|
console.log(chalk.yellow('Operation cancelled.'));
|
554
|
-
return;
|
555
|
-
}
|
560
|
+
return;
|
561
|
+
}
|
556
562
|
|
557
|
-
spinner.start();
|
558
|
-
}
|
563
|
+
spinner.start();
|
564
|
+
}
|
559
565
|
|
560
|
-
// Write
|
566
|
+
// Write Dockerfile
|
561
567
|
await fs.writeFile(targetPath, dockerContent);
|
562
568
|
|
563
569
|
spinner.success({ text: 'Dockerfile added successfully!' });
|
564
570
|
|
565
|
-
console.log('\nTo build and run Docker image:');
|
566
|
-
console.log(chalk.cyan(' docker build -t my-app .'));
|
571
|
+
console.log('\nTo build and run Docker image:');
|
572
|
+
console.log(chalk.cyan(' docker build -t my-app .'));
|
567
573
|
console.log(chalk.cyan(' docker run -p 3000:' + (isSSR ? '3000' : '80') + ' my-app'));
|
568
|
-
|
569
|
-
} catch (error) {
|
574
|
+
|
575
|
+
} catch (error) {
|
570
576
|
spinner.error({ text: 'Failed to add Dockerfile' });
|
571
577
|
console.error(chalk.red(error));
|
572
578
|
process.exit(1);
|
573
|
-
}
|
574
|
-
}
|
579
|
+
}
|
580
|
+
}
|
575
581
|
|
576
|
-
// Add API route
|
582
|
+
// Add API route templates
|
577
583
|
const API_ROUTE_TEMPLATE = `import { Request, Response } from 'express';
|
578
584
|
|
579
585
|
export const get = (req: Request, res: Response) => {
|
580
586
|
res.json({
|
581
|
-
message: 'This is a GET endpoint',
|
587
|
+
message: 'This is a GET endpoint',
|
582
588
|
query: req.query,
|
583
|
-
timestamp: new Date().toISOString()
|
584
|
-
});
|
589
|
+
timestamp: new Date().toISOString()
|
590
|
+
});
|
585
591
|
};
|
586
592
|
|
587
593
|
export const post = (req: Request, res: Response) => {
|
588
|
-
res.json({
|
589
|
-
message: 'This is a POST endpoint',
|
590
|
-
body: req.body
|
591
|
-
timestamp: new Date().toISOString()
|
594
|
+
res.json({
|
595
|
+
message: 'This is a POST endpoint',
|
596
|
+
body: req.body,
|
597
|
+
timestamp: new Date().toISOString()
|
592
598
|
});
|
593
|
-
};
|
599
|
+
};
|
594
600
|
|
595
601
|
export const put = (req: Request, res: Response) => {
|
596
602
|
res.json({
|
597
603
|
message: 'This is a PUT endpoint',
|
598
|
-
body: req.body,
|
604
|
+
body: req.body,
|
599
605
|
timestamp: new Date().toISOString()
|
600
|
-
});
|
601
|
-
};
|
602
|
-
|
606
|
+
});
|
607
|
+
};
|
608
|
+
|
603
609
|
export const delete_ = (req: Request, res: Response) => {
|
604
|
-
res.json({
|
610
|
+
res.json({
|
605
611
|
message: 'This is a DELETE endpoint',
|
606
612
|
timestamp: new Date().toISOString()
|
607
613
|
});
|
608
614
|
};
|
609
|
-
|
610
|
-
// You can add middleware that will be applied to all
|
611
|
-
export const middleware = [
|
615
|
+
|
616
|
+
// You can add middleware that will be applied to all methods
|
617
|
+
export const middleware = [
|
612
618
|
// Example middleware
|
613
|
-
(req: Request, res: Response, next: Function) => {
|
619
|
+
(req: Request, res: Response, next: Function) => {
|
614
620
|
console.log(\`\${req.method} \${req.url} - \${new Date().toISOString()}\`);
|
615
621
|
next();
|
616
622
|
}
|
617
623
|
];
|
618
|
-
`;
|
619
|
-
|
620
|
-
const DYNAMIC_API_ROUTE_TEMPLATE = `import { Request, Response } from 'express';
|
624
|
+
`;
|
625
|
+
|
626
|
+
const DYNAMIC_API_ROUTE_TEMPLATE = `import { Request, Response } from 'express';
|
621
627
|
|
622
|
-
export const get = (req: Request, res: Response) => {
|
628
|
+
export const get = (req: Request, res: Response) => {
|
623
629
|
res.json({
|
624
630
|
message: 'This is a dynamic route GET endpoint',
|
625
631
|
params: req.params,
|
626
632
|
query: req.query,
|
627
|
-
timestamp: new Date().toISOString()
|
628
|
-
});
|
633
|
+
timestamp: new Date().toISOString()
|
634
|
+
});
|
629
635
|
};
|
630
|
-
|
631
|
-
export const
|
632
|
-
res.json({
|
633
|
-
message: 'This is a dynamic route
|
634
|
-
params: req.params,
|
636
|
+
|
637
|
+
export const post = (req: Request, res: Response) => {
|
638
|
+
res.json({
|
639
|
+
message: 'This is a dynamic route POST endpoint',
|
640
|
+
params: req.params,
|
635
641
|
body: req.body,
|
636
642
|
timestamp: new Date().toISOString()
|
637
|
-
});
|
638
|
-
};
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
643
|
+
});
|
644
|
+
};
|
664
645
|
|
646
|
+
export const put = (req: Request, res: Response) => {
|
647
|
+
res.json({
|
648
|
+
message: 'This is a dynamic route PUT endpoint',
|
649
|
+
params: req.params,
|
650
|
+
body: req.body,
|
651
|
+
timestamp: new Date().toISOString()
|
652
|
+
});
|
653
|
+
};
|
665
654
|
|
655
|
+
export const delete_ = (req: Request, res: Response) => {
|
656
|
+
res.json({
|
657
|
+
message: 'This is a dynamic route DELETE endpoint',
|
658
|
+
params: req.params,
|
659
|
+
timestamp: new Date().toISOString()
|
660
|
+
});
|
661
|
+
};
|
666
662
|
|
663
|
+
// You can add middleware that will be applied to all methods
|
664
|
+
export const middleware = [
|
665
|
+
// Example middleware
|
666
|
+
(req: Request, res: Response, next: Function) => {
|
667
|
+
console.log(\`\${req.method} \${req.url} - \${new Date().toISOString()}\`);
|
668
|
+
next();
|
669
|
+
}
|
670
|
+
];
|
671
|
+
`;
|
667
672
|
|
668
|
-
|
673
|
+
// Add tsconfig.server.json template
|
674
|
+
const TSCONFIG_SERVER_TEMPLATE = `{
|
675
|
+
"compilerOptions": {
|
676
|
+
"target": "ES2020",
|
677
|
+
"module": "NodeNext",
|
678
|
+
"moduleResolution": "NodeNext",
|
679
|
+
"esModuleInterop": true,
|
680
|
+
"outDir": "./dist",
|
681
|
+
"declaration": true,
|
682
|
+
"sourceMap": true,
|
683
|
+
"noEmit": false,
|
684
|
+
"strict": true,
|
685
|
+
"skipLibCheck": true
|
686
|
+
},
|
669
687
|
"include": ["server.ts", "api/**/*.ts"],
|
670
688
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
671
689
|
}`;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "frontend-hamroun",
|
3
|
-
"version": "1.2.
|
3
|
+
"version": "1.2.18",
|
4
4
|
"description": "A lightweight full-stack JavaScript framework",
|
5
5
|
"type": "module",
|
6
6
|
"main": "./dist/index.js",
|
@@ -19,6 +19,11 @@
|
|
19
19
|
"import": "./dist/index.mjs",
|
20
20
|
"require": "./dist/index.js",
|
21
21
|
"default": "./dist/index.js"
|
22
|
+
},
|
23
|
+
"./server": {
|
24
|
+
"types": "./dist/server/index.d.ts",
|
25
|
+
"import": "./dist/server/index.js",
|
26
|
+
"require": "./dist/server/index.js"
|
22
27
|
}
|
23
28
|
},
|
24
29
|
"bin": {
|