@63klabs/cache-data 1.2.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 +234 -0
- package/LICENSE.txt +21 -0
- package/README.md +1265 -0
- package/SECURITY.md +5 -0
- package/package.json +58 -0
- package/src/index.js +9 -0
- package/src/lib/dao-cache.js +2024 -0
- package/src/lib/dao-endpoint.js +186 -0
- package/src/lib/tools/APIRequest.class.js +673 -0
- package/src/lib/tools/AWS.classes.js +250 -0
- package/src/lib/tools/CachedParametersSecrets.classes.js +492 -0
- package/src/lib/tools/ClientRequest.class.js +567 -0
- package/src/lib/tools/Connections.classes.js +466 -0
- package/src/lib/tools/DebugAndLog.class.js +416 -0
- package/src/lib/tools/ImmutableObject.class.js +71 -0
- package/src/lib/tools/RequestInfo.class.js +323 -0
- package/src/lib/tools/Response.class.js +547 -0
- package/src/lib/tools/ResponseDataModel.class.js +183 -0
- package/src/lib/tools/Timer.class.js +189 -0
- package/src/lib/tools/generic.response.html.js +88 -0
- package/src/lib/tools/generic.response.json.js +102 -0
- package/src/lib/tools/generic.response.rss.js +88 -0
- package/src/lib/tools/generic.response.text.js +86 -0
- package/src/lib/tools/generic.response.xml.js +82 -0
- package/src/lib/tools/index.js +318 -0
- package/src/lib/tools/utils.js +305 -0
- package/src/lib/tools/vars.js +34 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
const { sanitize } = require("./utils");
|
|
2
|
+
const util = require('util');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A simple Debug and Logging class.
|
|
6
|
+
*/
|
|
7
|
+
class DebugAndLog {
|
|
8
|
+
|
|
9
|
+
static #logLevel = -1;
|
|
10
|
+
static #expiration = -1;
|
|
11
|
+
|
|
12
|
+
static PROD = "PROD";
|
|
13
|
+
static TEST = "TEST";
|
|
14
|
+
static DEV = "DEV";
|
|
15
|
+
|
|
16
|
+
static ENVIRONMENTS = [DebugAndLog.PROD, DebugAndLog.TEST, DebugAndLog.DEV];
|
|
17
|
+
|
|
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
|
|
24
|
+
|
|
25
|
+
constructor() {
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Set the log level.
|
|
30
|
+
* @param {number} logLevel 0 - 5
|
|
31
|
+
* @param {*} expiration YYYY-MM-DD HH:MM:SS format. Only set to specified level until this date
|
|
32
|
+
*/
|
|
33
|
+
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();
|
|
47
|
+
} 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;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
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
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
*
|
|
87
|
+
* @returns {number} The current log level
|
|
88
|
+
*/
|
|
89
|
+
static getLogLevel() {
|
|
90
|
+
if ( this.#logLevel === -1 ) {
|
|
91
|
+
this.setLogLevel();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return this.#logLevel;
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check process.env for an environment variable named
|
|
100
|
+
* env, deployEnvironment, environment, or stage. If they
|
|
101
|
+
* are not set it will return DebugAndLog.PROD which
|
|
102
|
+
* is considered safe (most restrictive)
|
|
103
|
+
* Note: This is the application environment, not the NODE_ENV
|
|
104
|
+
* @returns {string} The current environment.
|
|
105
|
+
*/
|
|
106
|
+
static getEnv() {
|
|
107
|
+
var possibleVars = ["env", "deployEnvironment", "environment", "stage"]; // this is the application env, not the NODE_ENV
|
|
108
|
+
var env = 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
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return (DebugAndLog.ENVIRONMENTS.includes(env) ? env : DebugAndLog.PROD);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
*
|
|
128
|
+
* @returns {number} log level
|
|
129
|
+
*/
|
|
130
|
+
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
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return logLevel;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
*
|
|
157
|
+
* @returns {boolean}
|
|
158
|
+
*/
|
|
159
|
+
static isNotProduction() {
|
|
160
|
+
return ( !DebugAndLog.isProduction() );
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
*
|
|
165
|
+
* @returns {boolean}
|
|
166
|
+
*/
|
|
167
|
+
static isProduction() {
|
|
168
|
+
return ( DebugAndLog.getEnv() === DebugAndLog.PROD );
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
*
|
|
173
|
+
* @returns {boolean}
|
|
174
|
+
*/
|
|
175
|
+
static isDevelopment() {
|
|
176
|
+
return ( DebugAndLog.getEnv() === DebugAndLog.DEV );
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
*
|
|
181
|
+
* @returns {boolean}
|
|
182
|
+
*/
|
|
183
|
+
static isTest() {
|
|
184
|
+
return ( DebugAndLog.getEnv() === DebugAndLog.TEST );
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Write a log entry.
|
|
189
|
+
* The format used will be "[TAG] message"
|
|
190
|
+
* @param {string} tag This will appear first in the log in all caps between square brackets ex: [TAG]
|
|
191
|
+
* @param {string} message The message to be displayed. May also be a delimited log string
|
|
192
|
+
* @param {object|null} obj An object to include in the log entry
|
|
193
|
+
*/
|
|
194
|
+
static async writeLog(tag, message, obj = null) {
|
|
195
|
+
|
|
196
|
+
const logLevels = {
|
|
197
|
+
error: console.error,
|
|
198
|
+
warn: console.warn,
|
|
199
|
+
log: console.log,
|
|
200
|
+
info: console.info,
|
|
201
|
+
debug: console.debug
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const DEFAULT_LEVEL = 'info';
|
|
205
|
+
const FORMAT_WITH_OBJ = '[%s] %s | %s';
|
|
206
|
+
const FORMAT_WITHOUT_OBJ = '[%s] %s';
|
|
207
|
+
|
|
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
|
+
const baseLog = function(level, tag, message, obj = null) {
|
|
247
|
+
// Early return for invalid input
|
|
248
|
+
if (typeof level !== 'string') {
|
|
249
|
+
throw new TypeError('Log level must be a string');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Use logical OR for faster undefined/null checks
|
|
253
|
+
const safeTag = String(tag || '');
|
|
254
|
+
const safeMessage = String(message || '');
|
|
255
|
+
|
|
256
|
+
// Direct property lookup is faster than hasOwnProperty
|
|
257
|
+
const logFn = logLevels[level] || logLevels[DEFAULT_LEVEL];
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
// Single util.format call with conditional arguments
|
|
261
|
+
if (obj !== null) {
|
|
262
|
+
logFn(
|
|
263
|
+
util.format(
|
|
264
|
+
FORMAT_WITH_OBJ,
|
|
265
|
+
safeTag,
|
|
266
|
+
safeMessage,
|
|
267
|
+
util.inspect(sanitize(obj), { depth: null })
|
|
268
|
+
)
|
|
269
|
+
);
|
|
270
|
+
} else {
|
|
271
|
+
logFn(
|
|
272
|
+
util.format(
|
|
273
|
+
FORMAT_WITHOUT_OBJ,
|
|
274
|
+
safeTag,
|
|
275
|
+
safeMessage
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
} catch (error) {
|
|
280
|
+
console.error('Logging failed:', error);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
// Create individual logging functions using the base function
|
|
285
|
+
const error = (tag, message, obj) => baseLog('error', tag, message, obj);
|
|
286
|
+
const warn = (tag, message, obj) => baseLog('warn', tag, message, obj);
|
|
287
|
+
const log = (tag, message, obj) => baseLog('log', tag, message, obj);
|
|
288
|
+
const info = (tag, message, obj) => baseLog('info', tag, message, obj);
|
|
289
|
+
const debug = (tag, message, obj) => baseLog('debug', tag, message, obj);
|
|
290
|
+
|
|
291
|
+
let lvl = DebugAndLog.getLogLevel();
|
|
292
|
+
tag = tag.toUpperCase();
|
|
293
|
+
|
|
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
|
+
// }
|
|
302
|
+
|
|
303
|
+
switch (tag) {
|
|
304
|
+
case DebugAndLog.ERROR:
|
|
305
|
+
error(tag, message, obj);
|
|
306
|
+
break;
|
|
307
|
+
case DebugAndLog.WARN:
|
|
308
|
+
warn(tag, message, obj);
|
|
309
|
+
break;
|
|
310
|
+
case DebugAndLog.MSG:
|
|
311
|
+
if (lvl >= 1) { info(tag, message, obj); } // 1
|
|
312
|
+
break;
|
|
313
|
+
case DebugAndLog.DIAG:
|
|
314
|
+
if (lvl >= 3) { debug(tag, message, obj); } //3
|
|
315
|
+
break;
|
|
316
|
+
case DebugAndLog.DEBUG:
|
|
317
|
+
if (lvl >= 5) { debug(tag, message, obj); } //5
|
|
318
|
+
break;
|
|
319
|
+
default: // log
|
|
320
|
+
log(tag, message, obj);
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return true;
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Level 5 - Verbose Values and Calculations and Stack Traces
|
|
329
|
+
* @param {string} message
|
|
330
|
+
* @param {object} obj
|
|
331
|
+
*/
|
|
332
|
+
static async debug(message, obj = null) {
|
|
333
|
+
return DebugAndLog.writeLog(DebugAndLog.DEBUG, message, obj);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Level 3 - Verbose timing and counts
|
|
338
|
+
* @param {string} message
|
|
339
|
+
* @param {object} obj
|
|
340
|
+
*/
|
|
341
|
+
static async diag(message, obj = null) {
|
|
342
|
+
return DebugAndLog.writeLog(DebugAndLog.DIAG, message, obj);
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Level 1 - Short messages and status
|
|
347
|
+
* @param {string} message
|
|
348
|
+
* @param {object} obj
|
|
349
|
+
*/
|
|
350
|
+
static async msg(message, obj = null) {
|
|
351
|
+
return DebugAndLog.writeLog(DebugAndLog.MSG, message, obj);
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Level 1 - Short messages and status
|
|
356
|
+
* (same as DebugAndLog.msg() )
|
|
357
|
+
* @param {string} message
|
|
358
|
+
* @param {object} obj
|
|
359
|
+
*/
|
|
360
|
+
static async message(message, obj = null) {
|
|
361
|
+
return DebugAndLog.msg(message, obj);
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Level 0 - Production worthy log entries that are not errors or warnings
|
|
366
|
+
* These should be formatted in a consistent manner and typically only
|
|
367
|
+
* one entry produced per invocation. (Usually produced at the end of a
|
|
368
|
+
* script's execution)
|
|
369
|
+
* @param {string} message The message, either a text string or fields separated by | or another character you can use to parse your logs
|
|
370
|
+
* @param {string} tag Optional. The tag that appears at the start of the log. Default is LOG. In logs it will appear at the start within square brackets '[LOG] message' You can use this to filter when parsing log reports
|
|
371
|
+
* @param {object} obj
|
|
372
|
+
*/
|
|
373
|
+
static async log(message, tag = DebugAndLog.LOG, obj = null) {
|
|
374
|
+
return DebugAndLog.writeLog(tag, message, obj);
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Level 0 - Warnings
|
|
379
|
+
* Errors are handled and execution continues.
|
|
380
|
+
* ClientRequest validation should be done first, and if we received an invalid
|
|
381
|
+
* request, then a warning, not an error, should be logged even though an
|
|
382
|
+
* error is returned to the client (error is on client side, not here,
|
|
383
|
+
* but we want to keep track of client errors).
|
|
384
|
+
* Requests should be validated first before all other processing.
|
|
385
|
+
* @param {string} message
|
|
386
|
+
* @param {object} obj
|
|
387
|
+
*/
|
|
388
|
+
static async warn(message, obj = null) {
|
|
389
|
+
DebugAndLog.writeLog(DebugAndLog.WARN, message, obj);
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Level 0 - Warnings
|
|
394
|
+
* (same as DebugAndLog.warn() )
|
|
395
|
+
* @param {string} message
|
|
396
|
+
* @param {object} obj
|
|
397
|
+
*/
|
|
398
|
+
static async warning(message, obj = null) {
|
|
399
|
+
DebugAndLog.warn(message, obj);
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Level 0 - Errors
|
|
404
|
+
* Errors cannot be handled in a way that will allow continued execution.
|
|
405
|
+
* An error will be passed back to the client. If a client sent a bad
|
|
406
|
+
* request, send a warning instead.
|
|
407
|
+
* @param {string} message
|
|
408
|
+
* @param {object} obj
|
|
409
|
+
*/
|
|
410
|
+
static async error(message, obj = null) {
|
|
411
|
+
DebugAndLog.writeLog(DebugAndLog.ERROR, message, obj);
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
module.exports = DebugAndLog;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Create an object that is able to return a copy and not
|
|
4
|
+
* a reference to its properties.
|
|
5
|
+
*/
|
|
6
|
+
class ImmutableObject {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param {object} obj The object you want to store as immutable. You can use keys for sub-objects to retreive those inner objects later
|
|
11
|
+
* @param {boolean} finalize Should we lock the object right away?
|
|
12
|
+
*/
|
|
13
|
+
constructor(obj = null, finalize = false) {
|
|
14
|
+
this.obj = obj;
|
|
15
|
+
this.locked = false;
|
|
16
|
+
if ( finalize ) {
|
|
17
|
+
this.finalize();
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Locks the object so it can't be changed.
|
|
23
|
+
*/
|
|
24
|
+
lock() {
|
|
25
|
+
if ( !this.locked ) {
|
|
26
|
+
/* We'll stringify the object to break all references,
|
|
27
|
+
then change it back to an object */
|
|
28
|
+
this.obj = JSON.parse(JSON.stringify(this.obj));
|
|
29
|
+
this.locked = true;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Finalizes the object by immediately locking it
|
|
35
|
+
* @param {object|null} obj // The object you want to store as immutable. You can use keys for sub-objects to retreive those inner objects later
|
|
36
|
+
*/
|
|
37
|
+
finalize(obj = null) {
|
|
38
|
+
if ( !this.locked ) {
|
|
39
|
+
if ( obj !== null ) { this.obj = obj; }
|
|
40
|
+
this.lock();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
*
|
|
46
|
+
* @returns A copy of the object, not a reference
|
|
47
|
+
*/
|
|
48
|
+
toObject() {
|
|
49
|
+
return this.get();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get a copy of the value, not a reference, via an object's key
|
|
54
|
+
* @param {string} key Key of the value you wish to return
|
|
55
|
+
* @returns {*} The value of the supplied key
|
|
56
|
+
*/
|
|
57
|
+
get(key = "") {
|
|
58
|
+
/* we need to break the reference to the orig obj.
|
|
59
|
+
tried many methods but parse seems to be only one that works
|
|
60
|
+
https://itnext.io/can-json-parse-be-performance-improvement-ba1069951839
|
|
61
|
+
https://medium.com/coding-at-dawn/how-to-use-the-spread-operator-in-javascript-b9e4a8b06fab
|
|
62
|
+
*/
|
|
63
|
+
//return {...this.connection[key]}; // doesn't make a deep copy
|
|
64
|
+
//return Object.assign({}, this.connection[key]);
|
|
65
|
+
|
|
66
|
+
return JSON.parse(JSON.stringify( (key === "" || !(key in this.obj)) ? this.obj : this.obj[key] ));
|
|
67
|
+
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
module.exports = ImmutableObject;
|