@seip/blue-bird 0.3.3 → 0.3.4

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 (43) hide show
  1. package/.env_example +23 -13
  2. package/LICENSE +21 -21
  3. package/README.md +79 -79
  4. package/backend/index.js +12 -12
  5. package/backend/routes/api.js +34 -34
  6. package/backend/routes/frontend.js +1 -8
  7. package/core/app.js +359 -359
  8. package/core/auth.js +69 -69
  9. package/core/cache.js +35 -35
  10. package/core/cli/component.js +42 -42
  11. package/core/cli/init.js +120 -118
  12. package/core/cli/react.js +383 -411
  13. package/core/cli/route.js +42 -42
  14. package/core/cli/scaffolding-auth.js +967 -0
  15. package/core/config.js +41 -41
  16. package/core/debug.js +248 -248
  17. package/core/logger.js +80 -80
  18. package/core/middleware.js +27 -27
  19. package/core/router.js +134 -134
  20. package/core/swagger.js +24 -24
  21. package/core/template.js +288 -288
  22. package/core/upload.js +76 -76
  23. package/core/validate.js +291 -290
  24. package/frontend/index.html +28 -22
  25. package/frontend/resources/js/App.jsx +28 -42
  26. package/frontend/resources/js/Main.jsx +17 -17
  27. package/frontend/resources/js/blue-bird/components/Button.jsx +67 -0
  28. package/frontend/resources/js/blue-bird/components/Card.jsx +17 -0
  29. package/frontend/resources/js/blue-bird/components/DataTable.jsx +126 -0
  30. package/frontend/resources/js/blue-bird/components/Input.jsx +21 -0
  31. package/frontend/resources/js/blue-bird/components/Label.jsx +12 -0
  32. package/frontend/resources/js/blue-bird/components/Modal.jsx +27 -0
  33. package/frontend/resources/js/blue-bird/components/Translate.jsx +12 -0
  34. package/frontend/resources/js/blue-bird/components/Typography.jsx +25 -0
  35. package/frontend/resources/js/blue-bird/contexts/LanguageContext.jsx +29 -0
  36. package/frontend/resources/js/blue-bird/contexts/SnackbarContext.jsx +38 -0
  37. package/frontend/resources/js/blue-bird/contexts/ThemeContext.jsx +49 -0
  38. package/frontend/resources/js/blue-bird/locales/en.json +30 -0
  39. package/frontend/resources/js/blue-bird/locales/es.json +30 -0
  40. package/frontend/resources/js/pages/About.jsx +33 -15
  41. package/frontend/resources/js/pages/Home.jsx +93 -68
  42. package/package.json +56 -55
  43. package/vite.config.js +21 -21
package/core/auth.js CHANGED
@@ -1,69 +1,69 @@
1
- import jwt from "jsonwebtoken";
2
-
3
- /**
4
- * Auth class to handle JWT generation, verification and protection.
5
- */
6
- class Auth {
7
- /**
8
- * Generates a JWT token.
9
- * @param {Object} payload - The data to store in the token.
10
- * @param {string} [secret=process.env.JWT_SECRET] - The secret key.
11
- * @param {string|number} [expiresIn='24h'] - Expiration time.
12
- * @returns {string} The generated token.
13
- * @example
14
- * const token = Auth.generateToken({ id: 1 });
15
- * console.log(token);
16
- *
17
- */
18
- static generateToken(payload, secret = process.env.JWT_SECRET || 'blue-bird-secret', expiresIn = '24h') {
19
- return jwt.sign(payload, secret, { expiresIn });
20
- }
21
-
22
- /**
23
- * Verifies a JWT token.
24
- * @param {string} token - The token to verify.
25
- * @param {string} [secret=process.env.JWT_SECRET] - The secret key.
26
- * @returns {Object|null} The decoded payload or null if invalid.
27
- * @example
28
- * const token = Auth.generateToken({ id: 1 });
29
- * const decoded = Auth.verifyToken(token);
30
- * console.log(decoded);
31
- */
32
- static verifyToken(token, secret = process.env.JWT_SECRET || 'blue-bird-secret') {
33
- try {
34
- return jwt.verify(token, secret);
35
- } catch (error) {
36
- return null;
37
- }
38
- }
39
-
40
- /**
41
- * Middleware to protect routes. Checks for token in Cookies or Authorization header.
42
- * @param {Object} options - Options for protection.
43
- * @param {string} [options.redirect] - URL to redirect if not authenticated (for web routes).
44
- * @returns {Function} Express middleware.
45
- * @example
46
- * app.use(Auth.protect({ redirect: "/login" }));
47
- */
48
- static protect(options = { redirect: null }) {
49
- return (req, res, next) => {
50
- const token = req.cookies?.token || req.headers.authorization?.split(" ")[1];
51
-
52
- if (!token) {
53
- if (options.redirect) return res.redirect(options.redirect);
54
- return res.status(401).json({ message: "Unauthorized: No token provided" });
55
- }
56
-
57
- const decoded = this.verifyToken(token);
58
- if (!decoded) {
59
- if (options.redirect) return res.redirect(options.redirect);
60
- return res.status(401).json({ message: "Unauthorized: Invalid token" });
61
- }
62
-
63
- req.user = decoded;
64
- next();
65
- };
66
- }
67
- }
68
-
69
- export default Auth;
1
+ import jwt from "jsonwebtoken";
2
+
3
+ /**
4
+ * Auth class to handle JWT generation, verification and protection.
5
+ */
6
+ class Auth {
7
+ /**
8
+ * Generates a JWT token.
9
+ * @param {Object} payload - The data to store in the token.
10
+ * @param {string} [secret=process.env.JWT_SECRET] - The secret key.
11
+ * @param {string|number} [expiresIn='24h'] - Expiration time.
12
+ * @returns {string} The generated token.
13
+ * @example
14
+ * const token = Auth.generateToken({ id: 1 });
15
+ * console.log(token);
16
+ *
17
+ */
18
+ static generateToken(payload, secret = process.env.JWT_SECRET || 'blue-bird-secret', expiresIn = '24h') {
19
+ return jwt.sign(payload, secret, { expiresIn });
20
+ }
21
+
22
+ /**
23
+ * Verifies a JWT token.
24
+ * @param {string} token - The token to verify.
25
+ * @param {string} [secret=process.env.JWT_SECRET] - The secret key.
26
+ * @returns {Object|null} The decoded payload or null if invalid.
27
+ * @example
28
+ * const token = Auth.generateToken({ id: 1 });
29
+ * const decoded = Auth.verifyToken(token);
30
+ * console.log(decoded);
31
+ */
32
+ static verifyToken(token, secret = process.env.JWT_SECRET || 'blue-bird-secret') {
33
+ try {
34
+ return jwt.verify(token, secret);
35
+ } catch (error) {
36
+ return null;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Middleware to protect routes. Checks for token in Cookies or Authorization header.
42
+ * @param {Object} options - Options for protection.
43
+ * @param {string} [options.redirect] - URL to redirect if not authenticated (for web routes).
44
+ * @returns {Function} Express middleware.
45
+ * @example
46
+ * app.use(Auth.protect({ redirect: "/login" }));
47
+ */
48
+ static protect(options = { redirect: null }) {
49
+ return (req, res, next) => {
50
+ const token = req.cookies?.token || req.headers.authorization?.split(" ")[1];
51
+
52
+ if (!token) {
53
+ if (options.redirect) return res.redirect(options.redirect);
54
+ return res.status(401).json({ message: "Unauthorized: No token provided" });
55
+ }
56
+
57
+ const decoded = this.verifyToken(token);
58
+ if (!decoded) {
59
+ if (options.redirect) return res.redirect(options.redirect);
60
+ return res.status(401).json({ message: "Unauthorized: Invalid token" });
61
+ }
62
+
63
+ req.user = decoded;
64
+ next();
65
+ };
66
+ }
67
+ }
68
+
69
+ export default Auth;
package/core/cache.js CHANGED
@@ -1,36 +1,36 @@
1
- const CACHE = {};
2
- /**
3
- * Cache Middleware
4
- * @example
5
- * router.get("/stats",
6
- Cache.middleware(120),
7
- controller.stats
8
- );
9
- * */
10
- class Cache {
11
-
12
- static middleware(seconds = 60) {
13
- return (req, res, next) => {
14
-
15
- const key = req.originalUrl;
16
-
17
- if (CACHE[key] && CACHE[key].expiry > Date.now()) {
18
- return res.json(CACHE[key].data);
19
- }
20
-
21
- const originalJson = res.json.bind(res);
22
-
23
- res.json = (body) => {
24
- CACHE[key] = {
25
- data: body,
26
- expiry: Date.now() + seconds * 1000
27
- };
28
- return originalJson(body);
29
- };
30
-
31
- next();
32
- };
33
- }
34
- }
35
-
1
+ const CACHE = {};
2
+ /**
3
+ * Cache Middleware
4
+ * @example
5
+ * router.get("/stats",
6
+ Cache.middleware(120),
7
+ controller.stats
8
+ );
9
+ * */
10
+ class Cache {
11
+
12
+ static middleware(seconds = 60) {
13
+ return (req, res, next) => {
14
+
15
+ const key = req.originalUrl;
16
+
17
+ if (CACHE[key] && CACHE[key].expiry > Date.now()) {
18
+ return res.json(CACHE[key].data);
19
+ }
20
+
21
+ const originalJson = res.json.bind(res);
22
+
23
+ res.json = (body) => {
24
+ CACHE[key] = {
25
+ data: body,
26
+ expiry: Date.now() + seconds * 1000
27
+ };
28
+ return originalJson(body);
29
+ };
30
+
31
+ next();
32
+ };
33
+ }
34
+ }
35
+
36
36
  export default Cache;
@@ -1,42 +1,42 @@
1
- import path from "node:path";
2
- import fs from "node:fs";
3
- import Config from "../config.js";
4
-
5
- const __dirname = Config.dirname();
6
-
7
- class ComponentCLI {
8
- /**
9
- * Create component react
10
- * @return {void}
11
- * /
12
- */
13
-
14
- create() {
15
- const folder = path.join(process.cwd(), "frontend/resources/components");
16
- if (!fs.existsSync(folder)) {
17
- fs.mkdirSync(folder, { recursive: true });
18
- }
19
- let nameComponent =`Component-${Math.random().toString(36).substring(7)}`;
20
- const nameParam = process.argv[2];
21
- if (nameParam.length > 0 && typeof nameParam === "string") {
22
- nameComponent = nameParam;
23
- nameComponent = nameComponent.charAt(0).toUpperCase() + nameComponent.slice(1);
24
- }
25
- const filePath = path.join(folder, `${nameComponent}.jsx`);
26
- const content = `import React from 'react';
27
-
28
- export default function ${nameComponent}() {
29
- return (
30
- <div>
31
- <h1>${nameComponent} Component</h1>
32
- </div>
33
- );
34
- }
35
- `;
36
- fs.writeFileSync(filePath, content);
37
- console.log(`Component ${nameComponent} created at ${filePath}`);
38
- }
39
- }
40
-
41
- const componentCLI = new ComponentCLI();
42
- componentCLI.create();
1
+ import path from "node:path";
2
+ import fs from "node:fs";
3
+ import Config from "../config.js";
4
+
5
+ const __dirname = Config.dirname();
6
+
7
+ class ComponentCLI {
8
+ /**
9
+ * Create component react
10
+ * @return {void}
11
+ * /
12
+ */
13
+
14
+ create() {
15
+ const folder = path.join(process.cwd(), "frontend/resources/components");
16
+ if (!fs.existsSync(folder)) {
17
+ fs.mkdirSync(folder, { recursive: true });
18
+ }
19
+ let nameComponent =`Component-${Math.random().toString(36).substring(7)}`;
20
+ const nameParam = process.argv[2];
21
+ if (nameParam.length > 0 && typeof nameParam === "string") {
22
+ nameComponent = nameParam;
23
+ nameComponent = nameComponent.charAt(0).toUpperCase() + nameComponent.slice(1);
24
+ }
25
+ const filePath = path.join(folder, `${nameComponent}.jsx`);
26
+ const content = `import React from 'react';
27
+
28
+ export default function ${nameComponent}() {
29
+ return (
30
+ <div>
31
+ <h1>${nameComponent} Component</h1>
32
+ </div>
33
+ );
34
+ }
35
+ `;
36
+ fs.writeFileSync(filePath, content);
37
+ console.log(`Component ${nameComponent} created at ${filePath}`);
38
+ }
39
+ }
40
+
41
+ const componentCLI = new ComponentCLI();
42
+ componentCLI.create();
package/core/cli/init.js CHANGED
@@ -1,118 +1,120 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from "node:fs";
4
- import path from "node:path";
5
- import chalk from "chalk";
6
-
7
- class ProjectInit {
8
- constructor() {
9
- this.appDir = process.cwd();
10
- this.sourceDir = path.resolve(import.meta.dirname, "../../");
11
- }
12
-
13
- async run() {
14
- console.log(chalk.cyan("Starting Blue Bird project initialization..."));
15
-
16
- const itemsToCopy = [
17
- "backend",
18
- "frontend",
19
- ".env_example"
20
- ];
21
-
22
- try {
23
- itemsToCopy.forEach(item => {
24
- const src = path.join(this.sourceDir, item);
25
- const dest = path.join(this.appDir, item);
26
-
27
- if (fs.existsSync(src)) {
28
- if (!fs.existsSync(dest)) {
29
- this.copyRecursive(src, dest);
30
- console.log(chalk.green(`✓ Copied ${item} to root.`));
31
- } else {
32
- console.log(chalk.yellow(`! ${item} already exists, skipping.`));
33
- }
34
- } else {
35
- console.warn(chalk.red(`✗ Source ${item} not found in ${this.sourceDir}`));
36
- }
37
- });
38
-
39
- const envPath = path.join(this.appDir, ".env");
40
- const envExamplePath = path.join(this.appDir, ".env_example");
41
- if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
42
- fs.copyFileSync(envExamplePath, envPath);
43
- console.log(chalk.green("✓ Created .env from .env_example."));
44
- }
45
-
46
- this.updatePackageJson();
47
-
48
- console.log(chalk.blue("\nBlue Bird initialization completed!"));
49
- console.log(chalk.white("Next steps:"));
50
- console.log(chalk.bold(" npm install"));
51
- console.log(chalk.bold(" npm run react"));
52
- console.log(chalk.bold(" npm run dev"));
53
-
54
- } catch (error) {
55
- console.error(chalk.red("Error during initialization:"), error.message);
56
- }
57
- }
58
-
59
- updatePackageJson() {
60
- const pkgPath = path.join(this.appDir, "package.json");
61
- if (fs.existsSync(pkgPath)) {
62
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
63
- pkg.scripts = pkg.scripts || {};
64
-
65
- const scriptsToAdd = {
66
- "dev": "node --watch --env-file=.env backend/index.js",
67
- "start": "node --env-file=.env backend/index.js",
68
- "react": "blue-bird react",
69
- "init": "blue-bird",
70
- "route": "blue-bird route",
71
- "component": "blue-bird component",
72
- "swagger-install": "blue-bird swagger-install"
73
- };
74
-
75
- let updated = false;
76
- for (const [key, value] of Object.entries(scriptsToAdd)) {
77
- if (!pkg.scripts[key]) {
78
- pkg.scripts[key] = value;
79
- updated = true;
80
- }
81
- }
82
-
83
- if (updated) {
84
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
85
- console.log(chalk.green("✓ Updated package.json scripts."));
86
- }
87
- }
88
- }
89
-
90
- copyRecursive(src, dest) {
91
- const stats = fs.statSync(src);
92
- const isDirectory = stats.isDirectory();
93
-
94
- if (isDirectory) {
95
- if (!fs.existsSync(dest)) {
96
- fs.mkdirSync(dest, { recursive: true });
97
- }
98
- fs.readdirSync(src).forEach(childItemName => {
99
- this.copyRecursive(path.join(src, childItemName), path.join(dest, childItemName));
100
- });
101
- } else {
102
- fs.copyFileSync(src, dest);
103
- }
104
- }
105
- }
106
-
107
- const initializer = new ProjectInit();
108
-
109
- const args = process.argv.slice(2);
110
- const command = args[0];
111
-
112
- if (command === "react") import("./react.js");
113
- else if (command === "route") import("./route.js")
114
- else if (command === "component") import("./component.js")
115
- else if (command === "swagger-install") import("./swagger.js")
116
- else initializer.run();
117
-
118
-
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import chalk from "chalk";
6
+
7
+ class ProjectInit {
8
+ constructor() {
9
+ this.appDir = process.cwd();
10
+ this.sourceDir = path.resolve(import.meta.dirname, "../../");
11
+ }
12
+
13
+ async run() {
14
+ console.log(chalk.cyan("Starting Blue Bird project initialization..."));
15
+
16
+ const itemsToCopy = [
17
+ "backend",
18
+ "frontend",
19
+ ".env_example"
20
+ ];
21
+
22
+ try {
23
+ itemsToCopy.forEach(item => {
24
+ const src = path.join(this.sourceDir, item);
25
+ const dest = path.join(this.appDir, item);
26
+
27
+ if (fs.existsSync(src)) {
28
+ if (!fs.existsSync(dest)) {
29
+ this.copyRecursive(src, dest);
30
+ console.log(chalk.green(`✓ Copied ${item} to root.`));
31
+ } else {
32
+ console.log(chalk.yellow(`! ${item} already exists, skipping.`));
33
+ }
34
+ } else {
35
+ console.warn(chalk.red(`✗ Source ${item} not found in ${this.sourceDir}`));
36
+ }
37
+ });
38
+
39
+ const envPath = path.join(this.appDir, ".env");
40
+ const envExamplePath = path.join(this.appDir, ".env_example");
41
+ if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
42
+ fs.copyFileSync(envExamplePath, envPath);
43
+ console.log(chalk.green("✓ Created .env from .env_example."));
44
+ }
45
+
46
+ this.updatePackageJson();
47
+
48
+ console.log(chalk.blue("\nBlue Bird initialization completed!"));
49
+ console.log(chalk.white("Next steps:"));
50
+ console.log(chalk.bold(" npm install"));
51
+ console.log(chalk.bold(" npm run react"));
52
+ console.log(chalk.bold(" npm run dev"));
53
+
54
+ } catch (error) {
55
+ console.error(chalk.red("Error during initialization:"), error.message);
56
+ }
57
+ }
58
+
59
+ updatePackageJson() {
60
+ const pkgPath = path.join(this.appDir, "package.json");
61
+ if (fs.existsSync(pkgPath)) {
62
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
63
+ pkg.scripts = pkg.scripts || {};
64
+
65
+ const scriptsToAdd = {
66
+ "dev": "node --watch --env-file=.env backend/index.js",
67
+ "start": "node --env-file=.env backend/index.js",
68
+ "react": "blue-bird react",
69
+ "init": "blue-bird",
70
+ "route": "blue-bird route",
71
+ "component": "blue-bird component",
72
+ "swagger-install": "blue-bird swagger-install",
73
+ "scaffolding-auth": "blue-bird scaffolding-auth"
74
+ };
75
+
76
+ let updated = false;
77
+ for (const [key, value] of Object.entries(scriptsToAdd)) {
78
+ if (!pkg.scripts[key]) {
79
+ pkg.scripts[key] = value;
80
+ updated = true;
81
+ }
82
+ }
83
+
84
+ if (updated) {
85
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
86
+ console.log(chalk.green("✓ Updated package.json scripts."));
87
+ }
88
+ }
89
+ }
90
+
91
+ copyRecursive(src, dest) {
92
+ const stats = fs.statSync(src);
93
+ const isDirectory = stats.isDirectory();
94
+
95
+ if (isDirectory) {
96
+ if (!fs.existsSync(dest)) {
97
+ fs.mkdirSync(dest, { recursive: true });
98
+ }
99
+ fs.readdirSync(src).forEach(childItemName => {
100
+ this.copyRecursive(path.join(src, childItemName), path.join(dest, childItemName));
101
+ });
102
+ } else {
103
+ fs.copyFileSync(src, dest);
104
+ }
105
+ }
106
+ }
107
+
108
+ const initializer = new ProjectInit();
109
+
110
+ const args = process.argv.slice(2);
111
+ const command = args[0];
112
+
113
+ if (command === "react") import("./react.js");
114
+ else if (command === "route") import("./route.js")
115
+ else if (command === "component") import("./component.js")
116
+ else if (command === "swagger-install") import("./swagger.js")
117
+ else if (command === "scaffolding-auth") import("./scaffolding-auth.js")
118
+ else initializer.run();
119
+
120
+