fast-map-cache 1.0.1 → 1.1.0

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 CHANGED
@@ -78,11 +78,13 @@ setTimeout(() => {
78
78
  }, 6000)
79
79
  ```
80
80
 
81
+ > Note: TTL is based on the timestamp of the last `set()` operation. A `get()` does not refresh TTL (i.e., it is not access-renewal).
82
+
81
83
  ### ❗ Important Note for Node.js Users
82
84
 
83
- When using `FastCacheWithTTL` with the `autoCleanup: true` option in a Node.js environment, a `setInterval` is used to periodically clean up expired items. This timer will prevent the Node.js process from exiting gracefully on its own.
85
+ When using `FastCacheWithTTL` with the `autoCleanup: true` option in Node.js, an internal `setInterval` is used for periodic cleanup. The timer is created with `unref()` when available, so it will not keep the process alive on its own.
84
86
 
85
- **You must manually call the `destroy()` method before your application exits to clear the timer.**
87
+ **It is still recommended to call `destroy()` before your application exits** to proactively clear resources and avoid potential hangs in long-running tasks or test environments.
86
88
 
87
89
  ```typescript
88
90
  const cache = createCacheWithTTL({ maxSize: 100, autoCleanup: true, ttl: 60000 })
package/README_zh-CN.md CHANGED
@@ -80,11 +80,13 @@ setTimeout(() => {
80
80
  }, 6000)
81
81
  ```
82
82
 
83
+ > 提示:TTL 以最近一次 `set()` 的时间为基准;`get()` 不会刷新 TTL(非“访问续期”)。
84
+
83
85
  ### ❗ Node.js 用户重要提示
84
86
 
85
- 在 Node.js 环境下使用 `FastCacheWithTTL` 并开启 `autoCleanup: true` 选项时,系统会使用 `setInterval` 定时清理过期缓存。这个定时器会阻止 Node.js 进程正常退出。
87
+ 在 Node.js 下使用 `autoCleanup: true` 时,内部会使用 `setInterval` 做周期清理;当环境支持时定时器会调用 `unref()`,因此不会单独阻止进程退出。
86
88
 
87
- **您必须在程序退出前手动调用 `destroy()` 方法来清除该定时器。**
89
+ **仍然建议在应用退出前调用 `destroy()` 主动释放资源**,可避免长生命周期任务或测试环境中的潜在挂起。
88
90
 
89
91
  ```typescript
90
92
  const cache = createCacheWithTTL({ maxSize: 100, autoCleanup: true, ttl: 60000 })
package/dist/main.d.mts CHANGED
@@ -66,6 +66,11 @@ declare class FastCache<K extends CacheKey, V> implements IFastCache<K, V> {
66
66
  protected addToHead(node: CacheNode<K, V>): void;
67
67
  protected removeNode(node: CacheNode<K, V>): void;
68
68
  protected moveToHead(node: CacheNode<K, V>): void;
69
+ /**
70
+ * 统一删除入口:删除 Map 记录并从 LRU 链表移除节点。
71
+ * 子类(如 TTL 版本)可覆写该方法以保证多链表同步删除。
72
+ */
73
+ protected deleteNode(node: CacheNode<K, V>): void;
69
74
  protected removeTail(): void;
70
75
  }
71
76
  //#endregion
@@ -103,6 +108,10 @@ declare class FastCacheWithTTL<K extends CacheKey, V> extends FastCache<K, V> {
103
108
  * 如果开启了 `autoCleanup`,你应当在应用关闭前调用此方法。
104
109
  */
105
110
  destroy(): void;
111
+ /**
112
+ * 覆写统一删除入口:先维护 TTL 链表,再调用父类删除 LRU/Map。
113
+ */
114
+ protected deleteNode(node: CacheNode<K, V>): void;
106
115
  private isExpired;
107
116
  private _addToTimeListTail;
108
117
  private _removeFromTimeList;
@@ -119,4 +128,4 @@ declare const CachePresets: {
119
128
  readonly tempCache: <T>(maxSize?: number, ttl?: number) => FastCacheWithTTL<string, T>;
120
129
  };
121
130
  //#endregion
122
- export { CacheKey, CacheNode, CacheOptions, CachePresets, CacheStats, FastCache, FastCacheWithTTL, IFastCache, createCache, createCacheWithTTL };
131
+ export { type CacheKey, type CacheNode, type CacheOptions, CachePresets, type CacheStats, FastCache, FastCacheWithTTL, type IFastCache, createCache, createCacheWithTTL };
package/dist/main.d.ts CHANGED
@@ -66,6 +66,11 @@ declare class FastCache<K extends CacheKey, V> implements IFastCache<K, V> {
66
66
  protected addToHead(node: CacheNode<K, V>): void;
67
67
  protected removeNode(node: CacheNode<K, V>): void;
68
68
  protected moveToHead(node: CacheNode<K, V>): void;
69
+ /**
70
+ * 统一删除入口:删除 Map 记录并从 LRU 链表移除节点。
71
+ * 子类(如 TTL 版本)可覆写该方法以保证多链表同步删除。
72
+ */
73
+ protected deleteNode(node: CacheNode<K, V>): void;
69
74
  protected removeTail(): void;
70
75
  }
71
76
  //#endregion
@@ -103,6 +108,10 @@ declare class FastCacheWithTTL<K extends CacheKey, V> extends FastCache<K, V> {
103
108
  * 如果开启了 `autoCleanup`,你应当在应用关闭前调用此方法。
104
109
  */
105
110
  destroy(): void;
111
+ /**
112
+ * 覆写统一删除入口:先维护 TTL 链表,再调用父类删除 LRU/Map。
113
+ */
114
+ protected deleteNode(node: CacheNode<K, V>): void;
106
115
  private isExpired;
107
116
  private _addToTimeListTail;
108
117
  private _removeFromTimeList;
@@ -119,4 +128,4 @@ declare const CachePresets: {
119
128
  readonly tempCache: <T>(maxSize?: number, ttl?: number) => FastCacheWithTTL<string, T>;
120
129
  };
121
130
  //#endregion
122
- export { CacheKey, CacheNode, CacheOptions, CachePresets, CacheStats, FastCache, FastCacheWithTTL, IFastCache, createCache, createCacheWithTTL };
131
+ export { type CacheKey, type CacheNode, type CacheOptions, CachePresets, type CacheStats, FastCache, FastCacheWithTTL, type IFastCache, createCache, createCacheWithTTL };
package/dist/main.js CHANGED
@@ -25,8 +25,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  //#endregion
27
27
 
28
- //#region node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/typeof.js
29
- var require_typeof = __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/typeof.js"(exports, module) {
28
+ //#region node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/typeof.js
29
+ var require_typeof = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/typeof.js": ((exports, module) => {
30
30
  function _typeof$2(o) {
31
31
  "@babel/helpers - typeof";
32
32
  return module.exports = _typeof$2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o$1) {
@@ -36,11 +36,11 @@ var require_typeof = __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.72.
36
36
  }, module.exports.__esModule = true, module.exports["default"] = module.exports, _typeof$2(o);
37
37
  }
38
38
  module.exports = _typeof$2, module.exports.__esModule = true, module.exports["default"] = module.exports;
39
- } });
39
+ }) });
40
40
 
41
41
  //#endregion
42
- //#region node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js
43
- var require_toPrimitive = __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js"(exports, module) {
42
+ //#region node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js
43
+ var require_toPrimitive = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js": ((exports, module) => {
44
44
  var _typeof$1 = require_typeof()["default"];
45
45
  function toPrimitive$1(t, r) {
46
46
  if ("object" != _typeof$1(t) || !t) return t;
@@ -53,11 +53,11 @@ var require_toPrimitive = __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@
53
53
  return ("string" === r ? String : Number)(t);
54
54
  }
55
55
  module.exports = toPrimitive$1, module.exports.__esModule = true, module.exports["default"] = module.exports;
56
- } });
56
+ }) });
57
57
 
58
58
  //#endregion
59
- //#region node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js
60
- var require_toPropertyKey = __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js"(exports, module) {
59
+ //#region node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js
60
+ var require_toPropertyKey = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js": ((exports, module) => {
61
61
  var _typeof = require_typeof()["default"];
62
62
  var toPrimitive = require_toPrimitive();
63
63
  function toPropertyKey$1(t) {
@@ -65,11 +65,11 @@ var require_toPropertyKey = __commonJS({ "node_modules/.pnpm/@oxc-project+runtim
65
65
  return "symbol" == _typeof(i) ? i : i + "";
66
66
  }
67
67
  module.exports = toPropertyKey$1, module.exports.__esModule = true, module.exports["default"] = module.exports;
68
- } });
68
+ }) });
69
69
 
70
70
  //#endregion
71
- //#region node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js
72
- var require_defineProperty = __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js"(exports, module) {
71
+ //#region node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js
72
+ var require_defineProperty = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js": ((exports, module) => {
73
73
  var toPropertyKey = require_toPropertyKey();
74
74
  function _defineProperty$2(e, r, t) {
75
75
  return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
@@ -80,11 +80,11 @@ var require_defineProperty = __commonJS({ "node_modules/.pnpm/@oxc-project+runti
80
80
  }) : e[r] = t, e;
81
81
  }
82
82
  module.exports = _defineProperty$2, module.exports.__esModule = true, module.exports["default"] = module.exports;
83
- } });
83
+ }) });
84
84
 
85
85
  //#endregion
86
86
  //#region src/fast-cache.ts
87
- var import_defineProperty$1 = __toESM(require_defineProperty());
87
+ var import_defineProperty$1 = /* @__PURE__ */ __toESM(require_defineProperty());
88
88
  /**
89
89
  * 高性能 LRU 缓存实现
90
90
  * 使用 Map + 双向链表实现 O(1) 复杂度的所有操作
@@ -135,8 +135,7 @@ var FastCache = class {
135
135
  delete(key) {
136
136
  const node = this.cache.get(key);
137
137
  if (node === void 0) return false;
138
- this.cache.delete(key);
139
- this.removeNode(node);
138
+ this.deleteNode(node);
140
139
  return true;
141
140
  }
142
141
  clear() {
@@ -190,18 +189,23 @@ var FastCache = class {
190
189
  this.removeNode(node);
191
190
  this.addToHead(node);
192
191
  }
192
+ /**
193
+ * 统一删除入口:删除 Map 记录并从 LRU 链表移除节点。
194
+ * 子类(如 TTL 版本)可覆写该方法以保证多链表同步删除。
195
+ */
196
+ deleteNode(node) {
197
+ this.cache.delete(node.key);
198
+ this.removeNode(node);
199
+ }
193
200
  removeTail() {
194
201
  const lastNode = this.tail.prev;
195
- if (lastNode && lastNode !== this.head) {
196
- this.cache.delete(lastNode.key);
197
- this.removeNode(lastNode);
198
- }
202
+ if (lastNode && lastNode !== this.head) this.deleteNode(lastNode);
199
203
  }
200
204
  };
201
205
 
202
206
  //#endregion
203
207
  //#region src/fast-cache-ttl.ts
204
- var import_defineProperty = __toESM(require_defineProperty());
208
+ var import_defineProperty = /* @__PURE__ */ __toESM(require_defineProperty());
205
209
  /**
206
210
  * 带 TTL (Time To Live) 支持的高性能缓存实现。
207
211
  * 继承自 FastCache,并增加了一个按时间排序的独立链表,
@@ -229,7 +233,10 @@ var FastCacheWithTTL = class extends FastCache {
229
233
  this.timeTail.timePrev = this.timeHead;
230
234
  if (this.autoCleanup && this.ttl > 0) {
231
235
  const cleanupInterval = options.cleanupInterval ?? this.ttl;
236
+ if (cleanupInterval <= 0) throw new Error("cleanupInterval must be positive");
232
237
  this.cleanupTimer = setInterval(() => this.cleanup(), cleanupInterval);
238
+ const anyTimer = this.cleanupTimer;
239
+ if (typeof anyTimer.unref === "function") anyTimer.unref();
233
240
  }
234
241
  }
235
242
  get(key) {
@@ -324,6 +331,13 @@ var FastCacheWithTTL = class extends FastCache {
324
331
  this.cleanupTimer = void 0;
325
332
  }
326
333
  }
334
+ /**
335
+ * 覆写统一删除入口:先维护 TTL 链表,再调用父类删除 LRU/Map。
336
+ */
337
+ deleteNode(node) {
338
+ this._removeFromTimeList(node);
339
+ super.deleteNode(node);
340
+ }
327
341
  isExpired(node, now) {
328
342
  if (this.ttl === 0 || node.timestamp === void 0) return false;
329
343
  return (now ?? Date.now()) - node.timestamp > this.ttl;
@@ -356,12 +370,12 @@ function createCacheWithTTL(options) {
356
370
  const CachePresets = {
357
371
  apiCache: (maxSize = 1e3) => createCache(maxSize),
358
372
  computeCache: (maxSize = 500) => createCache(maxSize),
359
- sessionCache: (maxSize = 100, ttl = 30 * 60 * 1e3) => createCacheWithTTL({
373
+ sessionCache: (maxSize = 100, ttl = 1800 * 1e3) => createCacheWithTTL({
360
374
  maxSize,
361
375
  ttl,
362
376
  autoCleanup: true
363
377
  }),
364
- tempCache: (maxSize = 200, ttl = 5 * 60 * 1e3) => createCacheWithTTL({
378
+ tempCache: (maxSize = 200, ttl = 300 * 1e3) => createCacheWithTTL({
365
379
  maxSize,
366
380
  ttl,
367
381
  autoCleanup: true
package/dist/main.mjs CHANGED
@@ -1,4 +1,4 @@
1
- //#region node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/esm/typeof.js
1
+ //#region node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/esm/typeof.js
2
2
  function _typeof(o) {
3
3
  "@babel/helpers - typeof";
4
4
  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o$1) {
@@ -9,7 +9,7 @@ function _typeof(o) {
9
9
  }
10
10
 
11
11
  //#endregion
12
- //#region node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/esm/toPrimitive.js
12
+ //#region node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/esm/toPrimitive.js
13
13
  function toPrimitive(t, r) {
14
14
  if ("object" != _typeof(t) || !t) return t;
15
15
  var e = t[Symbol.toPrimitive];
@@ -22,14 +22,14 @@ function toPrimitive(t, r) {
22
22
  }
23
23
 
24
24
  //#endregion
25
- //#region node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/esm/toPropertyKey.js
25
+ //#region node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/esm/toPropertyKey.js
26
26
  function toPropertyKey(t) {
27
27
  var i = toPrimitive(t, "string");
28
28
  return "symbol" == _typeof(i) ? i : i + "";
29
29
  }
30
30
 
31
31
  //#endregion
32
- //#region node_modules/.pnpm/@oxc-project+runtime@0.72.3/node_modules/@oxc-project/runtime/src/helpers/esm/defineProperty.js
32
+ //#region node_modules/.pnpm/@oxc-project+runtime@0.80.0/node_modules/@oxc-project/runtime/src/helpers/esm/defineProperty.js
33
33
  function _defineProperty(e, r, t) {
34
34
  return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
35
35
  value: t,
@@ -91,8 +91,7 @@ var FastCache = class {
91
91
  delete(key) {
92
92
  const node = this.cache.get(key);
93
93
  if (node === void 0) return false;
94
- this.cache.delete(key);
95
- this.removeNode(node);
94
+ this.deleteNode(node);
96
95
  return true;
97
96
  }
98
97
  clear() {
@@ -146,12 +145,17 @@ var FastCache = class {
146
145
  this.removeNode(node);
147
146
  this.addToHead(node);
148
147
  }
148
+ /**
149
+ * 统一删除入口:删除 Map 记录并从 LRU 链表移除节点。
150
+ * 子类(如 TTL 版本)可覆写该方法以保证多链表同步删除。
151
+ */
152
+ deleteNode(node) {
153
+ this.cache.delete(node.key);
154
+ this.removeNode(node);
155
+ }
149
156
  removeTail() {
150
157
  const lastNode = this.tail.prev;
151
- if (lastNode && lastNode !== this.head) {
152
- this.cache.delete(lastNode.key);
153
- this.removeNode(lastNode);
154
- }
158
+ if (lastNode && lastNode !== this.head) this.deleteNode(lastNode);
155
159
  }
156
160
  };
157
161
 
@@ -184,7 +188,10 @@ var FastCacheWithTTL = class extends FastCache {
184
188
  this.timeTail.timePrev = this.timeHead;
185
189
  if (this.autoCleanup && this.ttl > 0) {
186
190
  const cleanupInterval = options.cleanupInterval ?? this.ttl;
191
+ if (cleanupInterval <= 0) throw new Error("cleanupInterval must be positive");
187
192
  this.cleanupTimer = setInterval(() => this.cleanup(), cleanupInterval);
193
+ const anyTimer = this.cleanupTimer;
194
+ if (typeof anyTimer.unref === "function") anyTimer.unref();
188
195
  }
189
196
  }
190
197
  get(key) {
@@ -279,6 +286,13 @@ var FastCacheWithTTL = class extends FastCache {
279
286
  this.cleanupTimer = void 0;
280
287
  }
281
288
  }
289
+ /**
290
+ * 覆写统一删除入口:先维护 TTL 链表,再调用父类删除 LRU/Map。
291
+ */
292
+ deleteNode(node) {
293
+ this._removeFromTimeList(node);
294
+ super.deleteNode(node);
295
+ }
282
296
  isExpired(node, now) {
283
297
  if (this.ttl === 0 || node.timestamp === void 0) return false;
284
298
  return (now ?? Date.now()) - node.timestamp > this.ttl;
@@ -311,12 +325,12 @@ function createCacheWithTTL(options) {
311
325
  const CachePresets = {
312
326
  apiCache: (maxSize = 1e3) => createCache(maxSize),
313
327
  computeCache: (maxSize = 500) => createCache(maxSize),
314
- sessionCache: (maxSize = 100, ttl = 30 * 60 * 1e3) => createCacheWithTTL({
328
+ sessionCache: (maxSize = 100, ttl = 1800 * 1e3) => createCacheWithTTL({
315
329
  maxSize,
316
330
  ttl,
317
331
  autoCleanup: true
318
332
  }),
319
- tempCache: (maxSize = 200, ttl = 5 * 60 * 1e3) => createCacheWithTTL({
333
+ tempCache: (maxSize = 200, ttl = 300 * 1e3) => createCacheWithTTL({
320
334
  maxSize,
321
335
  ttl,
322
336
  autoCleanup: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fast-map-cache",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "High-performance TypeScript LRU cache (with optional TTL) for Node.js & browsers.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,21 +25,6 @@
25
25
  },
26
26
  "./package.json": "./package.json"
27
27
  },
28
- "scripts": {
29
- "test": "vitest run",
30
- "test:coverage": "vitest run --coverage",
31
- "lint": "oxlint",
32
- "build": "pnpm lint && pnpm type-check && tsdown",
33
- "bench": "vitest bench --run",
34
- "prepare": "simple-git-hooks install",
35
- "run:example": "npx tsx examples/01-basic-example.ts",
36
- "type-check": "tsc --noEmit",
37
- "format": "prettier --write .",
38
- "gen-report": "pnpm bench && tsx scripts/generate-performance-report.ts",
39
- "changeset": "changeset",
40
- "version:packages": "changeset version",
41
- "release": "pnpm build && changeset publish"
42
- },
43
28
  "keywords": [
44
29
  "cache",
45
30
  "lru",
@@ -91,5 +76,19 @@
91
76
  "bugs": {
92
77
  "url": "https://github.com/crper/fast-map-cache/issues"
93
78
  },
94
- "homepage": "https://github.com/crper/fast-map-cache#readme"
95
- }
79
+ "homepage": "https://github.com/crper/fast-map-cache#readme",
80
+ "scripts": {
81
+ "test": "vitest run",
82
+ "test:coverage": "vitest run --coverage",
83
+ "lint": "oxlint",
84
+ "build": "pnpm lint && pnpm type-check && tsdown",
85
+ "bench": "vitest bench --run",
86
+ "run:example": "npx tsx examples/01-basic-example.ts",
87
+ "type-check": "tsc --noEmit",
88
+ "format": "prettier --write .",
89
+ "gen-report": "pnpm bench && tsx scripts/generate-performance-report.ts",
90
+ "changeset": "changeset",
91
+ "version:packages": "changeset version",
92
+ "release": "pnpm build && changeset publish"
93
+ }
94
+ }