@63klabs/cache-data 1.3.0 → 1.3.2

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/CHANGELOG.md CHANGED
@@ -8,6 +8,16 @@ Report all vulnerabilities under the [Security menu](https://github.com/63Klabs/
8
8
 
9
9
  > Note: This project is still in beta. Even though changes are tested and breaking changes are avoided, things may break.
10
10
 
11
+ ## 1.3.2 (2025-09-12)
12
+
13
+ ### Enhancements
14
+
15
+ - `DebugAndLog`: The environment variable `AWS_LAMBDA_LOG_LEVEL` is now checked as well for setting logging level. `LOG_LEVEL` has priority.
16
+
17
+ ### Fixes
18
+
19
+ - `DebugAndLog`: Environment and Logging Level value checks are fixed
20
+
11
21
  ## 1.3.0 (2025-07-16)
12
22
 
13
23
  ### Enhancements
package/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) [year] [fullname]
3
+ Copyright (c) 2025 Chad Kluck
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@63klabs/cache-data",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Cache data from an API endpoint or application process using AWS S3 and DynamoDb",
5
5
  "author": "Chad Leigh Kluck (https://chadkluck.me)",
6
6
  "license": "MIT",
@@ -25,7 +25,7 @@
25
25
  "@aws-sdk/client-s3": "3.x",
26
26
  "@aws-sdk/client-ssm": "3.x",
27
27
  "@aws-sdk/lib-dynamodb": "3.x",
28
- "chai": "^5.2.0",
28
+ "chai": "^6.0.1",
29
29
  "chai-http": "^5.1.2",
30
30
  "mocha": "^11.7.1",
31
31
  "sinon": "^21.0.0"
@@ -1,153 +1,230 @@
1
1
  const { sanitize } = require("./utils");
2
2
  const util = require('util');
3
3
 
4
+ const _getNodeEnv = function() {
5
+ return process.env?.NODE_ENV === "development" ? "development" : "production";
6
+ };
7
+
8
+ "use strict"
9
+
4
10
  /**
5
11
  * A simple Debug and Logging class.
6
12
  */
7
13
  class DebugAndLog {
8
14
 
9
15
  static #logLevel = -1;
10
- static #expiration = -1;
16
+ static #environment = null;
17
+ static #initialNodeEnv = _getNodeEnv();
18
+ static #nodeEnvChangeWarnCount = 0;
19
+
20
+ // in priority order
21
+ static ALLOWED_ENV_TYPE_VAR_NAMES = ["CACHE_DATA_ENV", "DEPLOY_ENVIRONMENT", "DEPLOY_ENV", "ENV_TYPE", "deploy_environment", "ENV", "env", "deployEnvironment", "ENVIRONMENT", "environment"];
22
+ static ALLOWED_LOG_VAR_NAMES = ["CACHE_DATA_LOG_LEVEL", "LOG_LEVEL", "log_level", "detailedLogs", "logLevel", "AWS_LAMBDA_LOG_LEVEL"]
11
23
 
12
24
  static PROD = "PROD";
13
25
  static TEST = "TEST";
14
26
  static DEV = "DEV";
15
27
 
16
- static ENVIRONMENTS = [DebugAndLog.PROD, DebugAndLog.TEST, DebugAndLog.DEV];
28
+ static ENVIRONMENTS = ["PROD", "TEST", "DEV"];//[DebugAndLog.PROD, DebugAndLog.TEST, DebugAndLog.DEV];
29
+
30
+ static LOG = "LOG";
31
+ static ERROR = "ERROR";
32
+ static WARN = "WARN";
33
+ static INFO = "INFO";
34
+ static MSG = "MSG";
35
+ static DIAG = "DIAG";
36
+ static DEBUG = "DEBUG";
37
+
38
+ static LOG_LEVEL_NUM = 0;
39
+ static ERROR_LEVEL_NUM = 0;
40
+ static WARN_LEVEL_NUM = 1;
41
+ static INFO_LEVEL_NUM = 2;
42
+ static MSG_LEVEL_NUM = 3;
43
+ static DIAG_LEVEL_NUM = 4;
44
+ static DEBUG_LEVEL_NUM = 5;
17
45
 
18
- static ERROR = "ERROR"; // 0
19
- static WARN = "WARN"; // 0
20
- static LOG = "LOG"; // 0
21
- static MSG = "MSG"; // 1
22
- static DIAG = "DIAG"; // 3
23
- static DEBUG = "DEBUG"; // 5
46
+ static PROD_DEFAULT_LEVEL_NUM = 2;
24
47
 
25
48
  constructor() {
26
49
  };
27
50
 
28
51
  /**
29
52
  * Set the log level.
53
+ * Deprecated. Set Lambda Environment variable CACHE_DATA_LOG_LEVEL, LOG_LEVEL, or AWS_LAMBDA_LOG_LEVEL instead.
30
54
  * @param {number} logLevel 0 - 5
31
- * @param {*} expiration YYYY-MM-DD HH:MM:SS format. Only set to specified level until this date
55
+ * @param {*} expiration Deprecated - no effect
32
56
  */
33
57
  static setLogLevel(logLevel = -1, expiration = -1) {
34
-
35
- if ( process.env.NODE_ENV === "production" && this.#logLevel > -1 ) {
36
- DebugAndLog.warn("LogLevel already set, cannot reset. Ignoring call to DebugAndLog.setLogLevel("+logLevel+")");
37
- } else {
38
- if ( expiration !== -1 ) {
39
- let time = new Date( expiration );
40
- this.#expiration = time.toISOString();
41
- } else {
42
- this.#expiration = -1;
43
- }
44
-
45
- if ( logLevel === -1 || this.nonDefaultLogLevelExpired()) {
46
- this.#logLevel = this.getDefaultLogLevel();
58
+ DebugAndLog.warn(`DebugAndLog.setLogLevel(${logLevel}, ${expiration}) is deprecated. Use CACHE_DATA_LOG_LEVEL, LOG_LEVEL, or AWS_LAMBDA_LOG_LEVEL environment variable instead.`);
59
+
60
+ if (DebugAndLog.isProduction()) {
61
+ if (Number.isFinite(Number(logLevel)) && Number(logLevel) <= DebugAndLog.PROD_DEFAULT_LEVEL_NUM) {
62
+ this.#logLevel = Number(logLevel);
47
63
  } else {
48
- if ( logLevel > 0 && DebugAndLog.isProduction() ) {
49
- DebugAndLog.warn("DebugAndLog: Production environment. Cannot set logLevel higher than 0. Ignoring call to DebugAndLog.setLogLevel("+logLevel+"). Default LogLevel override code should be removed before production");
50
- this.#logLevel = this.getDefaultLogLevel();
51
- } else {
52
- this.#logLevel = logLevel;
53
- DebugAndLog.msg("DebugAndLog: Override of log level default set: "+logLevel+". Default LogLevel override code should be removed before production");
54
- if ( this.#expiration === -1 ) {
55
- DebugAndLog.warn("DebugAndLog: Override of log level default set WITHOUT EXPIRATION. An expiration is recommended.");
56
- }
57
- }
58
- }
59
- }
60
-
61
- };
62
-
63
- static nonDefaultLogLevelExpired() {
64
- let r = false;
65
-
66
- if ( this.#expiration !== -1 ) {
67
- let now = new Date();
68
- if ( now.toISOString() > this.#expiration ) {
69
- DebugAndLog.warn("DebugAndLog: Override of log level default expired. Call to DebugAndLog.setLogLevel() should be commented out or removed");
70
- r = true;
64
+ this.#logLevel = DebugAndLog.PROD_DEFAULT_LEVEL_NUM;
71
65
  }
66
+ } else if (Number.isFinite(Number(logLevel))) {
67
+ this.#logLevel = Number(logLevel);
72
68
  }
73
69
 
74
- return r;
75
- }
76
-
77
- /**
78
- *
79
- * @returns {string} The expiration date of the set log level
80
- */
81
- static getExpiration() {
82
- return this.#expiration;
83
- }
70
+ return this.#logLevel;
71
+ };
84
72
 
85
73
  /**
86
74
  *
87
75
  * @returns {number} The current log level
88
76
  */
89
77
  static getLogLevel() {
90
- if ( this.#logLevel === -1 ) {
91
- this.setLogLevel();
78
+
79
+ if ( this.#logLevel < 0 || DebugAndLog.nodeEnvIsDevelopment() || DebugAndLog.nodeEnvHasChanged() ) {
80
+ this.#logLevel = this.getDefaultLogLevel();
92
81
  }
93
82
 
94
83
  return this.#logLevel;
95
84
 
96
85
  }
97
86
 
87
+ /**
88
+ * Alias for getEnvType()
89
+ */
90
+ static getEnv() {
91
+ return DebugAndLog.getEnvType();
92
+ };
93
+
98
94
  /**
99
95
  * Check process.env for an environment variable named
100
96
  * env, deployEnvironment, environment, or stage. If they
101
97
  * are not set it will return DebugAndLog.PROD which
102
98
  * is considered safe (most restrictive)
103
99
  * Note: This is the application environment, not the NODE_ENV
104
- * @returns {string} The current environment.
100
+ * @returns {string} PROD|TEST|DEV - The current environment.
105
101
  */
106
- static getEnv() {
107
- var possibleVars = ["env", "deployEnvironment", "environment", "stage, deploy_environment"]; // this is the application env, not the NODE_ENV
108
- var env = (process.env?.NODE_ENV === "development" ? DebugAndLog.DEV : DebugAndLog.PROD); // if env or deployEnvironment not set, fail to safe
109
-
110
- if ( "env" in process ) {
111
- for (let i in possibleVars) {
112
- let e = possibleVars[i];
113
- let uE = possibleVars[i].toUpperCase();
114
- if (e in process.env && process.env[e] !== "" && process.env[e] !== null) {
115
- env = process.env[e].toUpperCase();
116
- break; // break out of the for loop
117
- } else if (uE in process.env && process.env[uE] !== "" && process.env[uE] !== null) {
118
- env = process.env[uE].toUpperCase();
119
- break; // break out of the for loop
120
- }
121
- };
102
+ static getEnvType() {
103
+ // We can switch if NODE_ENV is set to "development"
104
+ if ( this.#environment === null || DebugAndLog.nodeEnvIsDevelopment() || DebugAndLog.nodeEnvHasChanged) {
105
+ const nodeEnvType = (DebugAndLog.nodeEnvIsDevelopment() ? DebugAndLog.DEV : DebugAndLog.PROD); // if env or deployEnvironment not set, fail to safe
106
+ const envType = DebugAndLog.getEnvTypeFromEnvVar();
107
+
108
+ this.#environment = (DebugAndLog.ENVIRONMENTS.includes(envType) ? envType : nodeEnvType);
122
109
  }
123
- return (DebugAndLog.ENVIRONMENTS.includes(env) ? env : DebugAndLog.PROD);
124
- };
110
+
111
+ return this.#environment;
112
+ }
113
+ /**
114
+ *
115
+ * @returns {string} PROD|TEST|DEV|NONE based upon first environment variable from DebugAndLog.ALLOWED_ENV_TYPE_VAR_NAMES found
116
+ */
117
+ static getEnvTypeFromEnvVar() {
118
+ let environmentType = "none";
119
+ const possibleVars = DebugAndLog.ALLOWED_ENV_TYPE_VAR_NAMES; // - this is the application env, not the NODE_ENV
120
+
121
+ for (let i in possibleVars) {
122
+ let e = possibleVars[i];
123
+ if (e in process.env && process.env[e] !== "" && process.env[e] !== null && DebugAndLog.ENVIRONMENTS.includes(process.env[e].toUpperCase())) {
124
+ environmentType = process.env[e].toUpperCase();
125
+ break; // break out of the for loop
126
+ }
127
+ };
128
+
129
+ return environmentType;
130
+ }
131
+
132
+ /**
133
+ * Is Environment Variable NODE_ENV set to "development"?
134
+ */
135
+ static nodeEnvIsDevelopment() {
136
+ return DebugAndLog.getNodeEnv() === "development";
137
+ }
138
+
139
+ /**
140
+ * Is Environment Variable NODE_ENV set to "production" or "" or undefined?
141
+ */
142
+ static nodeEnvIsProduction() {
143
+ return !this.nodeEnvIsDevelopment();
144
+ }
145
+
146
+ /**
147
+ * Get the current NODE_ENV (returns "production" if not set or if NODE_ENV is set to anything other than "development")
148
+ * Calls DebugAndLog.nodeEnvHasChanged() to log a warning if the value has changed since initialization. Should only change during testing.
149
+ * @returns {string} development|production
150
+ */
151
+ static getNodeEnv() {
152
+ DebugAndLog.nodeEnvHasChanged();
153
+ return _getNodeEnv();
154
+ }
155
+
156
+ /**
157
+ * Checks to see if the current NODE_ENV environment variable has changed since DebugAndLog was initialized.
158
+ * The only time this should happen is while running tests. This should never happen in a production application.
159
+ * If these warnings are triggered as you application is running, something is modifying process.env.NODE_ENV during execution.
160
+ * @returns {boolean}
161
+ */
162
+ static nodeEnvHasChanged() {
163
+ const hasChanged = _getNodeEnv() !== this.#initialNodeEnv;
164
+ if (hasChanged && this.#logLevel > -1) {
165
+ this.#nodeEnvChangeWarnCount++;
166
+ // if this.#nodeEnvChangeWarnCount == 1 or is divisible by 25
167
+ if (this.#nodeEnvChangeWarnCount === 1 || this.#nodeEnvChangeWarnCount % 100 === 0) {
168
+ DebugAndLog.warn(`DebugAndLog: NODE_ENV changed from initial value of '${this.#initialNodeEnv}' to '${_getNodeEnv()}' during execution. This is not recommended outside of tests.`);
169
+ }
170
+ } else {
171
+ this.#nodeEnvChangeWarnCount = 0;
172
+ }
173
+
174
+ return hasChanged;
175
+ }
125
176
 
126
177
  /**
127
178
  *
128
179
  * @returns {number} log level
129
180
  */
130
181
  static getDefaultLogLevel() {
131
- var possibleVars = ["detailedLogs", "logLevel"];
132
- var logLevel = 0;
133
-
134
- if ( DebugAndLog.isNotProduction() ) { // PROD is always at logLevel 0. Always.
135
-
136
- if ( "env" in process ) {
137
- for (let i in possibleVars) {
138
- let lev = possibleVars[i];
139
- let uLEV = possibleVars[i].toUpperCase();
140
- if (lev in process.env && !(Number.isNaN(process.env[lev])) && process.env[lev] !== "" && process.env[lev] !== null) {
141
- logLevel = Number(process.env[lev]);
142
- break; // break out of the for loop
143
- } else if (uLEV in process.env && !(Number.isNaN(process.env[uLEV])) && process.env[uLEV] !== "" && process.env[uLEV] !== null) {
144
- logLevel = Number(process.env[uLEV]);
145
- break; // break out of the for loop
182
+ let possibleVars = DebugAndLog.ALLOWED_LOG_VAR_NAMES; // in priority order and we want to evaluate AWS_LAMBDA_LOG_LEVEL as upper
183
+ let logLevel = DebugAndLog.PROD_DEFAULT_LEVEL_NUM;
184
+ let found = false;
185
+
186
+ for (let i in possibleVars) {
187
+ let lev = possibleVars[i];
188
+ if (lev in process.env && process.env[lev] !== "" && process.env[lev] !== null) {
189
+ if (lev === "AWS_LAMBDA_LOG_LEVEL") {
190
+
191
+ switch (process.env.AWS_LAMBDA_LOG_LEVEL) {
192
+ case "DEBUG":
193
+ logLevel = DebugAndLog.DEBUG_LEVEL_NUM;
194
+ found = true;
195
+ break;
196
+ case "INFO":
197
+ logLevel = DebugAndLog.INFO_LEVEL_NUM;
198
+ found = true;
199
+ break;
200
+ case "WARN":
201
+ logLevel = DebugAndLog.WARN_LEVEL_NUM;
202
+ found = true;
203
+ break;
204
+ case "ERROR":
205
+ logLevel = DebugAndLog.ERROR_LEVEL_NUM;
206
+ found = true;
207
+ break;
208
+ default: // invalid
209
+ break;
146
210
  }
147
- };
148
- }
149
211
 
150
- }
212
+ } else if (Number.isFinite(Number(process.env[lev]))) {
213
+ logLevel = Number(process.env[lev]);
214
+ found = true;
215
+ }
216
+
217
+ if (found) {
218
+ if (DebugAndLog.isProduction()) {
219
+ if (logLevel > DebugAndLog.PROD_DEFAULT_LEVEL_NUM) {
220
+ DebugAndLog.warn(`DebugAndLog: ${lev} set to ${logLevel} in production environment. Only 0-2 is allowed in production. Setting to ${DebugAndLog.PROD_DEFAULT_LEVEL_NUM}`);
221
+ logLevel = DebugAndLog.PROD_DEFAULT_LEVEL_NUM;
222
+ }
223
+ }
224
+ break; // break out of the for loop
225
+ }
226
+ }
227
+ };
151
228
 
152
229
  return logLevel;
153
230
  };
@@ -205,44 +282,6 @@ class DebugAndLog {
205
282
  const FORMAT_WITH_OBJ = '[%s] %s | %s';
206
283
  const FORMAT_WITHOUT_OBJ = '[%s] %s';
207
284
 
208
- // const baseLog = function(level, tag, message, obj = null) {
209
- // // Validate inputs
210
- // if (typeof level !== 'string') {
211
- // throw new TypeError('Log level must be a string');
212
- // }
213
-
214
- // // Ensure tag and message are strings
215
- // const safeTag = String(tag || '');
216
- // const safeMessage = String(message || '');
217
-
218
- // // Validate log level is allowed
219
- // if (!Object.prototype.hasOwnProperty.call(logLevels, level)) {
220
- // level = 'info'; // Default to info if invalid level
221
- // }
222
-
223
- // const logFn = logLevels[level];
224
-
225
- // try {
226
- // let formattedMessage;
227
- // if (obj !== null) {
228
- // formattedMessage = util.format(
229
- // '[%s] %s | %s',
230
- // safeTag,
231
- // safeMessage,
232
- // util.inspect(sanitize(obj), { depth: null })
233
- // );
234
- // } else {
235
- // formattedMessage = util.format(
236
- // '[%s] %s',
237
- // safeTag,
238
- // safeMessage
239
- // );
240
- // }
241
- // logFn(formattedMessage);
242
- // } catch (error) {
243
- // console.error('Logging failed:', error);
244
- // }
245
- // };
246
285
  const baseLog = function(level, tag, message, obj = null) {
247
286
  // Early return for invalid input
248
287
  if (typeof level !== 'string') {
@@ -288,33 +327,29 @@ class DebugAndLog {
288
327
  const info = (tag, message, obj) => baseLog('info', tag, message, obj);
289
328
  const debug = (tag, message, obj) => baseLog('debug', tag, message, obj);
290
329
 
291
- let lvl = DebugAndLog.getLogLevel();
292
- tag = tag.toUpperCase();
330
+ // let lvl = (this.#logLevel > -1) ? DebugAndLog.getLogLevel() : DebugAndLog.MSG_LEVEL_NUM;
331
+ let lvl = (this.#logLevel > -1) ? this.#logLevel : DebugAndLog.INFO_LEVEL_NUM;
293
332
 
294
- // if ( obj !== null ) {
295
- // let msgObj = obj;
296
- // if ( Array.isArray(msgObj)) { msgObj = { array: msgObj};}
297
- // if ( ""+msgObj === "[object Object]" || ""+msgObj === "[object Array]") {
298
- // msgObj = JSON.stringify(sanitize(msgObj));
299
- // }
300
- // message += " | "+msgObj;
301
- // }
333
+ tag = tag.toUpperCase();
302
334
 
303
335
  switch (tag) {
304
336
  case DebugAndLog.ERROR:
305
337
  error(tag, message, obj);
306
338
  break;
307
339
  case DebugAndLog.WARN:
308
- warn(tag, message, obj);
340
+ if (lvl >= DebugAndLog.WARN_LEVEL_NUM) { warn(tag, message, obj); }
309
341
  break;
342
+ case DebugAndLog.INFO:
343
+ if (lvl >= DebugAndLog.INFO_LEVEL_NUM) { info(tag, message, obj); }
344
+ break;
310
345
  case DebugAndLog.MSG:
311
- if (lvl >= 1) { info(tag, message, obj); } // 1
346
+ if (lvl >= DebugAndLog.MSG_LEVEL_NUM) { info(tag, message, obj); }
312
347
  break;
313
348
  case DebugAndLog.DIAG:
314
- if (lvl >= 3) { debug(tag, message, obj); } //3
349
+ if (lvl >= DebugAndLog.DIAG_LEVEL_NUM) { debug(tag, message, obj); }
315
350
  break;
316
351
  case DebugAndLog.DEBUG:
317
- if (lvl >= 5) { debug(tag, message, obj); } //5
352
+ if (lvl >= DebugAndLog.DEBUG_LEVEL_NUM) { debug(tag, message, obj); }
318
353
  break;
319
354
  default: // log
320
355
  log(tag, message, obj);
@@ -343,7 +378,7 @@ class DebugAndLog {
343
378
  };
344
379
 
345
380
  /**
346
- * Level 1 - Short messages and status
381
+ * Level 2 - Short messages and status
347
382
  * @param {string} message
348
383
  * @param {object} obj
349
384
  */
@@ -352,7 +387,7 @@ class DebugAndLog {
352
387
  };
353
388
 
354
389
  /**
355
- * Level 1 - Short messages and status
390
+ * Level 2 - Short messages and status
356
391
  * (same as DebugAndLog.msg() )
357
392
  * @param {string} message
358
393
  * @param {object} obj
@@ -361,6 +396,15 @@ class DebugAndLog {
361
396
  return DebugAndLog.msg(message, obj);
362
397
  };
363
398
 
399
+ /**
400
+ * Level 1 - Short messages and status
401
+ * @param {string} message
402
+ * @param {object} obj
403
+ */
404
+ static async info(message, obj = null) {
405
+ return DebugAndLog.writeLog(DebugAndLog.INFO, message, obj);
406
+ };
407
+
364
408
  /**
365
409
  * Level 0 - Production worthy log entries that are not errors or warnings
366
410
  * These should be formatted in a consistent manner and typically only
@@ -413,4 +457,6 @@ class DebugAndLog {
413
457
 
414
458
  };
415
459
 
460
+ DebugAndLog.getLogLevel();
461
+
416
462
  module.exports = DebugAndLog;