@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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. 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 8388608 (8 MB).
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
@@ -68,5 +68,5 @@
68
68
  "engines": {
69
69
  "node": "^22.13.0 || >=24.0.0"
70
70
  },
71
- "version": "3.0.0"
71
+ "version": "3.0.1"
72
72
  }
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 (8 MB).
20
+ * Default maximum allowed size for a value in bytes (1 MB).
21
21
  * @type {number}
22
22
  */
23
- const DEFAULT_VALUE_SIZE = 8 * 1024 * 1024;
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
- // Approximate.
208
- return input.toString().length * MAX_BYTES_PER_CHAR <= max;
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
- if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) {
221
- return input.byteLength <= max;
222
- }
223
- if (input instanceof Date) {
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(targetForJson);
291
+ const serialized = JSON.stringify(input);
241
292
  if (serialized === undefined) {
242
293
  return false;
243
294
  }