@isaacs/ttlcache 1.0.2 → 1.0.5

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/index.d.ts +169 -0
  2. package/index.js +48 -21
  3. package/package.json +31 -4
package/index.d.ts ADDED
@@ -0,0 +1,169 @@
1
+ // Type definitions for ttlcache 1.0.0
2
+ // Project: https://github.com/isaacs/ttlcache
3
+ // Loosely based on @isaacs/lru-cache
4
+ // https://github.com/isaacs/node-lru-cache/blob/v7.10.1/index.d.ts
5
+
6
+ declare class TTLCache<K, V> implements Iterable<[K, V]> {
7
+ constructor(options: TTLCache.Options<K, V>)
8
+
9
+ /**
10
+ * The total number of items held in the cache at the current moment.
11
+ */
12
+ public readonly size: number
13
+
14
+ /**
15
+ * Add a value to the cache.
16
+ */
17
+ public set(key: K, value: V, options?: TTLCache.SetOptions): this
18
+
19
+ /**
20
+ * Return a value from the cache.
21
+ * If the key is not found, `get()` will return `undefined`.
22
+ * This can be confusing when setting values specifically to `undefined`,
23
+ * as in `cache.set(key, undefined)`. Use `cache.has()` to determine
24
+ * whether a key is present in the cache at all.
25
+ */
26
+ public get<T = V>(
27
+ key: K,
28
+ options?: TTLCache.GetOptions
29
+ ): T | undefined
30
+
31
+ /**
32
+ * Check if a key is in the cache.
33
+ * Will return false if the item is stale, even though it is technically
34
+ * in the cache.
35
+ */
36
+ public has(key: K): boolean
37
+
38
+ /**
39
+ * Deletes a key out of the cache.
40
+ * Returns true if the key was deleted, false otherwise.
41
+ */
42
+ public delete(key: K): boolean
43
+
44
+ /**
45
+ * Clear the cache entirely, throwing away all values.
46
+ */
47
+ public clear(): void
48
+
49
+ /**
50
+ * Delete any stale entries. Returns true if anything was removed, false
51
+ * otherwise.
52
+ */
53
+ public purgeStale(): boolean
54
+
55
+ /**
56
+ * Return the remaining time before an item expires.
57
+ * Returns 0 if the item is not found in the cache or is already expired.
58
+ */
59
+ public getRemainingTTL(key: K): number
60
+
61
+ /**
62
+ * Return a generator yielding `[key, value]` pairs, from soonest expiring
63
+ * to latest expiring. (Items expiring at the same time are walked in insertion order.)
64
+ */
65
+ public entries(): Generator<[K, V]>
66
+
67
+ /**
68
+ * Return a generator yielding the keys in the cache,
69
+ * from soonest expiring to latest expiring.
70
+ */
71
+ public keys(): Generator<K>
72
+
73
+ /**
74
+ * Return a generator yielding the values in the cache,
75
+ * from soonest expiring to latest expiring.
76
+ */
77
+ public values(): Generator<V>
78
+
79
+ /**
80
+ * Iterating over the cache itself yields the same results as
81
+ * `cache.entries()`
82
+ */
83
+ public [Symbol.iterator](): Iterator<[K, V]>
84
+ }
85
+
86
+ declare namespace TTLCache {
87
+ type DisposeReason = 'evict' | 'set' | 'delete'
88
+
89
+ type Disposer<K, V> = (
90
+ value: V,
91
+ key: K,
92
+ reason: DisposeReason
93
+ ) => void
94
+
95
+ type TTLOptions = {
96
+ /**
97
+ * Max time in milliseconds for items to live in cache before they are
98
+ * considered stale. Note that stale items are NOT preemptively removed
99
+ * by default, and MAY live in the cache, contributing to max,
100
+ * long after they have expired.
101
+ *
102
+ * Must be an integer number of ms, defaults to 0, which means "no TTL"
103
+ */
104
+ ttl: number
105
+
106
+ /**
107
+ * Boolean flag to tell the cache to not update the TTL when
108
+ * setting a new value for an existing key (ie, when updating a value
109
+ * rather than inserting a new value). Note that the TTL value is
110
+ * _always_ set when adding a new entry into the cache.
111
+ *
112
+ * @default false
113
+ */
114
+ noUpdateTTL?: boolean
115
+ }
116
+
117
+ type Options<K, V> = {
118
+ /**
119
+ * The number of items to keep.
120
+ *
121
+ * @default Infinity
122
+ */
123
+ max?: number
124
+
125
+ /**
126
+ * Update the age of items on cache.get(), renewing their TTL
127
+ *
128
+ * @default false
129
+ */
130
+ updateAgeOnGet?: boolean
131
+
132
+ /**
133
+ * Function that is called on items when they are dropped from the cache.
134
+ * This can be handy if you want to close file descriptors or do other
135
+ * cleanup tasks when items are no longer accessible. Called with `key,
136
+ * value`. It's called before actually removing the item from the
137
+ * internal cache, so it is *NOT* safe to re-add them.
138
+ * Use `disposeAfter` if you wish to dispose items after they have been
139
+ * full removed, when it is safe to add them back to the cache.
140
+ */
141
+ dispose?: Disposer<K, V>
142
+ } & TTLOptions
143
+
144
+ type SetOptions = {
145
+ /**
146
+ * Set to true to suppress calling the dispose() function if the entry
147
+ * key is still accessible within the cache.
148
+ *
149
+ * @default false
150
+ */
151
+ noDisposeOnSet?: boolean
152
+ noUpdateTTL?: boolean
153
+ ttl?: number
154
+ }
155
+
156
+ type GetOptions = {
157
+ /**
158
+ * Update the age of items
159
+ */
160
+ updateAgeOnGet?: boolean
161
+
162
+ /**
163
+ * Set new TTL, applied only when `updateAgeOnGet` is true
164
+ */
165
+ ttl?: number
166
+ }
167
+ }
168
+
169
+ export = TTLCache
package/index.js CHANGED
@@ -3,18 +3,24 @@
3
3
  // Relies on the fact that integer Object keys are kept sorted,
4
4
  // and managed very efficiently by V8.
5
5
 
6
- const maybeReqPerfHooks = (fallback) => {
6
+ const maybeReqPerfHooks = fallback => {
7
7
  try {
8
8
  return require('perf_hooks').performance
9
9
  } catch (e) {
10
10
  return fallback
11
11
  }
12
12
  }
13
- const {now} = maybeReqPerfHooks(Date)
13
+ const { now } = maybeReqPerfHooks(Date)
14
14
  const isPosInt = n => n && n === Math.floor(n) && n > 0 && isFinite(n)
15
15
 
16
16
  class TTLCache {
17
- constructor ({ max = Infinity, ttl, updateAgeOnGet = false, noUpdateTTL = false, dispose }) {
17
+ constructor({
18
+ max = Infinity,
19
+ ttl,
20
+ updateAgeOnGet = false,
21
+ noUpdateTTL = false,
22
+ dispose,
23
+ }) {
18
24
  // {[expirationTime]: [keys]}
19
25
  this.expirations = Object.create(null)
20
26
  // {key=>val}
@@ -29,6 +35,8 @@ class TTLCache {
29
35
  }
30
36
  this.ttl = ttl
31
37
  this.max = max
38
+ this.updateAgeOnGet = updateAgeOnGet
39
+ this.noUpdateTTL = noUpdateTTL
32
40
  if (dispose !== undefined) {
33
41
  if (typeof dispose !== 'function') {
34
42
  throw new TypeError('dispose must be function if set')
@@ -37,8 +45,9 @@ class TTLCache {
37
45
  }
38
46
  }
39
47
 
40
- clear () {
41
- const entries = this.dispose !== TTLCache.prototype.dispose ? [...this] : []
48
+ clear() {
49
+ const entries =
50
+ this.dispose !== TTLCache.prototype.dispose ? [...this] : []
42
51
  this.data.clear()
43
52
  this.expirationMap.clear()
44
53
  this.expirations = Object.create(null)
@@ -47,13 +56,22 @@ class TTLCache {
47
56
  }
48
57
  }
49
58
 
50
- set (key, val, { ttl = this.ttl, noUpdateTTL = this.noUpdateTTL, noDisposeOnSet = this.noDisposeOnSet } = {}) {
59
+ set(
60
+ key,
61
+ val,
62
+ {
63
+ ttl = this.ttl,
64
+ noUpdateTTL = this.noUpdateTTL,
65
+ noDisposeOnSet = this.noDisposeOnSet,
66
+ } = {}
67
+ ) {
51
68
  if (!isPosInt(ttl)) {
52
69
  throw new TypeError('ttl must be positive integer')
53
70
  }
54
71
  const current = this.expirationMap.get(key)
55
72
  const time = now()
56
- const oldValue = current === undefined ? undefined : this.data.get(key)
73
+ const oldValue =
74
+ current === undefined ? undefined : this.data.get(key)
57
75
  if (current !== undefined) {
58
76
  // we aren't updating the ttl, so just set the data
59
77
  if (noUpdateTTL && current > time) {
@@ -96,26 +114,35 @@ class TTLCache {
96
114
  return this
97
115
  }
98
116
 
99
- has (key) {
117
+ has(key) {
100
118
  return this.data.has(key)
101
119
  }
102
120
 
103
- getRemainingTTL (key) {
121
+ getRemainingTTL(key) {
104
122
  const expiration = this.expirationMap.get(key)
105
- return expiration !== undefined ? Math.max(0, expiration - now()) : 0
123
+ return expiration !== undefined
124
+ ? Math.max(0, expiration - now())
125
+ : 0
106
126
  }
107
127
 
108
- get (key, { updateAgeOnGet = this.updateAgeOnGet, ttl = this.ttl } = {}) {
128
+ get(
129
+ key,
130
+ { updateAgeOnGet = this.updateAgeOnGet, ttl = this.ttl } = {}
131
+ ) {
109
132
  const val = this.data.get(key)
110
133
  if (updateAgeOnGet) {
111
- this.set(key, val, { noUpdateTTL: false, noDisposeOnSet: true, ttl })
134
+ this.set(key, val, {
135
+ noUpdateTTL: false,
136
+ noDisposeOnSet: true,
137
+ ttl,
138
+ })
112
139
  }
113
140
  return val
114
141
  }
115
142
 
116
- dispose (value, key) {}
143
+ dispose(_, __) {}
117
144
 
118
- delete (key) {
145
+ delete(key) {
119
146
  const current = this.expirationMap.get(key)
120
147
  if (current !== undefined) {
121
148
  const value = this.data.get(key)
@@ -133,7 +160,7 @@ class TTLCache {
133
160
  return false
134
161
  }
135
162
 
136
- purgeToCapacity () {
163
+ purgeToCapacity() {
137
164
  for (const exp in this.expirations) {
138
165
  const keys = this.expirations[exp]
139
166
  if (this.size - keys.length >= this.max) {
@@ -157,11 +184,11 @@ class TTLCache {
157
184
  }
158
185
  }
159
186
 
160
- get size () {
187
+ get size() {
161
188
  return this.data.size
162
189
  }
163
190
 
164
- purgeStale () {
191
+ purgeStale() {
165
192
  const n = now()
166
193
  for (const exp in this.expirations) {
167
194
  if (exp > n) {
@@ -177,28 +204,28 @@ class TTLCache {
177
204
  }
178
205
  }
179
206
 
180
- *entries () {
207
+ *entries() {
181
208
  for (const exp in this.expirations) {
182
209
  for (const key of this.expirations[exp]) {
183
210
  yield [key, this.data.get(key)]
184
211
  }
185
212
  }
186
213
  }
187
- *keys () {
214
+ *keys() {
188
215
  for (const exp in this.expirations) {
189
216
  for (const key of this.expirations[exp]) {
190
217
  yield key
191
218
  }
192
219
  }
193
220
  }
194
- *values () {
221
+ *values() {
195
222
  for (const exp in this.expirations) {
196
223
  for (const key of this.expirations[exp]) {
197
224
  yield this.data.get(key)
198
225
  }
199
226
  }
200
227
  }
201
- [Symbol.iterator] () {
228
+ [Symbol.iterator]() {
202
229
  return this.entries()
203
230
  }
204
231
  }
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@isaacs/ttlcache",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "files": [
5
- "index.js"
5
+ "index.js",
6
+ "index.d.ts"
6
7
  ],
7
8
  "main": "index.js",
8
9
  "exports": {
@@ -23,10 +24,36 @@
23
24
  "prepublishOnly": "git push origin --follow-tags"
24
25
  },
25
26
  "devDependencies": {
26
- "clock-mock": "^1.0.4",
27
- "tap": "^16.0.1"
27
+ "@types/node": "^17.0.42",
28
+ "@types/tap": "^15.0.7",
29
+ "clock-mock": "^1.0.6",
30
+ "prettier": "^2.7.0",
31
+ "tap": "^16.0.1",
32
+ "ts-node": "^10.8.1",
33
+ "typescript": "^4.7.3"
28
34
  },
29
35
  "engines": {
30
36
  "node": ">=12"
37
+ },
38
+ "tap": {
39
+ "nyc-arg": [
40
+ "--include=index.js"
41
+ ],
42
+ "node-arg": [
43
+ "--require",
44
+ "ts-node/register"
45
+ ],
46
+ "ts": false
47
+ },
48
+ "prettier": {
49
+ "semi": false,
50
+ "printWidth": 70,
51
+ "tabWidth": 2,
52
+ "useTabs": false,
53
+ "singleQuote": true,
54
+ "jsxSingleQuote": false,
55
+ "bracketSameLine": true,
56
+ "arrowParens": "avoid",
57
+ "endOfLine": "lf"
31
58
  }
32
59
  }