@seip/blue-bird 1.1.3 → 1.1.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.
package/core/queue.js ADDED
@@ -0,0 +1,121 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { getRedisClient } from "./cache.js";
4
+
5
+ /**
6
+ * Lightweight background queue worker module with Redis and in-memory fallback.
7
+ */
8
+ class QueueManager {
9
+ constructor() {
10
+ this.handlers = new Map();
11
+ this.memoryQueue = [];
12
+ this.isProcessing = false;
13
+ this.redisPrefix = "bluebird:queue:";
14
+ }
15
+
16
+ /**
17
+ * Registers a job handler function.
18
+ * @param {string} jobName - Name of the job.
19
+ * @param {Function} handler - Async function(payload).
20
+ */
21
+ process(jobName, handler) {
22
+ if (typeof handler !== "function") {
23
+ throw new Error(`Handler for job '${jobName}' must be a function.`);
24
+ }
25
+ this.handlers.set(jobName, handler);
26
+ }
27
+
28
+ /**
29
+ * Dispatches a new job to the queue.
30
+ * @param {string} jobName - Name of the job.
31
+ * @param {any} payload - Data payload to pass to the handler.
32
+ * @param {object} [options] - Options (e.g. delayMs).
33
+ * @returns {Promise<boolean>}
34
+ */
35
+ async dispatch(jobName, payload = {}, options = {}) {
36
+ const jobItem = {
37
+ id: `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
38
+ name: jobName,
39
+ payload,
40
+ createdAt: new Date().toISOString(),
41
+ };
42
+
43
+ const redis = getRedisClient();
44
+ if (redis && redis.isReady) {
45
+ try {
46
+ await redis.lPush(`${this.redisPrefix}jobs`, JSON.stringify(jobItem));
47
+ return true;
48
+ } catch (err) {
49
+ console.error("[QUEUE ERROR] Failed to dispatch job to Redis:", err.message);
50
+ }
51
+ }
52
+
53
+ // In-memory fallback
54
+ if (options.delayMs && options.delayMs > 0) {
55
+ setTimeout(() => {
56
+ this.memoryQueue.push(jobItem);
57
+ this.runMemoryWorker();
58
+ }, options.delayMs);
59
+ } else {
60
+ this.memoryQueue.push(jobItem);
61
+ setImmediate(() => this.runMemoryWorker());
62
+ }
63
+
64
+ return true;
65
+ }
66
+
67
+ /**
68
+ * Executes in-memory queue jobs sequentially.
69
+ * @private
70
+ */
71
+ async runMemoryWorker() {
72
+ if (this.isProcessing || this.memoryQueue.length === 0) return;
73
+ this.isProcessing = true;
74
+
75
+ while (this.memoryQueue.length > 0) {
76
+ const job = this.memoryQueue.shift();
77
+ if (!job) continue;
78
+
79
+ const handler = this.handlers.get(job.name);
80
+ if (!handler) {
81
+ console.warn(`[QUEUE WARN] No handler registered for job '${job.name}'.`);
82
+ continue;
83
+ }
84
+
85
+ try {
86
+ await handler(job.payload);
87
+ } catch (err) {
88
+ console.error(`[QUEUE ERROR] Error processing job '${job.name}' (${job.id}):`, err);
89
+ }
90
+ }
91
+
92
+ this.isProcessing = false;
93
+ }
94
+
95
+ /**
96
+ * Auto-loads all job definition files from backend/jobs/.
97
+ */
98
+ async loadJobs(jobsDir = path.resolve(process.cwd(), "backend/jobs")) {
99
+ if (!fs.existsSync(jobsDir)) return;
100
+
101
+ const files = fs
102
+ .readdirSync(jobsDir)
103
+ .filter((f) => f.endsWith(".js") || f.endsWith(".mjs"));
104
+
105
+ for (const file of files) {
106
+ const fullPath = path.join(jobsDir, file);
107
+ try {
108
+ const module = await import(`file://${fullPath}`);
109
+ if (typeof module.default === "function") {
110
+ const jobName = path.basename(file, path.extname(file));
111
+ this.process(jobName, module.default);
112
+ }
113
+ } catch (err) {
114
+ console.error(`[QUEUE ERROR] Failed to load job file '${file}':`, err.message);
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ export const Queue = new QueueManager();
121
+ export default Queue;
package/core/validate.js CHANGED
@@ -148,19 +148,20 @@ class Validator {
148
148
  * const result = await loginValidator.validate(req);
149
149
  */
150
150
  async validate(req) {
151
+ const isExpressReq = req && (req.body !== undefined || req.headers !== undefined);
151
152
  let lang =
152
153
  req?.body?.lang ||
153
154
  req?.query?.lang ||
154
155
  req?.params?.lang ||
155
156
  req?.cookies?.lang ||
156
- req?.headers["accept-language"]?.split(",")[0]?.split("-")[0] ||
157
+ req?.headers?.["accept-language"]?.split(",")[0]?.split("-")[0] ||
157
158
  req?.session?.lang ||
158
159
  this.lang_default ||
159
160
  "es";
160
161
  const msg = this.messages[lang] || this.messages.es;
161
162
  const errors = [];
162
163
  const messages = [];
163
- const body = req.body || {};
164
+ const body = isExpressReq ? (req.body || {}) : (req || {});
164
165
 
165
166
  for (const [field, config] of Object.entries(this.schema)) {
166
167
  let value = body[field];
package/docker/nginx.conf CHANGED
@@ -65,6 +65,29 @@ http {
65
65
  try_files $uri =404;
66
66
  }
67
67
 
68
+ # -------------------------------------------------------------
69
+ # Optional: Protected Static Frontend Pages (auth_request)
70
+ # Uncomment this block to protect private static pages (e.g. /dashboard)
71
+ # Nginx will subrequest Express /api/auth/check before serving HTML.
72
+ # -------------------------------------------------------------
73
+ # location ~ ^/(dashboard|admin|app|account) {
74
+ # auth_request /api/auth/check;
75
+ # error_page 401 = @login_redirect;
76
+ # try_files $uri $uri.html /index.html =404;
77
+ # }
78
+ #
79
+ # location = /api/auth/check {
80
+ # internal;
81
+ # proxy_pass http://app:3000/api/auth/check;
82
+ # proxy_pass_request_body off;
83
+ # proxy_set_header Content-Length "";
84
+ # proxy_set_header X-Original-URI $request_uri;
85
+ # }
86
+ #
87
+ # location @login_redirect {
88
+ # return 302 /login?redirect=$request_uri;
89
+ # }
90
+
68
91
  location / {
69
92
  add_header Cache-Control "no-cache";
70
93
  try_files $uri $uri.html $uri/ @node_app;
@@ -1,145 +1,145 @@
1
- <!DOCTYPE html>
2
- <html lang="en" data-theme="dark">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Blue Bird Framework</title>
8
- <link rel="canonical" href="https://seip25.github.io/Blue-bird/" />
9
- <meta name="description"
10
- content="Blue Bird is a fast, structured, and opinionated Express.js framework for developers who want visual elegance and performance with raw HTML and CSS.">
11
- <meta name="keywords" content="Blue Bird, Express.js, Node.js, Semantic CSS, Performance, Nginx, Redis">
12
- <meta name="author" content="Seip25">
13
- <link rel="icon" href="/images/favicon.ico" />
14
- <link rel="stylesheet" href="/css/bluebird.css" />
15
- <script src="/js/bluebird.js"></script>
16
- </head>
17
-
18
- <body>
19
- <header>
20
- <nav>
21
- <a href="/" class="flex items-center gap-2">
22
- <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
23
- stroke-linecap="round" stroke-linejoin="round" class="text-blue">
24
- <path d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
25
- </svg>
26
- <strong class="text-xl text-gradient">Blue Bird</strong>
27
- </a>
28
- </nav>
29
- </header>
30
-
31
- <main>
32
- <aside>
33
- <h4>Menu</h4>
34
- <a href="/" class="active badge badge-glow px-3 py-3">Home</a>
35
- <a href="/about">About</a>
36
- <a href="https://seip25.github.io/Blue-bird-css/" target="_blank">Blue Bird CSS</a>
37
- <a href="https://github.com/seip25/Blue-bird" target="_blank" role="button"
38
- class="btn-sm outline">GitHub</a>
39
- </aside>
40
-
41
- <div>
42
- <section class="hero ">
43
- <h1 class="mt-3 text-gradient font-bold">Hello, Developer!</h1>
44
- <p class="lead">
45
- Blue Bird is a fast, structured, and opinionated Express.js framework for developers who want
46
- visual elegance and performance with raw HTML and CSS.
47
- </p>
48
- <div class="hero-actions">
49
- <a href="/about" role="button">About Us &rarr;</a>
50
- <a href="https://seip25.github.io/Blue-bird-css/" target="_blank" role="button" class="outline">Blue
51
- Bird CSS Docs</a>
52
- <a href="https://github.com/seip25/Blue-bird" target="_blank" role="button"
53
- class="outline">GitHub</a>
54
- </div>
55
- </section>
56
-
57
- <div class="mt-8">
58
- <div class="grid cols-3 gap-4">
59
- <article class="hover-glow ">
60
- <header>
61
- <span class="badge badge-primary mb-2">Rendering</span>
62
- <h3 class="text-gradient-blue">Ultra-Fast HTML Render</h3>
63
- </header>
64
- <p>Direct static HTML rendering using high-speed string placeholder
65
- replacement, bypassing heavy
66
- parsing engines completely.</p>
67
- </article>
68
-
69
- <article class="hover-glow ">
70
- <header>
71
- <span class="badge badge-primary mb-2">Performance</span>
72
- <h3 class="text-gradient-blue">In-Memory Caching</h3>
73
- </header>
74
- <p>Configurable time-to-live caching. Rendered pages are stored in RAM for
75
- instant,
76
- sub-millisecond
77
- delivery in production.</p>
78
- </article>
79
-
80
- <article class="hover-glow ">
81
- <header>
82
- <span class="badge badge-primary mb-2">Security</span>
83
- <h3 class="text-gradient-blue">JWT &amp; Route Security</h3>
84
- </header>
85
- <p>Secure cookie management, GCM-encrypted JWT tokens, custom helmet
86
- configurations, and route
87
- rate
88
- limiting built-in.</p>
89
- </article>
90
-
91
- <article class="hover-glow ">
92
- <header>
93
- <span class="badge badge-primary mb-2">Database</span>
94
- <h3 class="text-gradient-blue">Unified DB Layer</h3>
95
- </header>
96
- <p>Built-in support for SQLite (WAL mode), MySQL, and PostgreSQL with
97
- connection pooling,
98
- retries,
99
- and Redis query caching.</p>
100
- </article>
101
-
102
- <article class="hover-glow ">
103
- <header>
104
- <span class="badge badge-primary mb-2">DevOps</span>
105
- <h3 class="text-gradient-blue">Zero-Config Docker</h3>
106
- </header>
107
- <p>Containerized development &amp; production orchestration with Nginx
108
- static delivery and Redis
109
- caching out of the box.</p>
110
- </article>
111
-
112
- <article class="hover-glow ">
113
- <header>
114
- <span class="badge badge-primary mb-2">Design</span>
115
- <h3 class="text-gradient-blue">Pure Semantic CSS</h3>
116
- </header>
117
- <p>Clean semantic markup styled by <a href="https://seip25.github.io/Blue-bird-css/"
118
- target="_blank">Blue Bird CSS</a> with
119
- zero JavaScript framework bloat or compile steps.
120
- </p>
121
- </article>
122
- </div>
123
- </div>
124
- </div>
125
- </main>
126
-
127
- <footer>
128
- <div class="footer-content">
129
- <p>Powered by <strong class="text-gradient">Blue Bird Framework</strong> &amp;
130
- <strong class="text-gradient-blue">
131
- <a href="https://seip25.github.io/Blue-bird-css/" target="_blank">Blue Bird
132
- CSS</a>
133
- </strong>.
134
- </p>
135
- <div class="lang-switcher">
136
- <a href="/" class="lang-link">Home</a>
137
- <a href="/about" class="lang-link">About</a>
138
- <a href="https://github.com/seip25/Blue-bird" target="_blank" class="github-star mt-2">&#9733;
139
- GitHub</a>
140
- </div>
141
- </div>
142
- </footer>
143
- </body>
144
-
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="dark">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Blue Bird Framework</title>
8
+ <link rel="canonical" href="https://seip25.github.io/Blue-bird/" />
9
+ <meta name="description"
10
+ content="Blue Bird is a fast, structured, and opinionated Express.js framework for developers who want visual elegance and performance with raw HTML and CSS.">
11
+ <meta name="keywords" content="Blue Bird, Express.js, Node.js, Semantic CSS, Performance, Nginx, Redis">
12
+ <meta name="author" content="Seip25">
13
+ <link rel="icon" href="/images/favicon.ico" />
14
+ <link rel="stylesheet" href="/css/bluebird.css" />
15
+ <script src="/js/bluebird.js"></script>
16
+ </head>
17
+
18
+ <body>
19
+ <header>
20
+ <nav>
21
+ <a href="/" class="flex items-center gap-2">
22
+ <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
23
+ stroke-linecap="round" stroke-linejoin="round" class="text-blue">
24
+ <path d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
25
+ </svg>
26
+ <strong class="text-xl text-gradient">Blue Bird</strong>
27
+ </a>
28
+ </nav>
29
+ </header>
30
+
31
+ <main>
32
+ <aside>
33
+ <h4>Menu</h4>
34
+ <a href="/" class="active badge badge-glow px-3 py-3">Home</a>
35
+ <a href="/about">About</a>
36
+ <a href="https://seip25.github.io/Blue-bird-css/" target="_blank">Blue Bird CSS</a>
37
+ <a href="https://github.com/seip25/Blue-bird" target="_blank" role="button"
38
+ class="btn-sm outline">GitHub</a>
39
+ </aside>
40
+
41
+ <div>
42
+ <section class="hero ">
43
+ <h1 class="mt-3 text-gradient font-bold">Hello, Developer!</h1>
44
+ <p class="lead">
45
+ Blue Bird is a fast, structured, and opinionated Express.js framework for developers who want
46
+ visual elegance and performance with raw HTML and CSS.
47
+ </p>
48
+ <div class="hero-actions">
49
+ <a href="/about" role="button">About Us &rarr;</a>
50
+ <a href="https://seip25.github.io/Blue-bird-css/" target="_blank" role="button" class="outline">Blue
51
+ Bird CSS Docs</a>
52
+ <a href="https://github.com/seip25/Blue-bird" target="_blank" role="button"
53
+ class="outline">GitHub</a>
54
+ </div>
55
+ </section>
56
+
57
+ <div class="mt-8">
58
+ <div class="grid cols-3 gap-4">
59
+ <article class="hover-glow ">
60
+ <header>
61
+ <span class="badge badge-primary mb-2">Rendering</span>
62
+ <h3 class="text-gradient-blue">Ultra-Fast HTML Render</h3>
63
+ </header>
64
+ <p>Direct static HTML rendering using high-speed string placeholder
65
+ replacement, bypassing heavy
66
+ parsing engines completely.</p>
67
+ </article>
68
+
69
+ <article class="hover-glow ">
70
+ <header>
71
+ <span class="badge badge-primary mb-2">Performance</span>
72
+ <h3 class="text-gradient-blue">In-Memory Caching</h3>
73
+ </header>
74
+ <p>Configurable time-to-live caching. Rendered pages are stored in RAM for
75
+ instant,
76
+ sub-millisecond
77
+ delivery in production.</p>
78
+ </article>
79
+
80
+ <article class="hover-glow ">
81
+ <header>
82
+ <span class="badge badge-primary mb-2">Security</span>
83
+ <h3 class="text-gradient-blue">JWT &amp; Route Security</h3>
84
+ </header>
85
+ <p>Secure cookie management, GCM-encrypted JWT tokens, custom helmet
86
+ configurations, and route
87
+ rate
88
+ limiting built-in.</p>
89
+ </article>
90
+
91
+ <article class="hover-glow ">
92
+ <header>
93
+ <span class="badge badge-primary mb-2">Database</span>
94
+ <h3 class="text-gradient-blue">Unified DB Layer</h3>
95
+ </header>
96
+ <p>Built-in support for SQLite (WAL mode), MySQL, and PostgreSQL with
97
+ connection pooling,
98
+ retries,
99
+ and Redis query caching.</p>
100
+ </article>
101
+
102
+ <article class="hover-glow ">
103
+ <header>
104
+ <span class="badge badge-primary mb-2">DevOps</span>
105
+ <h3 class="text-gradient-blue">Zero-Config Docker</h3>
106
+ </header>
107
+ <p>Containerized development &amp; production orchestration with Nginx
108
+ static delivery and Redis
109
+ caching out of the box.</p>
110
+ </article>
111
+
112
+ <article class="hover-glow ">
113
+ <header>
114
+ <span class="badge badge-primary mb-2">Design</span>
115
+ <h3 class="text-gradient-blue">Pure Semantic CSS</h3>
116
+ </header>
117
+ <p>Clean semantic markup styled by <a href="https://seip25.github.io/Blue-bird-css/"
118
+ target="_blank">Blue Bird CSS</a> with
119
+ zero JavaScript framework bloat or compile steps.
120
+ </p>
121
+ </article>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ </main>
126
+
127
+ <footer>
128
+ <div class="footer-content">
129
+ <p>Powered by <strong class="text-gradient">Blue Bird Framework</strong> &amp;
130
+ <strong class="text-gradient-blue">
131
+ <a href="https://seip25.github.io/Blue-bird-css/" target="_blank">Blue Bird
132
+ CSS</a>
133
+ </strong>.
134
+ </p>
135
+ <div class="lang-switcher">
136
+ <a href="/" class="lang-link">Home</a>
137
+ <a href="/about" class="lang-link">About</a>
138
+ <a href="https://github.com/seip25/Blue-bird" target="_blank" class="github-star mt-2">&#9733;
139
+ GitHub</a>
140
+ </div>
141
+ </div>
142
+ </footer>
143
+ </body>
144
+
145
145
  </html>