@withjoy/limiter 0.1.3 → 0.1.4-test
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 +4 -0
- package/limitd-redis/LICENSE +21 -0
- package/limitd-redis/README.md +183 -0
- package/limitd-redis/docker-compose.yml +11 -0
- package/limitd-redis/index.js +2 -0
- package/limitd-redis/lib/cb.js +45 -0
- package/limitd-redis/lib/client.js +135 -0
- package/limitd-redis/lib/db.js +501 -0
- package/limitd-redis/lib/db_ping.js +106 -0
- package/limitd-redis/lib/put.lua +31 -0
- package/limitd-redis/lib/take.lua +48 -0
- package/limitd-redis/lib/utils.js +116 -0
- package/limitd-redis/lib/validation.js +64 -0
- package/limitd-redis/node_modules/lru-cache/LICENSE +15 -0
- package/limitd-redis/node_modules/lru-cache/README.md +158 -0
- package/limitd-redis/node_modules/lru-cache/index.js +468 -0
- package/limitd-redis/node_modules/lru-cache/package.json +74 -0
- package/limitd-redis/node_modules/ms/index.js +162 -0
- package/limitd-redis/node_modules/ms/license.md +21 -0
- package/limitd-redis/node_modules/ms/package.json +73 -0
- package/limitd-redis/node_modules/ms/readme.md +59 -0
- package/limitd-redis/node_modules/yallist/LICENSE +15 -0
- package/limitd-redis/node_modules/yallist/README.md +204 -0
- package/limitd-redis/node_modules/yallist/iterator.js +7 -0
- package/limitd-redis/node_modules/yallist/package.json +65 -0
- package/limitd-redis/node_modules/yallist/yallist.js +370 -0
- package/limitd-redis/opslevel.yml +6 -0
- package/limitd-redis/package-lock.json +3484 -0
- package/limitd-redis/package.json +31 -0
- package/limitd-redis/test/cb.tests.js +124 -0
- package/limitd-redis/test/client.tests.js +194 -0
- package/limitd-redis/test/db.tests.js +1318 -0
- package/limitd-redis/test/validation.tests.js +124 -0
- package/limiter.js +57 -1
- package/package.json +3 -2
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = LRUCache
|
|
4
|
+
|
|
5
|
+
// This will be a proper iterable 'Map' in engines that support it,
|
|
6
|
+
// or a fakey-fake PseudoMap in older versions.
|
|
7
|
+
var Map = require('pseudomap')
|
|
8
|
+
var util = require('util')
|
|
9
|
+
|
|
10
|
+
// A linked list to keep track of recently-used-ness
|
|
11
|
+
var Yallist = require('yallist')
|
|
12
|
+
|
|
13
|
+
// use symbols if possible, otherwise just _props
|
|
14
|
+
var hasSymbol = typeof Symbol === 'function' && process.env._nodeLRUCacheForceNoSymbol !== '1'
|
|
15
|
+
var makeSymbol
|
|
16
|
+
if (hasSymbol) {
|
|
17
|
+
makeSymbol = function (key) {
|
|
18
|
+
return Symbol(key)
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
makeSymbol = function (key) {
|
|
22
|
+
return '_' + key
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var MAX = makeSymbol('max')
|
|
27
|
+
var LENGTH = makeSymbol('length')
|
|
28
|
+
var LENGTH_CALCULATOR = makeSymbol('lengthCalculator')
|
|
29
|
+
var ALLOW_STALE = makeSymbol('allowStale')
|
|
30
|
+
var MAX_AGE = makeSymbol('maxAge')
|
|
31
|
+
var DISPOSE = makeSymbol('dispose')
|
|
32
|
+
var NO_DISPOSE_ON_SET = makeSymbol('noDisposeOnSet')
|
|
33
|
+
var LRU_LIST = makeSymbol('lruList')
|
|
34
|
+
var CACHE = makeSymbol('cache')
|
|
35
|
+
|
|
36
|
+
function naiveLength () { return 1 }
|
|
37
|
+
|
|
38
|
+
// lruList is a yallist where the head is the youngest
|
|
39
|
+
// item, and the tail is the oldest. the list contains the Hit
|
|
40
|
+
// objects as the entries.
|
|
41
|
+
// Each Hit object has a reference to its Yallist.Node. This
|
|
42
|
+
// never changes.
|
|
43
|
+
//
|
|
44
|
+
// cache is a Map (or PseudoMap) that matches the keys to
|
|
45
|
+
// the Yallist.Node object.
|
|
46
|
+
function LRUCache (options) {
|
|
47
|
+
if (!(this instanceof LRUCache)) {
|
|
48
|
+
return new LRUCache(options)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof options === 'number') {
|
|
52
|
+
options = { max: options }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!options) {
|
|
56
|
+
options = {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var max = this[MAX] = options.max
|
|
60
|
+
// Kind of weird to have a default max of Infinity, but oh well.
|
|
61
|
+
if (!max ||
|
|
62
|
+
!(typeof max === 'number') ||
|
|
63
|
+
max <= 0) {
|
|
64
|
+
this[MAX] = Infinity
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var lc = options.length || naiveLength
|
|
68
|
+
if (typeof lc !== 'function') {
|
|
69
|
+
lc = naiveLength
|
|
70
|
+
}
|
|
71
|
+
this[LENGTH_CALCULATOR] = lc
|
|
72
|
+
|
|
73
|
+
this[ALLOW_STALE] = options.stale || false
|
|
74
|
+
this[MAX_AGE] = options.maxAge || 0
|
|
75
|
+
this[DISPOSE] = options.dispose
|
|
76
|
+
this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false
|
|
77
|
+
this.reset()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// resize the cache when the max changes.
|
|
81
|
+
Object.defineProperty(LRUCache.prototype, 'max', {
|
|
82
|
+
set: function (mL) {
|
|
83
|
+
if (!mL || !(typeof mL === 'number') || mL <= 0) {
|
|
84
|
+
mL = Infinity
|
|
85
|
+
}
|
|
86
|
+
this[MAX] = mL
|
|
87
|
+
trim(this)
|
|
88
|
+
},
|
|
89
|
+
get: function () {
|
|
90
|
+
return this[MAX]
|
|
91
|
+
},
|
|
92
|
+
enumerable: true
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
Object.defineProperty(LRUCache.prototype, 'allowStale', {
|
|
96
|
+
set: function (allowStale) {
|
|
97
|
+
this[ALLOW_STALE] = !!allowStale
|
|
98
|
+
},
|
|
99
|
+
get: function () {
|
|
100
|
+
return this[ALLOW_STALE]
|
|
101
|
+
},
|
|
102
|
+
enumerable: true
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
Object.defineProperty(LRUCache.prototype, 'maxAge', {
|
|
106
|
+
set: function (mA) {
|
|
107
|
+
if (!mA || !(typeof mA === 'number') || mA < 0) {
|
|
108
|
+
mA = 0
|
|
109
|
+
}
|
|
110
|
+
this[MAX_AGE] = mA
|
|
111
|
+
trim(this)
|
|
112
|
+
},
|
|
113
|
+
get: function () {
|
|
114
|
+
return this[MAX_AGE]
|
|
115
|
+
},
|
|
116
|
+
enumerable: true
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// resize the cache when the lengthCalculator changes.
|
|
120
|
+
Object.defineProperty(LRUCache.prototype, 'lengthCalculator', {
|
|
121
|
+
set: function (lC) {
|
|
122
|
+
if (typeof lC !== 'function') {
|
|
123
|
+
lC = naiveLength
|
|
124
|
+
}
|
|
125
|
+
if (lC !== this[LENGTH_CALCULATOR]) {
|
|
126
|
+
this[LENGTH_CALCULATOR] = lC
|
|
127
|
+
this[LENGTH] = 0
|
|
128
|
+
this[LRU_LIST].forEach(function (hit) {
|
|
129
|
+
hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key)
|
|
130
|
+
this[LENGTH] += hit.length
|
|
131
|
+
}, this)
|
|
132
|
+
}
|
|
133
|
+
trim(this)
|
|
134
|
+
},
|
|
135
|
+
get: function () { return this[LENGTH_CALCULATOR] },
|
|
136
|
+
enumerable: true
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
Object.defineProperty(LRUCache.prototype, 'length', {
|
|
140
|
+
get: function () { return this[LENGTH] },
|
|
141
|
+
enumerable: true
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
Object.defineProperty(LRUCache.prototype, 'itemCount', {
|
|
145
|
+
get: function () { return this[LRU_LIST].length },
|
|
146
|
+
enumerable: true
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
LRUCache.prototype.rforEach = function (fn, thisp) {
|
|
150
|
+
thisp = thisp || this
|
|
151
|
+
for (var walker = this[LRU_LIST].tail; walker !== null;) {
|
|
152
|
+
var prev = walker.prev
|
|
153
|
+
forEachStep(this, fn, walker, thisp)
|
|
154
|
+
walker = prev
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function forEachStep (self, fn, node, thisp) {
|
|
159
|
+
var hit = node.value
|
|
160
|
+
if (isStale(self, hit)) {
|
|
161
|
+
del(self, node)
|
|
162
|
+
if (!self[ALLOW_STALE]) {
|
|
163
|
+
hit = undefined
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (hit) {
|
|
167
|
+
fn.call(thisp, hit.value, hit.key, self)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
LRUCache.prototype.forEach = function (fn, thisp) {
|
|
172
|
+
thisp = thisp || this
|
|
173
|
+
for (var walker = this[LRU_LIST].head; walker !== null;) {
|
|
174
|
+
var next = walker.next
|
|
175
|
+
forEachStep(this, fn, walker, thisp)
|
|
176
|
+
walker = next
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
LRUCache.prototype.keys = function () {
|
|
181
|
+
return this[LRU_LIST].toArray().map(function (k) {
|
|
182
|
+
return k.key
|
|
183
|
+
}, this)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
LRUCache.prototype.values = function () {
|
|
187
|
+
return this[LRU_LIST].toArray().map(function (k) {
|
|
188
|
+
return k.value
|
|
189
|
+
}, this)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
LRUCache.prototype.reset = function () {
|
|
193
|
+
if (this[DISPOSE] &&
|
|
194
|
+
this[LRU_LIST] &&
|
|
195
|
+
this[LRU_LIST].length) {
|
|
196
|
+
this[LRU_LIST].forEach(function (hit) {
|
|
197
|
+
this[DISPOSE](hit.key, hit.value)
|
|
198
|
+
}, this)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this[CACHE] = new Map() // hash of items by key
|
|
202
|
+
this[LRU_LIST] = new Yallist() // list of items in order of use recency
|
|
203
|
+
this[LENGTH] = 0 // length of items in the list
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
LRUCache.prototype.dump = function () {
|
|
207
|
+
return this[LRU_LIST].map(function (hit) {
|
|
208
|
+
if (!isStale(this, hit)) {
|
|
209
|
+
return {
|
|
210
|
+
k: hit.key,
|
|
211
|
+
v: hit.value,
|
|
212
|
+
e: hit.now + (hit.maxAge || 0)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}, this).toArray().filter(function (h) {
|
|
216
|
+
return h
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
LRUCache.prototype.dumpLru = function () {
|
|
221
|
+
return this[LRU_LIST]
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* istanbul ignore next */
|
|
225
|
+
LRUCache.prototype.inspect = function (n, opts) {
|
|
226
|
+
var str = 'LRUCache {'
|
|
227
|
+
var extras = false
|
|
228
|
+
|
|
229
|
+
var as = this[ALLOW_STALE]
|
|
230
|
+
if (as) {
|
|
231
|
+
str += '\n allowStale: true'
|
|
232
|
+
extras = true
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
var max = this[MAX]
|
|
236
|
+
if (max && max !== Infinity) {
|
|
237
|
+
if (extras) {
|
|
238
|
+
str += ','
|
|
239
|
+
}
|
|
240
|
+
str += '\n max: ' + util.inspect(max, opts)
|
|
241
|
+
extras = true
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
var maxAge = this[MAX_AGE]
|
|
245
|
+
if (maxAge) {
|
|
246
|
+
if (extras) {
|
|
247
|
+
str += ','
|
|
248
|
+
}
|
|
249
|
+
str += '\n maxAge: ' + util.inspect(maxAge, opts)
|
|
250
|
+
extras = true
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
var lc = this[LENGTH_CALCULATOR]
|
|
254
|
+
if (lc && lc !== naiveLength) {
|
|
255
|
+
if (extras) {
|
|
256
|
+
str += ','
|
|
257
|
+
}
|
|
258
|
+
str += '\n length: ' + util.inspect(this[LENGTH], opts)
|
|
259
|
+
extras = true
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
var didFirst = false
|
|
263
|
+
this[LRU_LIST].forEach(function (item) {
|
|
264
|
+
if (didFirst) {
|
|
265
|
+
str += ',\n '
|
|
266
|
+
} else {
|
|
267
|
+
if (extras) {
|
|
268
|
+
str += ',\n'
|
|
269
|
+
}
|
|
270
|
+
didFirst = true
|
|
271
|
+
str += '\n '
|
|
272
|
+
}
|
|
273
|
+
var key = util.inspect(item.key).split('\n').join('\n ')
|
|
274
|
+
var val = { value: item.value }
|
|
275
|
+
if (item.maxAge !== maxAge) {
|
|
276
|
+
val.maxAge = item.maxAge
|
|
277
|
+
}
|
|
278
|
+
if (lc !== naiveLength) {
|
|
279
|
+
val.length = item.length
|
|
280
|
+
}
|
|
281
|
+
if (isStale(this, item)) {
|
|
282
|
+
val.stale = true
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
val = util.inspect(val, opts).split('\n').join('\n ')
|
|
286
|
+
str += key + ' => ' + val
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
if (didFirst || extras) {
|
|
290
|
+
str += '\n'
|
|
291
|
+
}
|
|
292
|
+
str += '}'
|
|
293
|
+
|
|
294
|
+
return str
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
LRUCache.prototype.set = function (key, value, maxAge) {
|
|
298
|
+
maxAge = maxAge || this[MAX_AGE]
|
|
299
|
+
|
|
300
|
+
var now = maxAge ? Date.now() : 0
|
|
301
|
+
var len = this[LENGTH_CALCULATOR](value, key)
|
|
302
|
+
|
|
303
|
+
if (this[CACHE].has(key)) {
|
|
304
|
+
if (len > this[MAX]) {
|
|
305
|
+
del(this, this[CACHE].get(key))
|
|
306
|
+
return false
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
var node = this[CACHE].get(key)
|
|
310
|
+
var item = node.value
|
|
311
|
+
|
|
312
|
+
// dispose of the old one before overwriting
|
|
313
|
+
// split out into 2 ifs for better coverage tracking
|
|
314
|
+
if (this[DISPOSE]) {
|
|
315
|
+
if (!this[NO_DISPOSE_ON_SET]) {
|
|
316
|
+
this[DISPOSE](key, item.value)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
item.now = now
|
|
321
|
+
item.maxAge = maxAge
|
|
322
|
+
item.value = value
|
|
323
|
+
this[LENGTH] += len - item.length
|
|
324
|
+
item.length = len
|
|
325
|
+
this.get(key)
|
|
326
|
+
trim(this)
|
|
327
|
+
return true
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
var hit = new Entry(key, value, len, now, maxAge)
|
|
331
|
+
|
|
332
|
+
// oversized objects fall out of cache automatically.
|
|
333
|
+
if (hit.length > this[MAX]) {
|
|
334
|
+
if (this[DISPOSE]) {
|
|
335
|
+
this[DISPOSE](key, value)
|
|
336
|
+
}
|
|
337
|
+
return false
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
this[LENGTH] += hit.length
|
|
341
|
+
this[LRU_LIST].unshift(hit)
|
|
342
|
+
this[CACHE].set(key, this[LRU_LIST].head)
|
|
343
|
+
trim(this)
|
|
344
|
+
return true
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
LRUCache.prototype.has = function (key) {
|
|
348
|
+
if (!this[CACHE].has(key)) return false
|
|
349
|
+
var hit = this[CACHE].get(key).value
|
|
350
|
+
if (isStale(this, hit)) {
|
|
351
|
+
return false
|
|
352
|
+
}
|
|
353
|
+
return true
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
LRUCache.prototype.get = function (key) {
|
|
357
|
+
return get(this, key, true)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
LRUCache.prototype.peek = function (key) {
|
|
361
|
+
return get(this, key, false)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
LRUCache.prototype.pop = function () {
|
|
365
|
+
var node = this[LRU_LIST].tail
|
|
366
|
+
if (!node) return null
|
|
367
|
+
del(this, node)
|
|
368
|
+
return node.value
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
LRUCache.prototype.del = function (key) {
|
|
372
|
+
del(this, this[CACHE].get(key))
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
LRUCache.prototype.load = function (arr) {
|
|
376
|
+
// reset the cache
|
|
377
|
+
this.reset()
|
|
378
|
+
|
|
379
|
+
var now = Date.now()
|
|
380
|
+
// A previous serialized cache has the most recent items first
|
|
381
|
+
for (var l = arr.length - 1; l >= 0; l--) {
|
|
382
|
+
var hit = arr[l]
|
|
383
|
+
var expiresAt = hit.e || 0
|
|
384
|
+
if (expiresAt === 0) {
|
|
385
|
+
// the item was created without expiration in a non aged cache
|
|
386
|
+
this.set(hit.k, hit.v)
|
|
387
|
+
} else {
|
|
388
|
+
var maxAge = expiresAt - now
|
|
389
|
+
// dont add already expired items
|
|
390
|
+
if (maxAge > 0) {
|
|
391
|
+
this.set(hit.k, hit.v, maxAge)
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
LRUCache.prototype.prune = function () {
|
|
398
|
+
var self = this
|
|
399
|
+
this[CACHE].forEach(function (value, key) {
|
|
400
|
+
get(self, key, false)
|
|
401
|
+
})
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function get (self, key, doUse) {
|
|
405
|
+
var node = self[CACHE].get(key)
|
|
406
|
+
if (node) {
|
|
407
|
+
var hit = node.value
|
|
408
|
+
if (isStale(self, hit)) {
|
|
409
|
+
del(self, node)
|
|
410
|
+
if (!self[ALLOW_STALE]) hit = undefined
|
|
411
|
+
} else {
|
|
412
|
+
if (doUse) {
|
|
413
|
+
self[LRU_LIST].unshiftNode(node)
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (hit) hit = hit.value
|
|
417
|
+
}
|
|
418
|
+
return hit
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function isStale (self, hit) {
|
|
422
|
+
if (!hit || (!hit.maxAge && !self[MAX_AGE])) {
|
|
423
|
+
return false
|
|
424
|
+
}
|
|
425
|
+
var stale = false
|
|
426
|
+
var diff = Date.now() - hit.now
|
|
427
|
+
if (hit.maxAge) {
|
|
428
|
+
stale = diff > hit.maxAge
|
|
429
|
+
} else {
|
|
430
|
+
stale = self[MAX_AGE] && (diff > self[MAX_AGE])
|
|
431
|
+
}
|
|
432
|
+
return stale
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function trim (self) {
|
|
436
|
+
if (self[LENGTH] > self[MAX]) {
|
|
437
|
+
for (var walker = self[LRU_LIST].tail;
|
|
438
|
+
self[LENGTH] > self[MAX] && walker !== null;) {
|
|
439
|
+
// We know that we're about to delete this one, and also
|
|
440
|
+
// what the next least recently used key will be, so just
|
|
441
|
+
// go ahead and set it now.
|
|
442
|
+
var prev = walker.prev
|
|
443
|
+
del(self, walker)
|
|
444
|
+
walker = prev
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function del (self, node) {
|
|
450
|
+
if (node) {
|
|
451
|
+
var hit = node.value
|
|
452
|
+
if (self[DISPOSE]) {
|
|
453
|
+
self[DISPOSE](hit.key, hit.value)
|
|
454
|
+
}
|
|
455
|
+
self[LENGTH] -= hit.length
|
|
456
|
+
self[CACHE].delete(hit.key)
|
|
457
|
+
self[LRU_LIST].removeNode(node)
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// classy, since V8 prefers predictable objects.
|
|
462
|
+
function Entry (key, value, length, now, maxAge) {
|
|
463
|
+
this.key = key
|
|
464
|
+
this.value = value
|
|
465
|
+
this.length = length
|
|
466
|
+
this.now = now
|
|
467
|
+
this.maxAge = maxAge || 0
|
|
468
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_args": [
|
|
3
|
+
[
|
|
4
|
+
"lru-cache@4.1.5",
|
|
5
|
+
"/Users/mindpath/work/joy/limiter"
|
|
6
|
+
]
|
|
7
|
+
],
|
|
8
|
+
"_from": "lru-cache@4.1.5",
|
|
9
|
+
"_id": "lru-cache@4.1.5",
|
|
10
|
+
"_inBundle": false,
|
|
11
|
+
"_integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
|
|
12
|
+
"_location": "/limitd-redis/lru-cache",
|
|
13
|
+
"_phantomChildren": {},
|
|
14
|
+
"_requested": {
|
|
15
|
+
"type": "version",
|
|
16
|
+
"registry": true,
|
|
17
|
+
"raw": "lru-cache@4.1.5",
|
|
18
|
+
"name": "lru-cache",
|
|
19
|
+
"escapedName": "lru-cache",
|
|
20
|
+
"rawSpec": "4.1.5",
|
|
21
|
+
"saveSpec": null,
|
|
22
|
+
"fetchSpec": "4.1.5"
|
|
23
|
+
},
|
|
24
|
+
"_requiredBy": [
|
|
25
|
+
"/limitd-redis"
|
|
26
|
+
],
|
|
27
|
+
"_resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
|
|
28
|
+
"_spec": "4.1.5",
|
|
29
|
+
"_where": "/Users/mindpath/work/joy/limiter",
|
|
30
|
+
"author": {
|
|
31
|
+
"name": "Isaac Z. Schlueter",
|
|
32
|
+
"email": "i@izs.me"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/isaacs/node-lru-cache/issues"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"pseudomap": "^1.0.2",
|
|
39
|
+
"yallist": "^2.1.2"
|
|
40
|
+
},
|
|
41
|
+
"description": "A cache object that deletes the least-recently-used items.",
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"benchmark": "^2.1.4",
|
|
44
|
+
"standard": "^12.0.1",
|
|
45
|
+
"tap": "^12.1.0"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"index.js"
|
|
49
|
+
],
|
|
50
|
+
"homepage": "https://github.com/isaacs/node-lru-cache#readme",
|
|
51
|
+
"keywords": [
|
|
52
|
+
"mru",
|
|
53
|
+
"lru",
|
|
54
|
+
"cache"
|
|
55
|
+
],
|
|
56
|
+
"license": "ISC",
|
|
57
|
+
"main": "index.js",
|
|
58
|
+
"name": "lru-cache",
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "git://github.com/isaacs/node-lru-cache.git"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"coveragerport": "tap --coverage-report=html",
|
|
65
|
+
"lintfix": "standard --fix test/*.js index.js",
|
|
66
|
+
"postpublish": "git push origin --all; git push origin --tags",
|
|
67
|
+
"posttest": "standard test/*.js index.js",
|
|
68
|
+
"postversion": "npm publish --tag=legacy",
|
|
69
|
+
"preversion": "npm test",
|
|
70
|
+
"snap": "TAP_SNAPSHOT=1 tap test/*.js -J",
|
|
71
|
+
"test": "tap test/*.js --100 -J"
|
|
72
|
+
},
|
|
73
|
+
"version": "4.1.5"
|
|
74
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
var s = 1000;
|
|
6
|
+
var m = s * 60;
|
|
7
|
+
var h = m * 60;
|
|
8
|
+
var d = h * 24;
|
|
9
|
+
var w = d * 7;
|
|
10
|
+
var y = d * 365.25;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parse or format the given `val`.
|
|
14
|
+
*
|
|
15
|
+
* Options:
|
|
16
|
+
*
|
|
17
|
+
* - `long` verbose formatting [false]
|
|
18
|
+
*
|
|
19
|
+
* @param {String|Number} val
|
|
20
|
+
* @param {Object} [options]
|
|
21
|
+
* @throws {Error} throw an error if val is not a non-empty string or a number
|
|
22
|
+
* @return {String|Number}
|
|
23
|
+
* @api public
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
module.exports = function (val, options) {
|
|
27
|
+
options = options || {};
|
|
28
|
+
var type = typeof val;
|
|
29
|
+
if (type === 'string' && val.length > 0) {
|
|
30
|
+
return parse(val);
|
|
31
|
+
} else if (type === 'number' && isFinite(val)) {
|
|
32
|
+
return options.long ? fmtLong(val) : fmtShort(val);
|
|
33
|
+
}
|
|
34
|
+
throw new Error(
|
|
35
|
+
'val is not a non-empty string or a valid number. val=' +
|
|
36
|
+
JSON.stringify(val)
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parse the given `str` and return milliseconds.
|
|
42
|
+
*
|
|
43
|
+
* @param {String} str
|
|
44
|
+
* @return {Number}
|
|
45
|
+
* @api private
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
function parse(str) {
|
|
49
|
+
str = String(str);
|
|
50
|
+
if (str.length > 100) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
|
|
54
|
+
str
|
|
55
|
+
);
|
|
56
|
+
if (!match) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
var n = parseFloat(match[1]);
|
|
60
|
+
var type = (match[2] || 'ms').toLowerCase();
|
|
61
|
+
switch (type) {
|
|
62
|
+
case 'years':
|
|
63
|
+
case 'year':
|
|
64
|
+
case 'yrs':
|
|
65
|
+
case 'yr':
|
|
66
|
+
case 'y':
|
|
67
|
+
return n * y;
|
|
68
|
+
case 'weeks':
|
|
69
|
+
case 'week':
|
|
70
|
+
case 'w':
|
|
71
|
+
return n * w;
|
|
72
|
+
case 'days':
|
|
73
|
+
case 'day':
|
|
74
|
+
case 'd':
|
|
75
|
+
return n * d;
|
|
76
|
+
case 'hours':
|
|
77
|
+
case 'hour':
|
|
78
|
+
case 'hrs':
|
|
79
|
+
case 'hr':
|
|
80
|
+
case 'h':
|
|
81
|
+
return n * h;
|
|
82
|
+
case 'minutes':
|
|
83
|
+
case 'minute':
|
|
84
|
+
case 'mins':
|
|
85
|
+
case 'min':
|
|
86
|
+
case 'm':
|
|
87
|
+
return n * m;
|
|
88
|
+
case 'seconds':
|
|
89
|
+
case 'second':
|
|
90
|
+
case 'secs':
|
|
91
|
+
case 'sec':
|
|
92
|
+
case 's':
|
|
93
|
+
return n * s;
|
|
94
|
+
case 'milliseconds':
|
|
95
|
+
case 'millisecond':
|
|
96
|
+
case 'msecs':
|
|
97
|
+
case 'msec':
|
|
98
|
+
case 'ms':
|
|
99
|
+
return n;
|
|
100
|
+
default:
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Short format for `ms`.
|
|
107
|
+
*
|
|
108
|
+
* @param {Number} ms
|
|
109
|
+
* @return {String}
|
|
110
|
+
* @api private
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
function fmtShort(ms) {
|
|
114
|
+
var msAbs = Math.abs(ms);
|
|
115
|
+
if (msAbs >= d) {
|
|
116
|
+
return Math.round(ms / d) + 'd';
|
|
117
|
+
}
|
|
118
|
+
if (msAbs >= h) {
|
|
119
|
+
return Math.round(ms / h) + 'h';
|
|
120
|
+
}
|
|
121
|
+
if (msAbs >= m) {
|
|
122
|
+
return Math.round(ms / m) + 'm';
|
|
123
|
+
}
|
|
124
|
+
if (msAbs >= s) {
|
|
125
|
+
return Math.round(ms / s) + 's';
|
|
126
|
+
}
|
|
127
|
+
return ms + 'ms';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Long format for `ms`.
|
|
132
|
+
*
|
|
133
|
+
* @param {Number} ms
|
|
134
|
+
* @return {String}
|
|
135
|
+
* @api private
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
function fmtLong(ms) {
|
|
139
|
+
var msAbs = Math.abs(ms);
|
|
140
|
+
if (msAbs >= d) {
|
|
141
|
+
return plural(ms, msAbs, d, 'day');
|
|
142
|
+
}
|
|
143
|
+
if (msAbs >= h) {
|
|
144
|
+
return plural(ms, msAbs, h, 'hour');
|
|
145
|
+
}
|
|
146
|
+
if (msAbs >= m) {
|
|
147
|
+
return plural(ms, msAbs, m, 'minute');
|
|
148
|
+
}
|
|
149
|
+
if (msAbs >= s) {
|
|
150
|
+
return plural(ms, msAbs, s, 'second');
|
|
151
|
+
}
|
|
152
|
+
return ms + ' ms';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Pluralization helper.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
function plural(ms, msAbs, n, name) {
|
|
160
|
+
var isPlural = msAbs >= n * 1.5;
|
|
161
|
+
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
|
|
162
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Vercel, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|