@seip/blue-bird 1.0.2 → 1.1.1

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/cache.js CHANGED
@@ -4,6 +4,17 @@ const CACHE = {};
4
4
 
5
5
  let redisClient = null;
6
6
  let isRedisConnected = false;
7
+
8
+ const rawCacheMode = (process.env.CACHE_MODE || "").toLowerCase().trim();
9
+ const CACHE_MODE =
10
+ rawCacheMode || (process.env.REDIS_HOST ? "redis" : "memory");
11
+ const isRedisMode = CACHE_MODE === "redis";
12
+ const isMemoryMode = CACHE_MODE === "memory" || CACHE_MODE === "inmemory";
13
+ const isNoneMode =
14
+ CACHE_MODE === "none" ||
15
+ CACHE_MODE === "disabled" ||
16
+ CACHE_MODE === "false";
17
+
7
18
  const redisHost = process.env.REDIS_HOST ?? false;
8
19
  const redisPort = process.env.REDIS_PORT ?? 6379;
9
20
  const redisPassword = process.env.REDIS_PASSWORD || "";
@@ -12,12 +23,11 @@ const redisUrl = redisPassword
12
23
  : `redis://${redisHost}:${redisPort}`;
13
24
 
14
25
  /**
15
- * Initializes the Redis client connection if REDIS_HOST env is set.
26
+ * Initializes the Redis client connection if CACHE_MODE is 'redis' and REDIS_HOST is configured.
16
27
  * @returns {Promise<void>}
17
28
  */
18
29
  async function initRedis() {
19
- if (redisClient) return;
20
- if (!redisHost) return;
30
+ if (!isRedisMode || !redisHost || redisClient) return;
21
31
 
22
32
  try {
23
33
  const { createClient } = await import("redis");
@@ -45,8 +55,11 @@ async function initRedis() {
45
55
  }
46
56
  }
47
57
 
48
- initRedis().catch(() => { });
58
+ if (isRedisMode && redisHost) {
59
+ initRedis().catch(() => {});
60
+ }
49
61
 
62
+ // Background cleanup timer for in-memory cache
50
63
  setInterval(() => {
51
64
  const now = Date.now();
52
65
  for (const key in CACHE) {
@@ -67,13 +80,18 @@ class Cache {
67
80
  */
68
81
  static middleware(seconds = 60) {
69
82
  return async (req, res, next) => {
83
+ if (isNoneMode) {
84
+ return next();
85
+ }
86
+
70
87
  const key = req.originalUrl;
71
88
 
72
- if (redisHost && !redisClient) {
73
- await initRedis().catch(() => { });
89
+ // 1. Redis Cache Lookup (if enabled)
90
+ if (isRedisMode && redisHost && !redisClient) {
91
+ await initRedis().catch(() => {});
74
92
  }
75
93
 
76
- if (isRedisConnected && redisClient) {
94
+ if (isRedisMode && isRedisConnected && redisClient) {
77
95
  try {
78
96
  const cachedData = await redisClient.get(key);
79
97
  if (cachedData) {
@@ -87,12 +105,13 @@ class Cache {
87
105
  return res.send(cached.data);
88
106
  }
89
107
  }
90
- } catch (err) {
108
+ } catch {
91
109
  isRedisConnected = false;
92
110
  }
93
111
  }
94
112
 
95
- if (!isRedisConnected || !redisClient) {
113
+ // 2. In-Memory Cache Lookup (memory mode or fallback)
114
+ if (!isRedisMode || !isRedisConnected || !redisClient) {
96
115
  if (CACHE[key] && CACHE[key].expiry > Date.now()) {
97
116
  const cached = CACHE[key];
98
117
  if (cached.type === "json") {
@@ -118,12 +137,12 @@ class Cache {
118
137
  data: body,
119
138
  expiry: Date.now() + seconds * 1000,
120
139
  };
121
- if (isRedisConnected && redisClient) {
140
+ if (isRedisMode && isRedisConnected && redisClient) {
122
141
  try {
123
142
  await redisClient.set(key, JSON.stringify(cacheObject), {
124
143
  EX: seconds,
125
144
  });
126
- } catch (err) {
145
+ } catch {
127
146
  CACHE[key] = cacheObject;
128
147
  }
129
148
  } else {
@@ -142,12 +161,12 @@ class Cache {
142
161
  data: body,
143
162
  expiry: Date.now() + seconds * 1000,
144
163
  };
145
- if (isRedisConnected && redisClient) {
164
+ if (isRedisMode && isRedisConnected && redisClient) {
146
165
  try {
147
166
  await redisClient.set(key, JSON.stringify(cacheObject), {
148
167
  EX: seconds,
149
168
  });
150
- } catch (err) {
169
+ } catch {
151
170
  CACHE[key] = cacheObject;
152
171
  }
153
172
  } else {
@@ -169,26 +188,29 @@ class Cache {
169
188
  * @returns {Promise<any|null>} Cached payload or null.
170
189
  */
171
190
  static async get(key) {
191
+ if (isNoneMode) return null;
172
192
  key = key.trim();
173
193
  if (!key) return null;
174
194
 
175
- if (redisHost && !redisClient) {
176
- await initRedis().catch(() => { });
195
+ if (isRedisMode && redisHost && !redisClient) {
196
+ await initRedis().catch(() => {});
177
197
  }
178
198
 
179
- if (isRedisConnected && redisClient) {
199
+ if (isRedisMode && isRedisConnected && redisClient) {
180
200
  try {
181
201
  const cachedData = await redisClient.get(key);
182
202
  if (cachedData) {
183
203
  try {
184
204
  const cached = JSON.parse(cachedData);
185
- return cached && typeof cached === "object" && "data" in cached ? cached.data : cached;
205
+ return cached && typeof cached === "object" && "data" in cached
206
+ ? cached.data
207
+ : cached;
186
208
  } catch {
187
209
  return cachedData;
188
210
  }
189
211
  }
190
212
  return null;
191
- } catch (err) {
213
+ } catch {
192
214
  isRedisConnected = false;
193
215
  }
194
216
  }
@@ -212,11 +234,12 @@ class Cache {
212
234
  * @returns {Promise<boolean>} True if set successfully.
213
235
  */
214
236
  static async set(key, value, seconds = 60) {
237
+ if (isNoneMode) return true;
215
238
  key = key.trim();
216
239
  if (!key) return false;
217
240
 
218
- if (redisHost && !redisClient) {
219
- await initRedis().catch(() => { });
241
+ if (isRedisMode && redisHost && !redisClient) {
242
+ await initRedis().catch(() => {});
220
243
  }
221
244
 
222
245
  const cacheObject = {
@@ -225,12 +248,12 @@ class Cache {
225
248
  expiry: Date.now() + seconds * 1000,
226
249
  };
227
250
 
228
- if (isRedisConnected && redisClient) {
251
+ if (isRedisMode && isRedisConnected && redisClient) {
229
252
  try {
230
253
  await redisClient.set(key, JSON.stringify(cacheObject), {
231
254
  EX: seconds,
232
255
  });
233
- } catch (err) {
256
+ } catch {
234
257
  CACHE[key] = cacheObject;
235
258
  }
236
259
  } else {
@@ -246,19 +269,19 @@ class Cache {
246
269
  * @returns {Promise<boolean>} True if deleted.
247
270
  */
248
271
  static async delete(keys) {
249
- if (!keys) return false;
272
+ if (isNoneMode || !keys) return false;
250
273
  const keyList = Array.isArray(keys) ? keys : [keys];
251
274
 
252
- if (redisHost && !redisClient) {
253
- await initRedis().catch(() => { });
275
+ if (isRedisMode && redisHost && !redisClient) {
276
+ await initRedis().catch(() => {});
254
277
  }
255
278
 
256
279
  for (const key of keyList) {
257
280
  delete CACHE[key];
258
- if (isRedisConnected && redisClient) {
281
+ if (isRedisMode && isRedisConnected && redisClient) {
259
282
  try {
260
283
  await redisClient.del(key);
261
- } catch (err) {
284
+ } catch {
262
285
  isRedisConnected = false;
263
286
  }
264
287
  }
@@ -284,15 +307,23 @@ class Cache {
284
307
  for (const key in CACHE) {
285
308
  delete CACHE[key];
286
309
  }
287
- if (isRedisConnected && redisClient) {
310
+ if (isRedisMode && isRedisConnected && redisClient) {
288
311
  try {
289
312
  await redisClient.flushDb();
290
- } catch (err) {
313
+ } catch {
291
314
  isRedisConnected = false;
292
315
  }
293
316
  }
294
317
  return true;
295
318
  }
319
+
320
+ /**
321
+ * Returns current active cache mode ('redis', 'memory', or 'none').
322
+ * @returns {string}
323
+ */
324
+ static getMode() {
325
+ return CACHE_MODE;
326
+ }
296
327
  }
297
328
 
298
329
  /**
@@ -300,7 +331,8 @@ class Cache {
300
331
  * @returns {Object|null} The Redis client instance or null.
301
332
  */
302
333
  export function getRedisClient() {
303
- return isRedisConnected ? redisClient : null;
334
+ return isRedisMode && isRedisConnected ? redisClient : null;
304
335
  }
305
336
 
306
337
  export default Cache;
338
+