mastercontroller 1.3.13 → 1.3.15

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/MasterTemp.js CHANGED
@@ -1,8 +1,34 @@
1
- // version 0.0.3
1
+ // version 0.1.0 - FAANG-level refactor with bug fixes and complete feature set
2
2
 
3
+ const { logger } = require('./error/MasterErrorLogger');
4
+
5
+ // Configuration Constants
6
+ const TEMP_CONFIG = {
7
+ MAX_KEY_LENGTH: 255,
8
+ MAX_VALUE_SIZE: 10 * 1024 * 1024, // 10MB
9
+ MAX_KEYS: 10000
10
+ };
11
+
12
+ /**
13
+ * MasterTemp - Temporary data storage utility
14
+ *
15
+ * Provides a simple key-value store for temporary data within a request lifecycle.
16
+ * Thread-safe when used per-request (each request gets its own instance).
17
+ *
18
+ * Features:
19
+ * - Type-safe storage with validation
20
+ * - Reserved key protection
21
+ * - Prototype pollution prevention
22
+ * - Size limits for DoS protection
23
+ * - Complete CRUD operations
24
+ * - Utility methods (keys, size, isEmpty)
25
+ *
26
+ * @class MasterTemp
27
+ */
3
28
  class MasterTemp{
4
29
 
5
30
  temp = {};
31
+ _reservedKeys = new Set(['temp', '_master', '__masterCache', '_reservedKeys', 'add', 'get', 'has', 'clear', 'clearAll', 'keys', 'size', 'isEmpty', 'toJSON']);
6
32
 
7
33
  // Lazy-load master to avoid circular dependency (Google-style lazy initialization)
8
34
  get _master() {
@@ -12,26 +38,282 @@ class MasterTemp{
12
38
  return this.__masterCache;
13
39
  }
14
40
 
41
+ /**
42
+ * Validate key name for security and correctness
43
+ *
44
+ * @private
45
+ * @param {string} name - Key name to validate
46
+ * @throws {TypeError} If name is not a string
47
+ * @throws {Error} If name is empty, reserved, too long, or contains dangerous characters
48
+ */
49
+ _validateKey(name) {
50
+ if (typeof name !== 'string') {
51
+ throw new TypeError('Key name must be a string');
52
+ }
53
+
54
+ if (!name || name.trim() === '') {
55
+ throw new Error('Key name cannot be empty');
56
+ }
57
+
58
+ if (this._reservedKeys.has(name)) {
59
+ throw new Error(`Key name '${name}' is reserved and cannot be used`);
60
+ }
61
+
62
+ if (name.length > TEMP_CONFIG.MAX_KEY_LENGTH) {
63
+ throw new Error(`Key name exceeds maximum length (${TEMP_CONFIG.MAX_KEY_LENGTH} characters)`);
64
+ }
65
+
66
+ // Prevent prototype pollution
67
+ if (name === '__proto__' || name === 'constructor' || name === 'prototype') {
68
+ throw new Error(`Key name '${name}' is forbidden (prototype pollution protection)`);
69
+ }
70
+
71
+ // Check for dangerous characters
72
+ if (/[<>{}[\]\\^`|]/.test(name)) {
73
+ throw new Error(`Key name contains invalid characters: ${name}`);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Validate value size for DoS protection
79
+ *
80
+ * @private
81
+ * @param {*} data - Value to validate
82
+ * @throws {Error} If value exceeds maximum size
83
+ */
84
+ _validateValue(data) {
85
+ try {
86
+ const jsonStr = JSON.stringify(data);
87
+ if (jsonStr.length > TEMP_CONFIG.MAX_VALUE_SIZE) {
88
+ throw new Error(`Value exceeds maximum size (${TEMP_CONFIG.MAX_VALUE_SIZE} bytes)`);
89
+ }
90
+ } catch (e) {
91
+ if (e.message.includes('circular')) {
92
+ throw new Error('Value contains circular references and cannot be stored');
93
+ }
94
+ throw e;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Add or update temporary data
100
+ *
101
+ * @param {string} name - Key name for the data
102
+ * @param {*} data - Data to store (any JSON-serializable value)
103
+ * @returns {boolean} True if successful, false otherwise
104
+ * @throws {TypeError} If name is not a string
105
+ * @throws {Error} If name is reserved, invalid, or value is too large
106
+ *
107
+ * @example
108
+ * temp.add('userId', 123);
109
+ * temp.add('userData', { name: 'John', email: 'john@example.com' });
110
+ * temp.add('items', [1, 2, 3]);
111
+ */
15
112
  add(name, data){
113
+ try {
114
+ this._validateKey(name);
115
+ this._validateValue(data);
16
116
 
17
- if(name !== "add" && name !== "clear"){
18
- this[name] = data;
117
+ // Check max keys limit
118
+ if (!this.has(name) && this.size() >= TEMP_CONFIG.MAX_KEYS) {
119
+ throw new Error(`Maximum number of keys (${TEMP_CONFIG.MAX_KEYS}) exceeded`);
120
+ }
121
+
122
+ // CRITICAL FIX: Store in this.temp[name] not this[name]
123
+ this.temp[name] = data;
124
+
125
+ logger.debug({
126
+ code: 'MC_TEMP_ADD',
127
+ message: 'Temporary data added',
128
+ key: name
129
+ });
130
+
131
+ return true;
132
+
133
+ } catch (error) {
134
+ logger.error({
135
+ code: 'MC_TEMP_ADD_ERROR',
136
+ message: 'Failed to add temporary data',
137
+ key: name,
138
+ error: error.message
139
+ });
140
+ throw error;
19
141
  }
20
- else{
21
- this._master.error.log("cannot use tempdata name add or clear", "warn");
142
+ }
143
+
144
+ /**
145
+ * Get temporary data by key
146
+ *
147
+ * @param {string} name - Key name
148
+ * @param {*} [defaultValue] - Default value if key doesn't exist
149
+ * @returns {*} Stored value or defaultValue if not found
150
+ *
151
+ * @example
152
+ * const userId = temp.get('userId');
153
+ * const theme = temp.get('theme', 'dark'); // Returns 'dark' if not set
154
+ */
155
+ get(name, defaultValue = undefined) {
156
+ try {
157
+ this._validateKey(name);
158
+ return this.has(name) ? this.temp[name] : defaultValue;
159
+ } catch (error) {
160
+ logger.warn({
161
+ code: 'MC_TEMP_GET_ERROR',
162
+ message: 'Failed to get temporary data',
163
+ key: name,
164
+ error: error.message
165
+ });
166
+ return defaultValue;
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Check if key exists in temporary storage
172
+ *
173
+ * @param {string} name - Key name to check
174
+ * @returns {boolean} True if key exists, false otherwise
175
+ *
176
+ * @example
177
+ * if (temp.has('userId')) {
178
+ * console.log('User ID is set');
179
+ * }
180
+ */
181
+ has(name) {
182
+ try {
183
+ this._validateKey(name);
184
+ return Object.prototype.hasOwnProperty.call(this.temp, name);
185
+ } catch (error) {
186
+ return false;
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Delete a single key from temporary storage
192
+ *
193
+ * @param {string} name - Key name to delete
194
+ * @returns {boolean} True if key was deleted, false if it didn't exist
195
+ *
196
+ * @example
197
+ * temp.clear('userId'); // Remove userId from storage
198
+ */
199
+ clear(name) {
200
+ try {
201
+ this._validateKey(name);
202
+
203
+ if (this.has(name)) {
204
+ delete this.temp[name];
205
+
206
+ logger.debug({
207
+ code: 'MC_TEMP_CLEAR',
208
+ message: 'Temporary data cleared',
209
+ key: name
210
+ });
211
+
212
+ return true;
213
+ }
214
+
215
+ return false;
216
+
217
+ } catch (error) {
218
+ logger.error({
219
+ code: 'MC_TEMP_CLEAR_ERROR',
220
+ message: 'Failed to clear temporary data',
221
+ key: name,
222
+ error: error.message
223
+ });
224
+ return false;
22
225
  }
23
226
  }
24
227
 
228
+ /**
229
+ * Clear all temporary data
230
+ *
231
+ * @returns {number} Number of keys cleared
232
+ *
233
+ * @example
234
+ * const cleared = temp.clearAll();
235
+ * console.log(`Cleared ${cleared} keys`);
236
+ */
25
237
  clearAll(){
26
- for (var key in this) {
27
- if (this.temp.hasOwnProperty(key)) {
28
- if(this.temp[key] !== "add" && this.temp[key] !== "clear"){
238
+ try {
239
+ const count = this.size();
240
+
241
+ // CRITICAL FIX: Iterate over this.temp, not this
242
+ for (const key in this.temp) {
243
+ if (Object.prototype.hasOwnProperty.call(this.temp, key)) {
29
244
  delete this.temp[key];
30
245
  }
31
246
  }
32
- };
247
+
248
+ logger.debug({
249
+ code: 'MC_TEMP_CLEAR_ALL',
250
+ message: 'All temporary data cleared',
251
+ count
252
+ });
253
+
254
+ return count;
255
+
256
+ } catch (error) {
257
+ logger.error({
258
+ code: 'MC_TEMP_CLEAR_ALL_ERROR',
259
+ message: 'Failed to clear all temporary data',
260
+ error: error.message
261
+ });
262
+ return 0;
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Get all keys in temporary storage
268
+ *
269
+ * @returns {string[]} Array of key names
270
+ *
271
+ * @example
272
+ * const keys = temp.keys();
273
+ * console.log('Stored keys:', keys); // ['userId', 'theme', 'items']
274
+ */
275
+ keys() {
276
+ return Object.keys(this.temp);
277
+ }
278
+
279
+ /**
280
+ * Get number of keys in temporary storage
281
+ *
282
+ * @returns {number} Number of stored keys
283
+ *
284
+ * @example
285
+ * console.log(`Storage contains ${temp.size()} items`);
286
+ */
287
+ size() {
288
+ return Object.keys(this.temp).length;
33
289
  }
34
290
 
291
+ /**
292
+ * Check if temporary storage is empty
293
+ *
294
+ * @returns {boolean} True if no keys stored, false otherwise
295
+ *
296
+ * @example
297
+ * if (temp.isEmpty()) {
298
+ * console.log('No temporary data stored');
299
+ * }
300
+ */
301
+ isEmpty() {
302
+ return this.size() === 0;
303
+ }
304
+
305
+ /**
306
+ * Convert temporary storage to plain JSON object
307
+ *
308
+ * @returns {Object} Plain object containing all key-value pairs
309
+ *
310
+ * @example
311
+ * const snapshot = temp.toJSON();
312
+ * console.log(JSON.stringify(snapshot));
313
+ */
314
+ toJSON() {
315
+ return { ...this.temp };
316
+ }
35
317
  }
36
318
 
37
- module.exports = { MasterTemp };
319
+ module.exports = { MasterTemp };