@asamuzakjp/generational-cache 3.0.0 → 3.0.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/README.md +1 -1
- package/package.json +1 -1
- package/src/index.js +71 -20
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ Creates a new cache instance with a maximum capacity of `max` entries.
|
|
|
55
55
|
* **cacheFunction** *(boolean)*: Caches functions if `true`. Defaults to `false`.
|
|
56
56
|
* **cacheSymbol** *(boolean)*: Caches symbols if `true`. Defaults to `false`.
|
|
57
57
|
* **maxKeySize** *(number)*: Maximum allowed size for a `key` in bytes. Defaults to 8192 (8 KB).
|
|
58
|
-
* **maxValueSize** *(number)*: Maximum allowed size for a `value` in bytes. Defaults to
|
|
58
|
+
* **maxValueSize** *(number)*: Maximum allowed size for a `value` in bytes. Defaults to 1048576 (1 MB).
|
|
59
59
|
* **strictValidate** *(boolean)*: Strictly validate object payload structures and sizes if `true`. Defaults to `true`.
|
|
60
60
|
|
|
61
61
|
### Properties
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -17,10 +17,10 @@ const MAX_BYTES_PER_CHAR = 4;
|
|
|
17
17
|
const DEFAULT_KEY_SIZE = 8 * 1024;
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Default maximum allowed size for a value in bytes (
|
|
20
|
+
* Default maximum allowed size for a value in bytes (1 MB).
|
|
21
21
|
* @type {number}
|
|
22
22
|
*/
|
|
23
|
-
const DEFAULT_VALUE_SIZE =
|
|
23
|
+
const DEFAULT_VALUE_SIZE = 1024 * 1024;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Flag indicating whether the current runtime environment is Node.js.
|
|
@@ -182,6 +182,60 @@ export class GenerationalCache {
|
|
|
182
182
|
return false;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Performs validation based on the specific type of built-in object.
|
|
187
|
+
* @param {string} typeStr - The type string of the object.
|
|
188
|
+
* @param {object} input - The object to validate.
|
|
189
|
+
* @param {number} max - The maximum allowable size in bytes.
|
|
190
|
+
* @returns {{ result?: boolean, input?: unknown }} The validation result, or the input.
|
|
191
|
+
*/
|
|
192
|
+
#validateBuiltInObject(typeStr, input, max) {
|
|
193
|
+
switch (typeStr) {
|
|
194
|
+
case 'Array': {
|
|
195
|
+
if (input.length > max - 2) {
|
|
196
|
+
return { result: false };
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
case 'Map':
|
|
201
|
+
case 'Set': {
|
|
202
|
+
if (input.size > max - 2) {
|
|
203
|
+
return { result: false };
|
|
204
|
+
}
|
|
205
|
+
input = [...input];
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case 'Date': {
|
|
209
|
+
if (Number.isNaN(input.getTime())) {
|
|
210
|
+
return { result: false };
|
|
211
|
+
}
|
|
212
|
+
return { result: this.#validateString(input.toISOString(), max - 2) };
|
|
213
|
+
}
|
|
214
|
+
case 'RegExp': {
|
|
215
|
+
return { result: this.#validateString(input.toString(), max) };
|
|
216
|
+
}
|
|
217
|
+
case 'ArrayBuffer':
|
|
218
|
+
case 'DataView':
|
|
219
|
+
case 'Int8Array':
|
|
220
|
+
case 'Uint8Array':
|
|
221
|
+
case 'Uint8ClampedArray':
|
|
222
|
+
case 'Int16Array':
|
|
223
|
+
case 'Uint16Array':
|
|
224
|
+
case 'Int32Array':
|
|
225
|
+
case 'Uint32Array':
|
|
226
|
+
case 'Float32Array':
|
|
227
|
+
case 'Float64Array':
|
|
228
|
+
case 'BigInt64Array':
|
|
229
|
+
case 'BigUint64Array': {
|
|
230
|
+
return { result: input.byteLength <= max };
|
|
231
|
+
}
|
|
232
|
+
default: {
|
|
233
|
+
// fall through
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return { input };
|
|
237
|
+
}
|
|
238
|
+
|
|
185
239
|
/**
|
|
186
240
|
* Validates if the given input fits within the specified maximum byte size.
|
|
187
241
|
* @param {K|V} input - The input data to validate (usually a string).
|
|
@@ -204,8 +258,15 @@ export class GenerationalCache {
|
|
|
204
258
|
return max >= 8;
|
|
205
259
|
}
|
|
206
260
|
case 'bigint': {
|
|
207
|
-
//
|
|
208
|
-
|
|
261
|
+
// Normalize negative bigint for bit-length calculation.
|
|
262
|
+
const signNormalized = input < 0n ? ~input : input;
|
|
263
|
+
if (signNormalized === 0n) {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
const hex = signNormalized.toString(16);
|
|
267
|
+
const firstCharBits = parseInt(hex[0], 16).toString(2).length;
|
|
268
|
+
const bitLength = (hex.length - 1) * 4 + firstCharBits + 1;
|
|
269
|
+
return bitLength <= max * 8;
|
|
209
270
|
}
|
|
210
271
|
case 'function': {
|
|
211
272
|
return this.#cacheFunction;
|
|
@@ -217,27 +278,17 @@ export class GenerationalCache {
|
|
|
217
278
|
if (!this.#strictValidate) {
|
|
218
279
|
return true;
|
|
219
280
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return this.#validateString(input.toISOString(), max);
|
|
225
|
-
}
|
|
226
|
-
if (input instanceof RegExp) {
|
|
227
|
-
return input.toString().length * MAX_BYTES_PER_CHAR <= max;
|
|
281
|
+
const typeStr = Object.prototype.toString.call(input).slice(8, -1);
|
|
282
|
+
const typeCheck = this.#validateBuiltInObject(typeStr, input, max);
|
|
283
|
+
if (typeCheck.result !== undefined) {
|
|
284
|
+
return typeCheck.result;
|
|
228
285
|
}
|
|
286
|
+
input = typeCheck.input;
|
|
229
287
|
if (this.#hasForbiddenTypes(input)) {
|
|
230
288
|
return false;
|
|
231
289
|
}
|
|
232
|
-
let targetForJson = input;
|
|
233
|
-
if (input instanceof Map || input instanceof Set) {
|
|
234
|
-
if (!input.size) {
|
|
235
|
-
return max >= 2;
|
|
236
|
-
}
|
|
237
|
-
targetForJson = [...input];
|
|
238
|
-
}
|
|
239
290
|
try {
|
|
240
|
-
const serialized = JSON.stringify(
|
|
291
|
+
const serialized = JSON.stringify(input);
|
|
241
292
|
if (serialized === undefined) {
|
|
242
293
|
return false;
|
|
243
294
|
}
|