@fefade/common 1.0.4 → 1.0.6
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/dist/index.d.mts +7 -8
- package/dist/index.d.ts +7 -8
- package/dist/index.js +35 -4589
- package/dist/index.mjs +27 -4598
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -1,4568 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
for (let key of __getOwnPropNames(from))
|
|
18
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
-
}
|
|
21
|
-
return to;
|
|
22
|
-
};
|
|
23
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
-
mod
|
|
30
|
-
));
|
|
31
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
-
|
|
33
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterAbstract.js
|
|
34
|
-
var require_RateLimiterAbstract = __commonJS({
|
|
35
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterAbstract.js"(exports2, module2) {
|
|
36
|
-
"use strict";
|
|
37
|
-
module2.exports = class RateLimiterAbstract {
|
|
38
|
-
/**
|
|
39
|
-
*
|
|
40
|
-
* @param opts Object {
|
|
41
|
-
* points: <required>, // Number of points (must be a number, can be negative)
|
|
42
|
-
* duration: <required>, // Per seconds (must be a non-negative number, 0 = never expires)
|
|
43
|
-
* blockDuration: 0, // Block if consumed more than points in current duration for blockDuration seconds
|
|
44
|
-
* execEvenly: false, // Execute allowed actions evenly over duration
|
|
45
|
-
* execEvenlyMinDelayMs: duration * 1000 / points, // ms, works with execEvenly=true option
|
|
46
|
-
* keyPrefix: 'rlflx',
|
|
47
|
-
* }
|
|
48
|
-
*/
|
|
49
|
-
constructor(opts = {}) {
|
|
50
|
-
this.points = opts.points;
|
|
51
|
-
this.duration = opts.duration;
|
|
52
|
-
this.blockDuration = opts.blockDuration;
|
|
53
|
-
this.execEvenly = opts.execEvenly;
|
|
54
|
-
this.execEvenlyMinDelayMs = opts.execEvenlyMinDelayMs;
|
|
55
|
-
this.keyPrefix = opts.keyPrefix;
|
|
56
|
-
}
|
|
57
|
-
get points() {
|
|
58
|
-
return this._points;
|
|
59
|
-
}
|
|
60
|
-
set points(value) {
|
|
61
|
-
if (Number.isFinite(value)) {
|
|
62
|
-
this._points = value;
|
|
63
|
-
} else {
|
|
64
|
-
throw new Error("points must be set and must be a finite number");
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
get duration() {
|
|
68
|
-
return this._duration;
|
|
69
|
-
}
|
|
70
|
-
set duration(value) {
|
|
71
|
-
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
72
|
-
this._duration = value;
|
|
73
|
-
} else {
|
|
74
|
-
throw new Error("duration must be set and must be a finite, non-negative number");
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
get msDuration() {
|
|
78
|
-
return this.duration * 1e3;
|
|
79
|
-
}
|
|
80
|
-
get blockDuration() {
|
|
81
|
-
return this._blockDuration;
|
|
82
|
-
}
|
|
83
|
-
set blockDuration(value) {
|
|
84
|
-
this._blockDuration = typeof value === "undefined" ? 0 : value;
|
|
85
|
-
}
|
|
86
|
-
get msBlockDuration() {
|
|
87
|
-
return this.blockDuration * 1e3;
|
|
88
|
-
}
|
|
89
|
-
get execEvenly() {
|
|
90
|
-
return this._execEvenly;
|
|
91
|
-
}
|
|
92
|
-
set execEvenly(value) {
|
|
93
|
-
this._execEvenly = typeof value === "undefined" ? false : Boolean(value);
|
|
94
|
-
}
|
|
95
|
-
get execEvenlyMinDelayMs() {
|
|
96
|
-
return this._execEvenlyMinDelayMs;
|
|
97
|
-
}
|
|
98
|
-
set execEvenlyMinDelayMs(value) {
|
|
99
|
-
this._execEvenlyMinDelayMs = typeof value === "undefined" ? Math.ceil(this.msDuration / this.points) : value;
|
|
100
|
-
}
|
|
101
|
-
get keyPrefix() {
|
|
102
|
-
return this._keyPrefix;
|
|
103
|
-
}
|
|
104
|
-
set keyPrefix(value) {
|
|
105
|
-
if (typeof value === "undefined") {
|
|
106
|
-
value = "rlflx";
|
|
107
|
-
}
|
|
108
|
-
if (typeof value !== "string") {
|
|
109
|
-
throw new Error("keyPrefix must be string");
|
|
110
|
-
}
|
|
111
|
-
this._keyPrefix = value;
|
|
112
|
-
}
|
|
113
|
-
_getKeySecDuration(options = {}) {
|
|
114
|
-
return options && options.customDuration >= 0 ? options.customDuration : this.duration;
|
|
115
|
-
}
|
|
116
|
-
getKey(key) {
|
|
117
|
-
return this.keyPrefix.length > 0 ? `${this.keyPrefix}:${key}` : key;
|
|
118
|
-
}
|
|
119
|
-
parseKey(rlKey) {
|
|
120
|
-
return rlKey.substring(this.keyPrefix.length);
|
|
121
|
-
}
|
|
122
|
-
consume() {
|
|
123
|
-
throw new Error("You have to implement the method 'consume'!");
|
|
124
|
-
}
|
|
125
|
-
penalty() {
|
|
126
|
-
throw new Error("You have to implement the method 'penalty'!");
|
|
127
|
-
}
|
|
128
|
-
reward() {
|
|
129
|
-
throw new Error("You have to implement the method 'reward'!");
|
|
130
|
-
}
|
|
131
|
-
get() {
|
|
132
|
-
throw new Error("You have to implement the method 'get'!");
|
|
133
|
-
}
|
|
134
|
-
set() {
|
|
135
|
-
throw new Error("You have to implement the method 'set'!");
|
|
136
|
-
}
|
|
137
|
-
block() {
|
|
138
|
-
throw new Error("You have to implement the method 'block'!");
|
|
139
|
-
}
|
|
140
|
-
delete() {
|
|
141
|
-
throw new Error("You have to implement the method 'delete'!");
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/BlockedKeys/BlockedKeys.js
|
|
148
|
-
var require_BlockedKeys = __commonJS({
|
|
149
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/BlockedKeys/BlockedKeys.js"(exports2, module2) {
|
|
150
|
-
"use strict";
|
|
151
|
-
module2.exports = class BlockedKeys {
|
|
152
|
-
constructor() {
|
|
153
|
-
this._keys = /* @__PURE__ */ new Map();
|
|
154
|
-
}
|
|
155
|
-
collectExpired() {
|
|
156
|
-
const now = Date.now();
|
|
157
|
-
for (const [key, expire] of this._keys) {
|
|
158
|
-
if (expire <= now) {
|
|
159
|
-
this._keys.delete(key);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Add new blocked key
|
|
165
|
-
*
|
|
166
|
-
* @param key String
|
|
167
|
-
* @param sec Number
|
|
168
|
-
*/
|
|
169
|
-
add(key, sec) {
|
|
170
|
-
this.addMs(key, sec * 1e3);
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Add new blocked key for ms
|
|
174
|
-
*
|
|
175
|
-
* @param key String
|
|
176
|
-
* @param ms Number
|
|
177
|
-
*/
|
|
178
|
-
addMs(key, ms) {
|
|
179
|
-
this._keys.set(key, Date.now() + ms);
|
|
180
|
-
if (this._keys.size > 999) {
|
|
181
|
-
this.collectExpired();
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* 0 means not blocked
|
|
186
|
-
*
|
|
187
|
-
* @param key
|
|
188
|
-
* @returns {number}
|
|
189
|
-
*/
|
|
190
|
-
msBeforeExpire(key) {
|
|
191
|
-
const expire = this._keys.get(key);
|
|
192
|
-
const now = Date.now();
|
|
193
|
-
if (expire && expire >= now) {
|
|
194
|
-
return expire - now;
|
|
195
|
-
}
|
|
196
|
-
return 0;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* If key is not given, delete all data in memory
|
|
200
|
-
*
|
|
201
|
-
* @param {string|undefined} key
|
|
202
|
-
*/
|
|
203
|
-
delete(key) {
|
|
204
|
-
if (key) {
|
|
205
|
-
this._keys.delete(key);
|
|
206
|
-
} else {
|
|
207
|
-
this._keys.clear();
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/BlockedKeys/index.js
|
|
215
|
-
var require_BlockedKeys2 = __commonJS({
|
|
216
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/BlockedKeys/index.js"(exports2, module2) {
|
|
217
|
-
"use strict";
|
|
218
|
-
var BlockedKeys = require_BlockedKeys();
|
|
219
|
-
module2.exports = BlockedKeys;
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterRes.js
|
|
224
|
-
var require_RateLimiterRes = __commonJS({
|
|
225
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterRes.js"(exports2, module2) {
|
|
226
|
-
"use strict";
|
|
227
|
-
module2.exports = class RateLimiterRes {
|
|
228
|
-
constructor(remainingPoints, msBeforeNext, consumedPoints, isFirstInDuration) {
|
|
229
|
-
this.remainingPoints = typeof remainingPoints === "undefined" ? 0 : remainingPoints;
|
|
230
|
-
this.msBeforeNext = typeof msBeforeNext === "undefined" ? 0 : msBeforeNext;
|
|
231
|
-
this.consumedPoints = typeof consumedPoints === "undefined" ? 0 : consumedPoints;
|
|
232
|
-
this.isFirstInDuration = typeof isFirstInDuration === "undefined" ? false : isFirstInDuration;
|
|
233
|
-
}
|
|
234
|
-
get msBeforeNext() {
|
|
235
|
-
return this._msBeforeNext;
|
|
236
|
-
}
|
|
237
|
-
set msBeforeNext(ms) {
|
|
238
|
-
this._msBeforeNext = ms;
|
|
239
|
-
return this;
|
|
240
|
-
}
|
|
241
|
-
get remainingPoints() {
|
|
242
|
-
return this._remainingPoints;
|
|
243
|
-
}
|
|
244
|
-
set remainingPoints(p) {
|
|
245
|
-
this._remainingPoints = p;
|
|
246
|
-
return this;
|
|
247
|
-
}
|
|
248
|
-
get consumedPoints() {
|
|
249
|
-
return this._consumedPoints;
|
|
250
|
-
}
|
|
251
|
-
set consumedPoints(p) {
|
|
252
|
-
this._consumedPoints = p;
|
|
253
|
-
return this;
|
|
254
|
-
}
|
|
255
|
-
get isFirstInDuration() {
|
|
256
|
-
return this._isFirstInDuration;
|
|
257
|
-
}
|
|
258
|
-
set isFirstInDuration(value) {
|
|
259
|
-
this._isFirstInDuration = Boolean(value);
|
|
260
|
-
}
|
|
261
|
-
_getDecoratedProperties() {
|
|
262
|
-
return {
|
|
263
|
-
remainingPoints: this.remainingPoints,
|
|
264
|
-
msBeforeNext: this.msBeforeNext,
|
|
265
|
-
consumedPoints: this.consumedPoints,
|
|
266
|
-
isFirstInDuration: this.isFirstInDuration
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
270
|
-
return this._getDecoratedProperties();
|
|
271
|
-
}
|
|
272
|
-
toString() {
|
|
273
|
-
return JSON.stringify(this._getDecoratedProperties());
|
|
274
|
-
}
|
|
275
|
-
toJSON() {
|
|
276
|
-
return this._getDecoratedProperties();
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterInsuredAbstract.js
|
|
283
|
-
var require_RateLimiterInsuredAbstract = __commonJS({
|
|
284
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterInsuredAbstract.js"(exports2, module2) {
|
|
285
|
-
"use strict";
|
|
286
|
-
var RateLimiterAbstract = require_RateLimiterAbstract();
|
|
287
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
288
|
-
module2.exports = class RateLimiterInsuredAbstract extends RateLimiterAbstract {
|
|
289
|
-
constructor(opts = {}) {
|
|
290
|
-
super(opts);
|
|
291
|
-
this.insuranceLimiter = opts.insuranceLimiter;
|
|
292
|
-
}
|
|
293
|
-
get insuranceLimiter() {
|
|
294
|
-
return this._insuranceLimiter;
|
|
295
|
-
}
|
|
296
|
-
set insuranceLimiter(value) {
|
|
297
|
-
if (typeof value !== "undefined" && !(value instanceof RateLimiterAbstract)) {
|
|
298
|
-
throw new Error("insuranceLimiter must be instance of RateLimiterAbstract");
|
|
299
|
-
}
|
|
300
|
-
this._insuranceLimiter = value;
|
|
301
|
-
if (this._insuranceLimiter) {
|
|
302
|
-
this._insuranceLimiter.blockDuration = this.blockDuration;
|
|
303
|
-
this._insuranceLimiter.execEvenly = this.execEvenly;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
_handleError(err, funcName, resolve, reject, params) {
|
|
307
|
-
if (err instanceof RateLimiterRes2) {
|
|
308
|
-
reject(err);
|
|
309
|
-
} else if (!(this.insuranceLimiter instanceof RateLimiterAbstract)) {
|
|
310
|
-
reject(err);
|
|
311
|
-
} else {
|
|
312
|
-
this.insuranceLimiter[funcName](...params).then((res) => {
|
|
313
|
-
resolve(res);
|
|
314
|
-
}).catch((res) => {
|
|
315
|
-
reject(res);
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
_operation(funcName, params) {
|
|
320
|
-
const promise2 = this[funcName](...params);
|
|
321
|
-
return new Promise((resolve, reject) => {
|
|
322
|
-
return promise2.then((res) => {
|
|
323
|
-
resolve(res);
|
|
324
|
-
}).catch((err) => {
|
|
325
|
-
if (funcName.startsWith("_")) {
|
|
326
|
-
funcName = funcName.slice(1);
|
|
327
|
-
}
|
|
328
|
-
this._handleError(err, funcName, resolve, reject, params);
|
|
329
|
-
});
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
consume(key, pointsToConsume = 1, options = {}) {
|
|
333
|
-
return this._operation("_consume", [key, pointsToConsume, options]);
|
|
334
|
-
}
|
|
335
|
-
penalty(key, points = 1, options = {}) {
|
|
336
|
-
return this._operation("_penalty", [key, points, options]);
|
|
337
|
-
}
|
|
338
|
-
reward(key, points = 1, options = {}) {
|
|
339
|
-
return this._operation("_reward", [key, points, options]);
|
|
340
|
-
}
|
|
341
|
-
get(key, options = {}) {
|
|
342
|
-
return this._operation("_get", [key, options]);
|
|
343
|
-
}
|
|
344
|
-
set(key, points, secDuration, options = {}) {
|
|
345
|
-
return this._operation("_set", [key, points, secDuration, options]);
|
|
346
|
-
}
|
|
347
|
-
block(key, secDuration, options = {}) {
|
|
348
|
-
return this._operation("_block", [key, secDuration, options]);
|
|
349
|
-
}
|
|
350
|
-
delete(key, options = {}) {
|
|
351
|
-
return this._operation("_delete", [key, options]);
|
|
352
|
-
}
|
|
353
|
-
_consume() {
|
|
354
|
-
throw new Error("You have to implement the method '_consume'!");
|
|
355
|
-
}
|
|
356
|
-
_penalty() {
|
|
357
|
-
throw new Error("You have to implement the method '_penalty'!");
|
|
358
|
-
}
|
|
359
|
-
_reward() {
|
|
360
|
-
throw new Error("You have to implement the method '_reward'!");
|
|
361
|
-
}
|
|
362
|
-
_get() {
|
|
363
|
-
throw new Error("You have to implement the method '_get'!");
|
|
364
|
-
}
|
|
365
|
-
_set() {
|
|
366
|
-
throw new Error("You have to implement the method '_set'!");
|
|
367
|
-
}
|
|
368
|
-
_block() {
|
|
369
|
-
throw new Error("You have to implement the method '_block'!");
|
|
370
|
-
}
|
|
371
|
-
_delete() {
|
|
372
|
-
throw new Error("You have to implement the method '_delete'!");
|
|
373
|
-
}
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterStoreAbstract.js
|
|
379
|
-
var require_RateLimiterStoreAbstract = __commonJS({
|
|
380
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterStoreAbstract.js"(exports2, module2) {
|
|
381
|
-
"use strict";
|
|
382
|
-
var RateLimiterAbstract = require_RateLimiterAbstract();
|
|
383
|
-
var BlockedKeys = require_BlockedKeys2();
|
|
384
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
385
|
-
var RateLimiterInsuredAbstract = require_RateLimiterInsuredAbstract();
|
|
386
|
-
module2.exports = class RateLimiterStoreAbstract extends RateLimiterInsuredAbstract {
|
|
387
|
-
/**
|
|
388
|
-
*
|
|
389
|
-
* @param opts Object Defaults {
|
|
390
|
-
* ... see other in RateLimiterAbstract
|
|
391
|
-
*
|
|
392
|
-
* inMemoryBlockOnConsumed: 40, // Number of points when key is blocked
|
|
393
|
-
* inMemoryBlockDuration: 10, // Block duration in seconds
|
|
394
|
-
* insuranceLimiter: RateLimiterAbstract
|
|
395
|
-
* }
|
|
396
|
-
*/
|
|
397
|
-
constructor(opts = {}) {
|
|
398
|
-
super(opts);
|
|
399
|
-
this.inMemoryBlockOnConsumed = opts.inMemoryBlockOnConsumed;
|
|
400
|
-
this.inMemoryBlockDuration = opts.inMemoryBlockDuration;
|
|
401
|
-
this._inMemoryBlockedKeys = new BlockedKeys();
|
|
402
|
-
}
|
|
403
|
-
get client() {
|
|
404
|
-
return this._client;
|
|
405
|
-
}
|
|
406
|
-
set client(value) {
|
|
407
|
-
if (typeof value === "undefined") {
|
|
408
|
-
throw new Error("storeClient is not set");
|
|
409
|
-
}
|
|
410
|
-
this._client = value;
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Have to be launched after consume
|
|
414
|
-
* It blocks key and execute evenly depending on result from store
|
|
415
|
-
*
|
|
416
|
-
* It uses _getRateLimiterRes function to prepare RateLimiterRes from store result
|
|
417
|
-
*
|
|
418
|
-
* @param resolve
|
|
419
|
-
* @param reject
|
|
420
|
-
* @param rlKey
|
|
421
|
-
* @param changedPoints
|
|
422
|
-
* @param storeResult
|
|
423
|
-
* @param {Object} options
|
|
424
|
-
* @private
|
|
425
|
-
*/
|
|
426
|
-
_afterConsume(resolve, reject, rlKey, changedPoints, storeResult, options = {}) {
|
|
427
|
-
const res = this._getRateLimiterRes(rlKey, changedPoints, storeResult);
|
|
428
|
-
if (this.inMemoryBlockOnConsumed > 0 && !(this.inMemoryBlockDuration > 0) && res.consumedPoints >= this.inMemoryBlockOnConsumed) {
|
|
429
|
-
this._inMemoryBlockedKeys.addMs(rlKey, res.msBeforeNext);
|
|
430
|
-
if (res.consumedPoints > this.points) {
|
|
431
|
-
return reject(res);
|
|
432
|
-
} else {
|
|
433
|
-
return resolve(res);
|
|
434
|
-
}
|
|
435
|
-
} else if (res.consumedPoints > this.points) {
|
|
436
|
-
let blockPromise = Promise.resolve();
|
|
437
|
-
if (this.blockDuration > 0 && res.consumedPoints <= this.points + changedPoints) {
|
|
438
|
-
res.msBeforeNext = this.msBlockDuration;
|
|
439
|
-
blockPromise = this._block(rlKey, res.consumedPoints, this.msBlockDuration, options);
|
|
440
|
-
}
|
|
441
|
-
if (this.inMemoryBlockOnConsumed > 0 && res.consumedPoints >= this.inMemoryBlockOnConsumed) {
|
|
442
|
-
this._inMemoryBlockedKeys.add(rlKey, this.inMemoryBlockDuration);
|
|
443
|
-
res.msBeforeNext = this.msInMemoryBlockDuration;
|
|
444
|
-
}
|
|
445
|
-
blockPromise.then(() => {
|
|
446
|
-
reject(res);
|
|
447
|
-
}).catch((err) => {
|
|
448
|
-
reject(err);
|
|
449
|
-
});
|
|
450
|
-
} else if (this.execEvenly && res.msBeforeNext > 0 && !res.isFirstInDuration) {
|
|
451
|
-
let delay = Math.ceil(res.msBeforeNext / (res.remainingPoints + 2));
|
|
452
|
-
if (delay < this.execEvenlyMinDelayMs) {
|
|
453
|
-
delay = res.consumedPoints * this.execEvenlyMinDelayMs;
|
|
454
|
-
}
|
|
455
|
-
setTimeout(resolve, delay, res);
|
|
456
|
-
} else {
|
|
457
|
-
resolve(res);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
getInMemoryBlockMsBeforeExpire(rlKey) {
|
|
461
|
-
if (this.inMemoryBlockOnConsumed > 0) {
|
|
462
|
-
return this._inMemoryBlockedKeys.msBeforeExpire(rlKey);
|
|
463
|
-
}
|
|
464
|
-
return 0;
|
|
465
|
-
}
|
|
466
|
-
get inMemoryBlockOnConsumed() {
|
|
467
|
-
return this._inMemoryBlockOnConsumed;
|
|
468
|
-
}
|
|
469
|
-
set inMemoryBlockOnConsumed(value) {
|
|
470
|
-
this._inMemoryBlockOnConsumed = value ? parseInt(value) : 0;
|
|
471
|
-
if (this.inMemoryBlockOnConsumed > 0 && this.points > this.inMemoryBlockOnConsumed) {
|
|
472
|
-
throw new Error('inMemoryBlockOnConsumed option must be greater or equal "points" option');
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
get inMemoryBlockDuration() {
|
|
476
|
-
return this._inMemoryBlockDuration;
|
|
477
|
-
}
|
|
478
|
-
set inMemoryBlockDuration(value) {
|
|
479
|
-
this._inMemoryBlockDuration = value ? parseInt(value) : 0;
|
|
480
|
-
if (this.inMemoryBlockDuration > 0 && this.inMemoryBlockOnConsumed === 0) {
|
|
481
|
-
throw new Error("inMemoryBlockOnConsumed option must be set up");
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
get msInMemoryBlockDuration() {
|
|
485
|
-
return this._inMemoryBlockDuration * 1e3;
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Block any key for secDuration seconds
|
|
489
|
-
*
|
|
490
|
-
* @param key
|
|
491
|
-
* @param secDuration
|
|
492
|
-
* @param {Object} options
|
|
493
|
-
*
|
|
494
|
-
* @return Promise<RateLimiterRes>
|
|
495
|
-
*/
|
|
496
|
-
block(key, secDuration, options = {}) {
|
|
497
|
-
const msDuration = secDuration * 1e3;
|
|
498
|
-
return this._block(this.getKey(key), this.points + 1, msDuration, options);
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Set points by key for any duration
|
|
502
|
-
*
|
|
503
|
-
* @param key
|
|
504
|
-
* @param points
|
|
505
|
-
* @param secDuration
|
|
506
|
-
* @param {Object} options
|
|
507
|
-
*
|
|
508
|
-
* @return Promise<RateLimiterRes>
|
|
509
|
-
*/
|
|
510
|
-
set(key, points, secDuration, options = {}) {
|
|
511
|
-
const msDuration = (secDuration >= 0 ? secDuration : this.duration) * 1e3;
|
|
512
|
-
return this._block(this.getKey(key), points, msDuration, options);
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
*
|
|
516
|
-
* @param key
|
|
517
|
-
* @param pointsToConsume
|
|
518
|
-
* @param {Object} options
|
|
519
|
-
* @returns Promise<RateLimiterRes>
|
|
520
|
-
*/
|
|
521
|
-
_consume(key, pointsToConsume = 1, options = {}) {
|
|
522
|
-
return new Promise((resolve, reject) => {
|
|
523
|
-
const rlKey = this.getKey(key);
|
|
524
|
-
const inMemoryBlockMsBeforeExpire = this.getInMemoryBlockMsBeforeExpire(rlKey);
|
|
525
|
-
if (inMemoryBlockMsBeforeExpire > 0) {
|
|
526
|
-
return reject(new RateLimiterRes2(0, inMemoryBlockMsBeforeExpire));
|
|
527
|
-
}
|
|
528
|
-
this._upsert(rlKey, pointsToConsume, this._getKeySecDuration(options) * 1e3, false, options).then((res) => {
|
|
529
|
-
this._afterConsume(resolve, reject, rlKey, pointsToConsume, res);
|
|
530
|
-
}).catch((err) => reject(err));
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
*
|
|
535
|
-
* @param key
|
|
536
|
-
* @param points
|
|
537
|
-
* @param {Object} options
|
|
538
|
-
* @returns Promise<RateLimiterRes>
|
|
539
|
-
*/
|
|
540
|
-
_penalty(key, points = 1, options = {}) {
|
|
541
|
-
const rlKey = this.getKey(key);
|
|
542
|
-
return new Promise((resolve, reject) => {
|
|
543
|
-
this._upsert(rlKey, points, this._getKeySecDuration(options) * 1e3, false, options).then((res) => {
|
|
544
|
-
resolve(this._getRateLimiterRes(rlKey, points, res));
|
|
545
|
-
}).catch((res) => reject(res));
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
*
|
|
550
|
-
* @param key
|
|
551
|
-
* @param points
|
|
552
|
-
* @param {Object} options
|
|
553
|
-
* @returns Promise<RateLimiterRes>
|
|
554
|
-
*/
|
|
555
|
-
_reward(key, points = 1, options = {}) {
|
|
556
|
-
const rlKey = this.getKey(key);
|
|
557
|
-
return new Promise((resolve, reject) => {
|
|
558
|
-
this._upsert(rlKey, -points, this._getKeySecDuration(options) * 1e3, false, options).then((res) => {
|
|
559
|
-
resolve(this._getRateLimiterRes(rlKey, -points, res));
|
|
560
|
-
}).catch((res) => reject(res));
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
*
|
|
565
|
-
* @param key
|
|
566
|
-
* @param {Object} options
|
|
567
|
-
* @returns Promise<RateLimiterRes>|null
|
|
568
|
-
*/
|
|
569
|
-
get(key, options = {}) {
|
|
570
|
-
const rlKey = this.getKey(key);
|
|
571
|
-
return new Promise((resolve, reject) => {
|
|
572
|
-
this._get(rlKey, options).then((res) => {
|
|
573
|
-
if (res === null || typeof res === "undefined") {
|
|
574
|
-
resolve(null);
|
|
575
|
-
} else {
|
|
576
|
-
resolve(this._getRateLimiterRes(rlKey, 0, res));
|
|
577
|
-
}
|
|
578
|
-
}).catch((err) => {
|
|
579
|
-
this._handleError(err, "get", resolve, reject, [key, options]);
|
|
580
|
-
});
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
*
|
|
585
|
-
* @param key
|
|
586
|
-
* @param {Object} options
|
|
587
|
-
* @returns Promise<boolean>
|
|
588
|
-
*/
|
|
589
|
-
delete(key, options = {}) {
|
|
590
|
-
const rlKey = this.getKey(key);
|
|
591
|
-
return new Promise((resolve, reject) => {
|
|
592
|
-
this._delete(rlKey, options).then((res) => {
|
|
593
|
-
this._inMemoryBlockedKeys.delete(rlKey);
|
|
594
|
-
resolve(res);
|
|
595
|
-
}).catch((err) => {
|
|
596
|
-
this._handleError(err, "delete", resolve, reject, [key, options]);
|
|
597
|
-
});
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Cleanup keys no-matter expired or not.
|
|
602
|
-
*/
|
|
603
|
-
deleteInMemoryBlockedAll() {
|
|
604
|
-
this._inMemoryBlockedKeys.delete();
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* Get RateLimiterRes object filled depending on storeResult, which specific for exact store
|
|
608
|
-
*
|
|
609
|
-
* @param rlKey
|
|
610
|
-
* @param changedPoints
|
|
611
|
-
* @param storeResult
|
|
612
|
-
* @private
|
|
613
|
-
*/
|
|
614
|
-
_getRateLimiterRes(rlKey, changedPoints, storeResult) {
|
|
615
|
-
throw new Error("You have to implement the method '_getRateLimiterRes'!");
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Block key for this.msBlockDuration milliseconds
|
|
619
|
-
* Usually, it just prolongs lifetime of key
|
|
620
|
-
*
|
|
621
|
-
* @param rlKey
|
|
622
|
-
* @param initPoints
|
|
623
|
-
* @param msDuration
|
|
624
|
-
* @param {Object} options
|
|
625
|
-
*
|
|
626
|
-
* @return Promise<any>
|
|
627
|
-
*/
|
|
628
|
-
_block(rlKey, initPoints, msDuration, options = {}) {
|
|
629
|
-
return new Promise((resolve, reject) => {
|
|
630
|
-
this._upsert(rlKey, initPoints, msDuration, true, options).then(() => {
|
|
631
|
-
resolve(new RateLimiterRes2(0, msDuration > 0 ? msDuration : -1, initPoints));
|
|
632
|
-
}).catch((err) => {
|
|
633
|
-
this._handleError(err, "block", resolve, reject, [this.parseKey(rlKey), msDuration / 1e3, options]);
|
|
634
|
-
});
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
/**
|
|
638
|
-
* Have to be implemented in every limiter
|
|
639
|
-
* Resolve with raw result from Store OR null if rlKey is not set
|
|
640
|
-
* or Reject with error
|
|
641
|
-
*
|
|
642
|
-
* @param rlKey
|
|
643
|
-
* @param {Object} options
|
|
644
|
-
* @private
|
|
645
|
-
*
|
|
646
|
-
* @return Promise<any>
|
|
647
|
-
*/
|
|
648
|
-
_get(rlKey, options = {}) {
|
|
649
|
-
throw new Error("You have to implement the method '_get'!");
|
|
650
|
-
}
|
|
651
|
-
/**
|
|
652
|
-
* Have to be implemented
|
|
653
|
-
* Resolve with true OR false if rlKey doesn't exist
|
|
654
|
-
* or Reject with error
|
|
655
|
-
*
|
|
656
|
-
* @param rlKey
|
|
657
|
-
* @param {Object} options
|
|
658
|
-
* @private
|
|
659
|
-
*
|
|
660
|
-
* @return Promise<any>
|
|
661
|
-
*/
|
|
662
|
-
_delete(rlKey, options = {}) {
|
|
663
|
-
throw new Error("You have to implement the method '_delete'!");
|
|
664
|
-
}
|
|
665
|
-
/**
|
|
666
|
-
* Have to be implemented
|
|
667
|
-
* Resolve with object used for {@link _getRateLimiterRes} to generate {@link RateLimiterRes}
|
|
668
|
-
*
|
|
669
|
-
* @param {string} rlKey
|
|
670
|
-
* @param {number} points
|
|
671
|
-
* @param {number} msDuration
|
|
672
|
-
* @param {boolean} forceExpire
|
|
673
|
-
* @param {Object} options
|
|
674
|
-
* @abstract
|
|
675
|
-
*
|
|
676
|
-
* @return Promise<Object>
|
|
677
|
-
*/
|
|
678
|
-
_upsert(rlKey, points, msDuration, forceExpire = false, options = {}) {
|
|
679
|
-
throw new Error("You have to implement the method '_upsert'!");
|
|
680
|
-
}
|
|
681
|
-
};
|
|
682
|
-
}
|
|
683
|
-
});
|
|
684
|
-
|
|
685
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterRedis.js
|
|
686
|
-
var require_RateLimiterRedis = __commonJS({
|
|
687
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterRedis.js"(exports2, module2) {
|
|
688
|
-
"use strict";
|
|
689
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
690
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
691
|
-
var incrTtlLuaScript = `redis.call('set', KEYS[1], 0, 'EX', ARGV[2], 'NX') local consumed = redis.call('incrby', KEYS[1], ARGV[1]) local ttl = redis.call('pttl', KEYS[1]) if ttl == -1 then redis.call('expire', KEYS[1], ARGV[2]) ttl = 1000 * ARGV[2] end return {consumed, ttl} `;
|
|
692
|
-
var RateLimiterRedis = class extends RateLimiterStoreAbstract {
|
|
693
|
-
/**
|
|
694
|
-
*
|
|
695
|
-
* @param {Object} opts
|
|
696
|
-
* Defaults {
|
|
697
|
-
* ... see other in RateLimiterStoreAbstract
|
|
698
|
-
*
|
|
699
|
-
* redis: RedisClient
|
|
700
|
-
* rejectIfRedisNotReady: boolean = false - reject / invoke insuranceLimiter immediately when redis connection is not "ready"
|
|
701
|
-
* }
|
|
702
|
-
*/
|
|
703
|
-
constructor(opts) {
|
|
704
|
-
super(opts);
|
|
705
|
-
this.client = opts.storeClient;
|
|
706
|
-
this._rejectIfRedisNotReady = !!opts.rejectIfRedisNotReady;
|
|
707
|
-
this._incrTtlLuaScript = opts.customIncrTtlLuaScript || incrTtlLuaScript;
|
|
708
|
-
this.useRedisPackage = opts.useRedisPackage || this.client.constructor.name === "Commander" || false;
|
|
709
|
-
this.useRedis3AndLowerPackage = opts.useRedis3AndLowerPackage;
|
|
710
|
-
if (typeof this.client.defineCommand === "function") {
|
|
711
|
-
this.client.defineCommand("rlflxIncr", {
|
|
712
|
-
numberOfKeys: 1,
|
|
713
|
-
lua: this._incrTtlLuaScript
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
/**
|
|
718
|
-
* Prevent actual redis call if redis connection is not ready
|
|
719
|
-
* Because of different connection state checks for ioredis and node-redis, only this clients would be actually checked.
|
|
720
|
-
* For any other clients all the requests would be passed directly to redis client
|
|
721
|
-
* @param {String} rlKey
|
|
722
|
-
* @param {Boolean} isReadonly
|
|
723
|
-
* @return {boolean}
|
|
724
|
-
* @private
|
|
725
|
-
*/
|
|
726
|
-
_isRedisReady(rlKey, isReadonly) {
|
|
727
|
-
if (!this._rejectIfRedisNotReady) {
|
|
728
|
-
return true;
|
|
729
|
-
}
|
|
730
|
-
if (this.client.status) {
|
|
731
|
-
return this.client.status === "ready";
|
|
732
|
-
}
|
|
733
|
-
if (typeof this.client.isReady === "function") {
|
|
734
|
-
return this.client.isReady();
|
|
735
|
-
}
|
|
736
|
-
if (typeof this.client.isReady === "boolean") {
|
|
737
|
-
return this.client.isReady === true;
|
|
738
|
-
}
|
|
739
|
-
if (this.client._slots && typeof this.client._slots.getClient === "function") {
|
|
740
|
-
if (typeof this.client.isOpen === "boolean" && this.client.isOpen !== true) {
|
|
741
|
-
return false;
|
|
742
|
-
}
|
|
743
|
-
try {
|
|
744
|
-
const slotClient = this.client._slots.getClient(rlKey, isReadonly);
|
|
745
|
-
return slotClient && slotClient.isReady === true;
|
|
746
|
-
} catch (error48) {
|
|
747
|
-
return false;
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
return true;
|
|
751
|
-
}
|
|
752
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
753
|
-
let [consumed, resTtlMs] = result;
|
|
754
|
-
if (Array.isArray(consumed)) {
|
|
755
|
-
[, consumed] = consumed;
|
|
756
|
-
[, resTtlMs] = resTtlMs;
|
|
757
|
-
}
|
|
758
|
-
const res = new RateLimiterRes2();
|
|
759
|
-
res.consumedPoints = parseInt(consumed);
|
|
760
|
-
res.isFirstInDuration = res.consumedPoints === changedPoints;
|
|
761
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
762
|
-
res.msBeforeNext = resTtlMs;
|
|
763
|
-
return res;
|
|
764
|
-
}
|
|
765
|
-
async _upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
766
|
-
if (typeof points == "string") {
|
|
767
|
-
if (!RegExp("^[1-9][0-9]*$").test(points)) {
|
|
768
|
-
throw new Error("Consuming string different than integer values is not supported by this package");
|
|
769
|
-
}
|
|
770
|
-
} else if (!Number.isInteger(points)) {
|
|
771
|
-
throw new Error("Consuming decimal number of points is not supported by this package");
|
|
772
|
-
}
|
|
773
|
-
if (!this._isRedisReady(rlKey, false)) {
|
|
774
|
-
throw new Error("Redis connection is not ready");
|
|
775
|
-
}
|
|
776
|
-
const secDuration = Math.floor(msDuration / 1e3);
|
|
777
|
-
const multi = this.client.multi();
|
|
778
|
-
if (forceExpire) {
|
|
779
|
-
if (secDuration > 0) {
|
|
780
|
-
if (!this.useRedisPackage && !this.useRedis3AndLowerPackage) {
|
|
781
|
-
multi.set(rlKey, points, "EX", secDuration);
|
|
782
|
-
} else {
|
|
783
|
-
multi.set(rlKey, points, { EX: secDuration });
|
|
784
|
-
}
|
|
785
|
-
} else {
|
|
786
|
-
multi.set(rlKey, points);
|
|
787
|
-
}
|
|
788
|
-
if (!this.useRedisPackage && !this.useRedis3AndLowerPackage) {
|
|
789
|
-
return multi.pttl(rlKey).exec(true);
|
|
790
|
-
}
|
|
791
|
-
return multi.pTTL(rlKey).exec(true);
|
|
792
|
-
}
|
|
793
|
-
if (secDuration > 0) {
|
|
794
|
-
if (!this.useRedisPackage && !this.useRedis3AndLowerPackage) {
|
|
795
|
-
return this.client.rlflxIncr(
|
|
796
|
-
[rlKey].concat([String(points), String(secDuration), String(this.points), String(this.duration)])
|
|
797
|
-
);
|
|
798
|
-
}
|
|
799
|
-
if (this.useRedis3AndLowerPackage) {
|
|
800
|
-
return new Promise((resolve, reject) => {
|
|
801
|
-
const incrCallback = function(err, result) {
|
|
802
|
-
if (err) {
|
|
803
|
-
return reject(err);
|
|
804
|
-
}
|
|
805
|
-
return resolve(result);
|
|
806
|
-
};
|
|
807
|
-
if (typeof this.client.rlflxIncr === "function") {
|
|
808
|
-
this.client.rlflxIncr(rlKey, points, secDuration, this.points, this.duration, incrCallback);
|
|
809
|
-
} else {
|
|
810
|
-
this.client.eval(this._incrTtlLuaScript, 1, rlKey, points, secDuration, this.points, this.duration, incrCallback);
|
|
811
|
-
}
|
|
812
|
-
});
|
|
813
|
-
} else {
|
|
814
|
-
return this.client.eval(this._incrTtlLuaScript, {
|
|
815
|
-
keys: [rlKey],
|
|
816
|
-
arguments: [String(points), String(secDuration), String(this.points), String(this.duration)]
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
} else {
|
|
820
|
-
if (!this.useRedisPackage && !this.useRedis3AndLowerPackage) {
|
|
821
|
-
return multi.incrby(rlKey, points).pttl(rlKey).exec(true);
|
|
822
|
-
}
|
|
823
|
-
return multi.incrBy(rlKey, points).pTTL(rlKey).exec(true);
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
async _get(rlKey) {
|
|
827
|
-
if (!this._isRedisReady(rlKey, true)) {
|
|
828
|
-
throw new Error("Redis connection is not ready");
|
|
829
|
-
}
|
|
830
|
-
if (!this.useRedisPackage && !this.useRedis3AndLowerPackage) {
|
|
831
|
-
return this.client.multi().get(rlKey).pttl(rlKey).exec().then((result) => {
|
|
832
|
-
const [[, points]] = result;
|
|
833
|
-
if (points === null) return null;
|
|
834
|
-
return result;
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
return this.client.multi().get(rlKey).pTTL(rlKey).exec(true).then((result) => {
|
|
838
|
-
const [points] = result;
|
|
839
|
-
if (points === null) return null;
|
|
840
|
-
return result;
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
_delete(rlKey) {
|
|
844
|
-
return this.client.del(rlKey).then((result) => result > 0);
|
|
845
|
-
}
|
|
846
|
-
};
|
|
847
|
-
module2.exports = RateLimiterRedis;
|
|
848
|
-
}
|
|
849
|
-
});
|
|
850
|
-
|
|
851
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterRedisNonAtomic.js
|
|
852
|
-
var require_RateLimiterRedisNonAtomic = __commonJS({
|
|
853
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterRedisNonAtomic.js"(exports2, module2) {
|
|
854
|
-
"use strict";
|
|
855
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
856
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
857
|
-
var RateLimiterRedisNonAtomic = class extends RateLimiterStoreAbstract {
|
|
858
|
-
constructor(opts) {
|
|
859
|
-
super(opts);
|
|
860
|
-
this.client = opts.storeClient;
|
|
861
|
-
this._rejectIfRedisNotReady = !!opts.rejectIfRedisNotReady;
|
|
862
|
-
this.useRedisPackage = opts.useRedisPackage || this.client.constructor.name === "Commander" || false;
|
|
863
|
-
}
|
|
864
|
-
_isRedisReady(rlKey, isReadonly) {
|
|
865
|
-
if (!this._rejectIfRedisNotReady) {
|
|
866
|
-
return true;
|
|
867
|
-
}
|
|
868
|
-
if (this.client.status) {
|
|
869
|
-
return this.client.status === "ready";
|
|
870
|
-
}
|
|
871
|
-
if (typeof this.client.isReady === "function") {
|
|
872
|
-
return this.client.isReady();
|
|
873
|
-
}
|
|
874
|
-
if (typeof this.client.isReady === "boolean") {
|
|
875
|
-
return this.client.isReady === true;
|
|
876
|
-
}
|
|
877
|
-
if (this.client._slots && typeof this.client._slots.getClient === "function") {
|
|
878
|
-
if (typeof this.client.isOpen === "boolean" && this.client.isOpen !== true) {
|
|
879
|
-
return false;
|
|
880
|
-
}
|
|
881
|
-
try {
|
|
882
|
-
const slotClient = this.client._slots.getClient(rlKey, isReadonly);
|
|
883
|
-
return slotClient && slotClient.isReady === true;
|
|
884
|
-
} catch (error48) {
|
|
885
|
-
return false;
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
return true;
|
|
889
|
-
}
|
|
890
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
891
|
-
let [consumed, resTtlMs] = result;
|
|
892
|
-
if (Array.isArray(consumed)) {
|
|
893
|
-
[, consumed] = consumed;
|
|
894
|
-
[, resTtlMs] = resTtlMs;
|
|
895
|
-
}
|
|
896
|
-
const res = new RateLimiterRes2();
|
|
897
|
-
res.consumedPoints = parseInt(consumed);
|
|
898
|
-
res.isFirstInDuration = res.consumedPoints === changedPoints;
|
|
899
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
900
|
-
res.msBeforeNext = resTtlMs;
|
|
901
|
-
return res;
|
|
902
|
-
}
|
|
903
|
-
_parseStoreResult(result) {
|
|
904
|
-
let points;
|
|
905
|
-
let ttlMs;
|
|
906
|
-
if (Array.isArray(result[0])) {
|
|
907
|
-
[, points] = result[0];
|
|
908
|
-
[, ttlMs] = result[1];
|
|
909
|
-
} else {
|
|
910
|
-
[points, ttlMs] = result;
|
|
911
|
-
}
|
|
912
|
-
return {
|
|
913
|
-
points: parseInt(points, 10),
|
|
914
|
-
ttlMs
|
|
915
|
-
};
|
|
916
|
-
}
|
|
917
|
-
_execMulti(multi) {
|
|
918
|
-
return multi.exec();
|
|
919
|
-
}
|
|
920
|
-
_setKey(rlKey, points, secDuration) {
|
|
921
|
-
const multi = this.client.multi();
|
|
922
|
-
if (secDuration > 0) {
|
|
923
|
-
if (!this.useRedisPackage) {
|
|
924
|
-
multi.set(rlKey, points, "EX", secDuration);
|
|
925
|
-
} else {
|
|
926
|
-
multi.set(rlKey, points, { EX: secDuration });
|
|
927
|
-
}
|
|
928
|
-
} else {
|
|
929
|
-
multi.set(rlKey, points);
|
|
930
|
-
}
|
|
931
|
-
return this._execMulti(multi);
|
|
932
|
-
}
|
|
933
|
-
_setKeyWithTtlMs(rlKey, points, ttlMs) {
|
|
934
|
-
const multi = this.client.multi();
|
|
935
|
-
multi.set(rlKey, points);
|
|
936
|
-
if (ttlMs > 0) {
|
|
937
|
-
if (!this.useRedisPackage) {
|
|
938
|
-
multi.pexpire(rlKey, ttlMs);
|
|
939
|
-
} else {
|
|
940
|
-
multi.pExpire(rlKey, ttlMs);
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
return this._execMulti(multi);
|
|
944
|
-
}
|
|
945
|
-
async _upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
946
|
-
if (typeof points == "string") {
|
|
947
|
-
if (!RegExp("^[1-9][0-9]*$").test(points)) {
|
|
948
|
-
throw new Error("Consuming string different than integer values is not supported by this package");
|
|
949
|
-
}
|
|
950
|
-
} else if (!Number.isInteger(points)) {
|
|
951
|
-
throw new Error("Consuming decimal number of points is not supported by this package");
|
|
952
|
-
}
|
|
953
|
-
if (!this._isRedisReady(rlKey, false)) {
|
|
954
|
-
throw new Error("Redis connection is not ready");
|
|
955
|
-
}
|
|
956
|
-
const parsedPoints = typeof points === "string" ? parseInt(points, 10) : points;
|
|
957
|
-
const secDuration = Math.floor(msDuration / 1e3);
|
|
958
|
-
if (forceExpire) {
|
|
959
|
-
await this._setKey(rlKey, parsedPoints, secDuration);
|
|
960
|
-
return [parsedPoints, secDuration > 0 ? secDuration * 1e3 : -1];
|
|
961
|
-
}
|
|
962
|
-
const currentResult = await this._get(rlKey);
|
|
963
|
-
const hasCurrent = currentResult !== null;
|
|
964
|
-
const current = hasCurrent ? this._parseStoreResult(currentResult) : { points: 0, ttlMs: -1 };
|
|
965
|
-
const newPoints = current.points + parsedPoints;
|
|
966
|
-
if (secDuration > 0) {
|
|
967
|
-
if (!hasCurrent) {
|
|
968
|
-
await this._setKey(rlKey, newPoints, secDuration);
|
|
969
|
-
return [newPoints, secDuration * 1e3];
|
|
970
|
-
}
|
|
971
|
-
if (current.ttlMs <= 0) {
|
|
972
|
-
await this._setKey(rlKey, newPoints, secDuration);
|
|
973
|
-
return [newPoints, secDuration * 1e3];
|
|
974
|
-
}
|
|
975
|
-
await this._setKeyWithTtlMs(rlKey, newPoints, current.ttlMs);
|
|
976
|
-
return [newPoints, current.ttlMs];
|
|
977
|
-
}
|
|
978
|
-
await this._setKey(rlKey, newPoints, 0);
|
|
979
|
-
return [newPoints, -1];
|
|
980
|
-
}
|
|
981
|
-
async _get(rlKey) {
|
|
982
|
-
if (!this._isRedisReady(rlKey, true)) {
|
|
983
|
-
throw new Error("Redis connection is not ready");
|
|
984
|
-
}
|
|
985
|
-
const multi = this.client.multi().get(rlKey);
|
|
986
|
-
if (!this.useRedisPackage) {
|
|
987
|
-
multi.pttl(rlKey);
|
|
988
|
-
} else {
|
|
989
|
-
multi.pTTL(rlKey);
|
|
990
|
-
}
|
|
991
|
-
return this._execMulti(multi).then((result) => {
|
|
992
|
-
if (Array.isArray(result[0])) {
|
|
993
|
-
const [, points2] = result[0];
|
|
994
|
-
if (points2 === null) return null;
|
|
995
|
-
return result;
|
|
996
|
-
}
|
|
997
|
-
const [points] = result;
|
|
998
|
-
if (points === null) return null;
|
|
999
|
-
return result;
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1002
|
-
_delete(rlKey) {
|
|
1003
|
-
return this.client.del(rlKey).then((result) => result > 0);
|
|
1004
|
-
}
|
|
1005
|
-
};
|
|
1006
|
-
module2.exports = RateLimiterRedisNonAtomic;
|
|
1007
|
-
}
|
|
1008
|
-
});
|
|
1009
|
-
|
|
1010
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterMongo.js
|
|
1011
|
-
var require_RateLimiterMongo = __commonJS({
|
|
1012
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterMongo.js"(exports2, module2) {
|
|
1013
|
-
"use strict";
|
|
1014
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
1015
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
1016
|
-
var RateLimiterMongo = class _RateLimiterMongo extends RateLimiterStoreAbstract {
|
|
1017
|
-
/**
|
|
1018
|
-
*
|
|
1019
|
-
* @param {Object} opts
|
|
1020
|
-
* Defaults {
|
|
1021
|
-
* indexKeyPrefix: {attr1: 1, attr2: 1}
|
|
1022
|
-
* ... see other in RateLimiterStoreAbstract
|
|
1023
|
-
*
|
|
1024
|
-
* mongo: MongoClient
|
|
1025
|
-
* }
|
|
1026
|
-
*/
|
|
1027
|
-
constructor(opts) {
|
|
1028
|
-
super(opts);
|
|
1029
|
-
this.dbName = opts.dbName;
|
|
1030
|
-
this.tableName = opts.tableName;
|
|
1031
|
-
this.indexKeyPrefix = opts.indexKeyPrefix;
|
|
1032
|
-
this.disableIndexesCreation = opts.disableIndexesCreation;
|
|
1033
|
-
if (opts.mongo) {
|
|
1034
|
-
this.client = opts.mongo;
|
|
1035
|
-
} else {
|
|
1036
|
-
this.client = opts.storeClient;
|
|
1037
|
-
}
|
|
1038
|
-
if (typeof this.client.then === "function") {
|
|
1039
|
-
this.client.then((conn) => {
|
|
1040
|
-
this.client = conn;
|
|
1041
|
-
this._initCollection();
|
|
1042
|
-
});
|
|
1043
|
-
} else {
|
|
1044
|
-
this._initCollection();
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
get dbName() {
|
|
1048
|
-
return this._dbName;
|
|
1049
|
-
}
|
|
1050
|
-
set dbName(value) {
|
|
1051
|
-
this._dbName = typeof value === "undefined" ? _RateLimiterMongo.getDbName() : value;
|
|
1052
|
-
}
|
|
1053
|
-
static getDbName() {
|
|
1054
|
-
return "node-rate-limiter-flexible";
|
|
1055
|
-
}
|
|
1056
|
-
get tableName() {
|
|
1057
|
-
return this._tableName;
|
|
1058
|
-
}
|
|
1059
|
-
set tableName(value) {
|
|
1060
|
-
this._tableName = typeof value === "undefined" ? this.keyPrefix : value;
|
|
1061
|
-
}
|
|
1062
|
-
get client() {
|
|
1063
|
-
return this._client;
|
|
1064
|
-
}
|
|
1065
|
-
set client(value) {
|
|
1066
|
-
if (typeof value === "undefined") {
|
|
1067
|
-
throw new Error("mongo is not set");
|
|
1068
|
-
}
|
|
1069
|
-
this._client = value;
|
|
1070
|
-
}
|
|
1071
|
-
get indexKeyPrefix() {
|
|
1072
|
-
return this._indexKeyPrefix;
|
|
1073
|
-
}
|
|
1074
|
-
set indexKeyPrefix(obj) {
|
|
1075
|
-
this._indexKeyPrefix = obj || {};
|
|
1076
|
-
}
|
|
1077
|
-
get disableIndexesCreation() {
|
|
1078
|
-
return this._disableIndexesCreation;
|
|
1079
|
-
}
|
|
1080
|
-
set disableIndexesCreation(value) {
|
|
1081
|
-
this._disableIndexesCreation = !!value;
|
|
1082
|
-
}
|
|
1083
|
-
async createIndexes() {
|
|
1084
|
-
const db = typeof this.client.db === "function" ? this.client.db(this.dbName) : this.client;
|
|
1085
|
-
const collection = db.collection(this.tableName);
|
|
1086
|
-
await collection.createIndex({ expire: -1 }, { expireAfterSeconds: 0 });
|
|
1087
|
-
await collection.createIndex(Object.assign({}, this.indexKeyPrefix, { key: 1 }), { unique: true });
|
|
1088
|
-
}
|
|
1089
|
-
_initCollection() {
|
|
1090
|
-
const db = typeof this.client.db === "function" ? this.client.db(this.dbName) : this.client;
|
|
1091
|
-
const collection = db.collection(this.tableName);
|
|
1092
|
-
if (!this.disableIndexesCreation) {
|
|
1093
|
-
this.createIndexes().catch((err) => {
|
|
1094
|
-
console.error(`Cannot create indexes for mongo collection ${this.tableName}`, err);
|
|
1095
|
-
});
|
|
1096
|
-
}
|
|
1097
|
-
this._collection = collection;
|
|
1098
|
-
}
|
|
1099
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
1100
|
-
const res = new RateLimiterRes2();
|
|
1101
|
-
let doc;
|
|
1102
|
-
if (typeof result.value === "undefined") {
|
|
1103
|
-
doc = result;
|
|
1104
|
-
} else {
|
|
1105
|
-
doc = result.value;
|
|
1106
|
-
}
|
|
1107
|
-
res.isFirstInDuration = doc.points === changedPoints;
|
|
1108
|
-
res.consumedPoints = doc.points;
|
|
1109
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
1110
|
-
res.msBeforeNext = doc.expire !== null ? Math.max(new Date(doc.expire).getTime() - Date.now(), 0) : -1;
|
|
1111
|
-
return res;
|
|
1112
|
-
}
|
|
1113
|
-
_upsert(key, points, msDuration, forceExpire = false, options = {}) {
|
|
1114
|
-
if (!this._collection) {
|
|
1115
|
-
return Promise.reject(Error("Mongo connection is not established"));
|
|
1116
|
-
}
|
|
1117
|
-
const docAttrs = options.attrs || {};
|
|
1118
|
-
let where;
|
|
1119
|
-
let upsertData;
|
|
1120
|
-
if (forceExpire) {
|
|
1121
|
-
where = { key };
|
|
1122
|
-
where = Object.assign(where, docAttrs);
|
|
1123
|
-
upsertData = {
|
|
1124
|
-
$set: {
|
|
1125
|
-
key,
|
|
1126
|
-
points,
|
|
1127
|
-
expire: msDuration > 0 ? new Date(Date.now() + msDuration) : null
|
|
1128
|
-
}
|
|
1129
|
-
};
|
|
1130
|
-
upsertData.$set = Object.assign(upsertData.$set, docAttrs);
|
|
1131
|
-
} else {
|
|
1132
|
-
where = {
|
|
1133
|
-
$or: [
|
|
1134
|
-
{ expire: { $gt: /* @__PURE__ */ new Date() } },
|
|
1135
|
-
{ expire: { $eq: null } }
|
|
1136
|
-
],
|
|
1137
|
-
key
|
|
1138
|
-
};
|
|
1139
|
-
where = Object.assign(where, docAttrs);
|
|
1140
|
-
upsertData = {
|
|
1141
|
-
$setOnInsert: {
|
|
1142
|
-
key,
|
|
1143
|
-
expire: msDuration > 0 ? new Date(Date.now() + msDuration) : null
|
|
1144
|
-
},
|
|
1145
|
-
$inc: { points }
|
|
1146
|
-
};
|
|
1147
|
-
upsertData.$setOnInsert = Object.assign(upsertData.$setOnInsert, docAttrs);
|
|
1148
|
-
}
|
|
1149
|
-
const upsertOptions = {
|
|
1150
|
-
upsert: true,
|
|
1151
|
-
returnDocument: "after"
|
|
1152
|
-
};
|
|
1153
|
-
return new Promise((resolve, reject) => {
|
|
1154
|
-
this._collection.findOneAndUpdate(
|
|
1155
|
-
where,
|
|
1156
|
-
upsertData,
|
|
1157
|
-
upsertOptions
|
|
1158
|
-
).then((res) => {
|
|
1159
|
-
resolve(res);
|
|
1160
|
-
}).catch((errUpsert) => {
|
|
1161
|
-
if (errUpsert && errUpsert.code === 11e3) {
|
|
1162
|
-
const replaceWhere = Object.assign({
|
|
1163
|
-
// try to replace OLD limit doc
|
|
1164
|
-
$or: [
|
|
1165
|
-
{ expire: { $lte: /* @__PURE__ */ new Date() } },
|
|
1166
|
-
{ expire: { $eq: null } }
|
|
1167
|
-
],
|
|
1168
|
-
key
|
|
1169
|
-
}, docAttrs);
|
|
1170
|
-
const replaceTo = {
|
|
1171
|
-
$set: Object.assign({
|
|
1172
|
-
key,
|
|
1173
|
-
points,
|
|
1174
|
-
expire: msDuration > 0 ? new Date(Date.now() + msDuration) : null
|
|
1175
|
-
}, docAttrs)
|
|
1176
|
-
};
|
|
1177
|
-
this._collection.findOneAndUpdate(
|
|
1178
|
-
replaceWhere,
|
|
1179
|
-
replaceTo,
|
|
1180
|
-
upsertOptions
|
|
1181
|
-
).then((res) => {
|
|
1182
|
-
resolve(res);
|
|
1183
|
-
}).catch((errReplace) => {
|
|
1184
|
-
if (errReplace && errReplace.code === 11e3) {
|
|
1185
|
-
this._upsert(key, points, msDuration, forceExpire).then((res) => resolve(res)).catch((err) => reject(err));
|
|
1186
|
-
} else {
|
|
1187
|
-
reject(errReplace);
|
|
1188
|
-
}
|
|
1189
|
-
});
|
|
1190
|
-
} else {
|
|
1191
|
-
reject(errUpsert);
|
|
1192
|
-
}
|
|
1193
|
-
});
|
|
1194
|
-
});
|
|
1195
|
-
}
|
|
1196
|
-
_get(rlKey, options = {}) {
|
|
1197
|
-
if (!this._collection) {
|
|
1198
|
-
return Promise.reject(Error("Mongo connection is not established"));
|
|
1199
|
-
}
|
|
1200
|
-
const docAttrs = options.attrs || {};
|
|
1201
|
-
const where = Object.assign({
|
|
1202
|
-
key: rlKey,
|
|
1203
|
-
$or: [
|
|
1204
|
-
{ expire: { $gt: /* @__PURE__ */ new Date() } },
|
|
1205
|
-
{ expire: { $eq: null } }
|
|
1206
|
-
]
|
|
1207
|
-
}, docAttrs);
|
|
1208
|
-
return this._collection.findOne(where);
|
|
1209
|
-
}
|
|
1210
|
-
_delete(rlKey, options = {}) {
|
|
1211
|
-
if (!this._collection) {
|
|
1212
|
-
return Promise.reject(Error("Mongo connection is not established"));
|
|
1213
|
-
}
|
|
1214
|
-
const docAttrs = options.attrs || {};
|
|
1215
|
-
const where = Object.assign({ key: rlKey }, docAttrs);
|
|
1216
|
-
return this._collection.deleteOne(where).then((res) => res.deletedCount > 0);
|
|
1217
|
-
}
|
|
1218
|
-
};
|
|
1219
|
-
module2.exports = RateLimiterMongo;
|
|
1220
|
-
}
|
|
1221
|
-
});
|
|
1222
|
-
|
|
1223
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterMySQL.js
|
|
1224
|
-
var require_RateLimiterMySQL = __commonJS({
|
|
1225
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterMySQL.js"(exports2, module2) {
|
|
1226
|
-
"use strict";
|
|
1227
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
1228
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
1229
|
-
var RateLimiterMySQL = class extends RateLimiterStoreAbstract {
|
|
1230
|
-
/**
|
|
1231
|
-
* @callback callback
|
|
1232
|
-
* @param {Object} err
|
|
1233
|
-
*
|
|
1234
|
-
* @param {Object} opts
|
|
1235
|
-
* @param {callback} cb
|
|
1236
|
-
* Defaults {
|
|
1237
|
-
* ... see other in RateLimiterStoreAbstract
|
|
1238
|
-
*
|
|
1239
|
-
* storeClient: anySqlClient,
|
|
1240
|
-
* storeType: 'knex', // required only for Knex instance
|
|
1241
|
-
* dbName: 'string',
|
|
1242
|
-
* tableName: 'string',
|
|
1243
|
-
* }
|
|
1244
|
-
*/
|
|
1245
|
-
constructor(opts, cb = null) {
|
|
1246
|
-
super(opts);
|
|
1247
|
-
this.client = opts.storeClient;
|
|
1248
|
-
this.clientType = opts.storeType;
|
|
1249
|
-
this.dbName = opts.dbName;
|
|
1250
|
-
this.tableName = opts.tableName;
|
|
1251
|
-
this.clearExpiredByTimeout = opts.clearExpiredByTimeout;
|
|
1252
|
-
this.tableCreated = opts.tableCreated;
|
|
1253
|
-
if (!this.tableCreated) {
|
|
1254
|
-
this._createDbAndTable().then(() => {
|
|
1255
|
-
this.tableCreated = true;
|
|
1256
|
-
if (this.clearExpiredByTimeout) {
|
|
1257
|
-
this._clearExpiredHourAgo();
|
|
1258
|
-
}
|
|
1259
|
-
if (typeof cb === "function") {
|
|
1260
|
-
cb();
|
|
1261
|
-
}
|
|
1262
|
-
}).catch((err) => {
|
|
1263
|
-
if (typeof cb === "function") {
|
|
1264
|
-
cb(err);
|
|
1265
|
-
} else {
|
|
1266
|
-
throw err;
|
|
1267
|
-
}
|
|
1268
|
-
});
|
|
1269
|
-
} else {
|
|
1270
|
-
if (this.clearExpiredByTimeout) {
|
|
1271
|
-
this._clearExpiredHourAgo();
|
|
1272
|
-
}
|
|
1273
|
-
if (typeof cb === "function") {
|
|
1274
|
-
cb();
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
clearExpired(expire) {
|
|
1279
|
-
return new Promise((resolve) => {
|
|
1280
|
-
this._getConnection().then((conn) => {
|
|
1281
|
-
conn.query(`DELETE FROM ??.?? WHERE expire < ?`, [this.dbName, this.tableName, expire], () => {
|
|
1282
|
-
this._releaseConnection(conn);
|
|
1283
|
-
resolve();
|
|
1284
|
-
});
|
|
1285
|
-
}).catch(() => {
|
|
1286
|
-
resolve();
|
|
1287
|
-
});
|
|
1288
|
-
});
|
|
1289
|
-
}
|
|
1290
|
-
_clearExpiredHourAgo() {
|
|
1291
|
-
if (this._clearExpiredTimeoutId) {
|
|
1292
|
-
clearTimeout(this._clearExpiredTimeoutId);
|
|
1293
|
-
}
|
|
1294
|
-
this._clearExpiredTimeoutId = setTimeout(() => {
|
|
1295
|
-
this.clearExpired(Date.now() - 36e5).then(() => {
|
|
1296
|
-
this._clearExpiredHourAgo();
|
|
1297
|
-
});
|
|
1298
|
-
}, 3e5);
|
|
1299
|
-
this._clearExpiredTimeoutId.unref();
|
|
1300
|
-
}
|
|
1301
|
-
/**
|
|
1302
|
-
*
|
|
1303
|
-
* @return Promise<any>
|
|
1304
|
-
* @private
|
|
1305
|
-
*/
|
|
1306
|
-
_getConnection() {
|
|
1307
|
-
switch (this.clientType) {
|
|
1308
|
-
case "pool":
|
|
1309
|
-
return new Promise((resolve, reject) => {
|
|
1310
|
-
this.client.getConnection((errConn, conn) => {
|
|
1311
|
-
if (errConn) {
|
|
1312
|
-
return reject(errConn);
|
|
1313
|
-
}
|
|
1314
|
-
resolve(conn);
|
|
1315
|
-
});
|
|
1316
|
-
});
|
|
1317
|
-
case "sequelize":
|
|
1318
|
-
return this._getSequelizeConnectionManager().getConnection();
|
|
1319
|
-
case "knex":
|
|
1320
|
-
return this.client.client.acquireConnection();
|
|
1321
|
-
default:
|
|
1322
|
-
return Promise.resolve(this.client);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
_releaseConnection(conn) {
|
|
1326
|
-
switch (this.clientType) {
|
|
1327
|
-
case "pool":
|
|
1328
|
-
return conn.release();
|
|
1329
|
-
case "sequelize":
|
|
1330
|
-
return this._getSequelizeConnectionManager().releaseConnection(conn);
|
|
1331
|
-
case "knex":
|
|
1332
|
-
return this.client.client.releaseConnection(conn);
|
|
1333
|
-
default:
|
|
1334
|
-
return true;
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
_getSequelizeConnectionManager() {
|
|
1338
|
-
let connectionManager;
|
|
1339
|
-
let originalError;
|
|
1340
|
-
try {
|
|
1341
|
-
connectionManager = this.client.connectionManager;
|
|
1342
|
-
} catch (err) {
|
|
1343
|
-
originalError = err;
|
|
1344
|
-
}
|
|
1345
|
-
if (connectionManager) {
|
|
1346
|
-
return connectionManager;
|
|
1347
|
-
}
|
|
1348
|
-
if (this.client.dialect && this.client.dialect.connectionManager) {
|
|
1349
|
-
return this.client.dialect.connectionManager;
|
|
1350
|
-
}
|
|
1351
|
-
if (originalError) {
|
|
1352
|
-
throw originalError;
|
|
1353
|
-
}
|
|
1354
|
-
throw new Error("Sequelize connection manager is not available");
|
|
1355
|
-
}
|
|
1356
|
-
/**
|
|
1357
|
-
*
|
|
1358
|
-
* @returns {Promise<any>}
|
|
1359
|
-
* @private
|
|
1360
|
-
*/
|
|
1361
|
-
_createDbAndTable() {
|
|
1362
|
-
return new Promise((resolve, reject) => {
|
|
1363
|
-
this._getConnection().then((conn) => {
|
|
1364
|
-
conn.query(`CREATE DATABASE IF NOT EXISTS \`${this.dbName}\`;`, (errDb) => {
|
|
1365
|
-
if (errDb) {
|
|
1366
|
-
this._releaseConnection(conn);
|
|
1367
|
-
return reject(errDb);
|
|
1368
|
-
}
|
|
1369
|
-
conn.query(this._getCreateTableStmt(), (err) => {
|
|
1370
|
-
if (err) {
|
|
1371
|
-
this._releaseConnection(conn);
|
|
1372
|
-
return reject(err);
|
|
1373
|
-
}
|
|
1374
|
-
this._releaseConnection(conn);
|
|
1375
|
-
resolve();
|
|
1376
|
-
});
|
|
1377
|
-
});
|
|
1378
|
-
}).catch((err) => {
|
|
1379
|
-
reject(err);
|
|
1380
|
-
});
|
|
1381
|
-
});
|
|
1382
|
-
}
|
|
1383
|
-
_getCreateTableStmt() {
|
|
1384
|
-
return `CREATE TABLE IF NOT EXISTS \`${this.dbName}\`.\`${this.tableName}\` (\`key\` VARCHAR(255) CHARACTER SET utf8 NOT NULL,\`points\` INT(9) NOT NULL default 0,\`expire\` BIGINT UNSIGNED,PRIMARY KEY (\`key\`)) ENGINE = INNODB;`;
|
|
1385
|
-
}
|
|
1386
|
-
get clientType() {
|
|
1387
|
-
return this._clientType;
|
|
1388
|
-
}
|
|
1389
|
-
set clientType(value) {
|
|
1390
|
-
if (typeof value === "undefined") {
|
|
1391
|
-
if (this.client.constructor.name === "Connection") {
|
|
1392
|
-
value = "connection";
|
|
1393
|
-
} else if (this.client.constructor.name === "Pool") {
|
|
1394
|
-
value = "pool";
|
|
1395
|
-
} else if (this.client.constructor.name === "Sequelize") {
|
|
1396
|
-
value = "sequelize";
|
|
1397
|
-
} else {
|
|
1398
|
-
throw new Error("storeType is not defined");
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
this._clientType = value.toLowerCase();
|
|
1402
|
-
}
|
|
1403
|
-
get dbName() {
|
|
1404
|
-
return this._dbName;
|
|
1405
|
-
}
|
|
1406
|
-
set dbName(value) {
|
|
1407
|
-
this._dbName = typeof value === "undefined" ? "rtlmtrflx" : value;
|
|
1408
|
-
}
|
|
1409
|
-
get tableName() {
|
|
1410
|
-
return this._tableName;
|
|
1411
|
-
}
|
|
1412
|
-
set tableName(value) {
|
|
1413
|
-
this._tableName = typeof value === "undefined" ? this.keyPrefix : value;
|
|
1414
|
-
}
|
|
1415
|
-
get tableCreated() {
|
|
1416
|
-
return this._tableCreated;
|
|
1417
|
-
}
|
|
1418
|
-
set tableCreated(value) {
|
|
1419
|
-
this._tableCreated = typeof value === "undefined" ? false : !!value;
|
|
1420
|
-
}
|
|
1421
|
-
get clearExpiredByTimeout() {
|
|
1422
|
-
return this._clearExpiredByTimeout;
|
|
1423
|
-
}
|
|
1424
|
-
set clearExpiredByTimeout(value) {
|
|
1425
|
-
this._clearExpiredByTimeout = typeof value === "undefined" ? true : Boolean(value);
|
|
1426
|
-
}
|
|
1427
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
1428
|
-
const res = new RateLimiterRes2();
|
|
1429
|
-
const [row] = result;
|
|
1430
|
-
res.isFirstInDuration = changedPoints === row.points;
|
|
1431
|
-
res.consumedPoints = res.isFirstInDuration ? changedPoints : row.points;
|
|
1432
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
1433
|
-
res.msBeforeNext = row.expire ? Math.max(row.expire - Date.now(), 0) : -1;
|
|
1434
|
-
return res;
|
|
1435
|
-
}
|
|
1436
|
-
_upsertTransaction(conn, key, points, msDuration, forceExpire) {
|
|
1437
|
-
return new Promise((resolve, reject) => {
|
|
1438
|
-
conn.query("BEGIN", (errBegin) => {
|
|
1439
|
-
if (errBegin) {
|
|
1440
|
-
conn.rollback();
|
|
1441
|
-
return reject(errBegin);
|
|
1442
|
-
}
|
|
1443
|
-
const dateNow = Date.now();
|
|
1444
|
-
const newExpire = msDuration > 0 ? dateNow + msDuration : null;
|
|
1445
|
-
let q;
|
|
1446
|
-
let values;
|
|
1447
|
-
if (forceExpire) {
|
|
1448
|
-
q = `INSERT INTO ??.?? VALUES (?, ?, ?)
|
|
1449
|
-
ON DUPLICATE KEY UPDATE
|
|
1450
|
-
points = ?,
|
|
1451
|
-
expire = ?;`;
|
|
1452
|
-
values = [
|
|
1453
|
-
this.dbName,
|
|
1454
|
-
this.tableName,
|
|
1455
|
-
key,
|
|
1456
|
-
points,
|
|
1457
|
-
newExpire,
|
|
1458
|
-
points,
|
|
1459
|
-
newExpire
|
|
1460
|
-
];
|
|
1461
|
-
} else {
|
|
1462
|
-
q = `INSERT INTO ??.?? VALUES (?, ?, ?)
|
|
1463
|
-
ON DUPLICATE KEY UPDATE
|
|
1464
|
-
points = IF(expire <= ?, ?, points + (?)),
|
|
1465
|
-
expire = IF(expire <= ?, ?, expire);`;
|
|
1466
|
-
values = [
|
|
1467
|
-
this.dbName,
|
|
1468
|
-
this.tableName,
|
|
1469
|
-
key,
|
|
1470
|
-
points,
|
|
1471
|
-
newExpire,
|
|
1472
|
-
dateNow,
|
|
1473
|
-
points,
|
|
1474
|
-
points,
|
|
1475
|
-
dateNow,
|
|
1476
|
-
newExpire
|
|
1477
|
-
];
|
|
1478
|
-
}
|
|
1479
|
-
conn.query(q, values, (errUpsert) => {
|
|
1480
|
-
if (errUpsert) {
|
|
1481
|
-
conn.rollback();
|
|
1482
|
-
return reject(errUpsert);
|
|
1483
|
-
}
|
|
1484
|
-
conn.query("SELECT points, expire FROM ??.?? WHERE `key` = ?;", [this.dbName, this.tableName, key], (errSelect, res) => {
|
|
1485
|
-
if (errSelect) {
|
|
1486
|
-
conn.rollback();
|
|
1487
|
-
return reject(errSelect);
|
|
1488
|
-
}
|
|
1489
|
-
conn.query("COMMIT", (err) => {
|
|
1490
|
-
if (err) {
|
|
1491
|
-
conn.rollback();
|
|
1492
|
-
return reject(err);
|
|
1493
|
-
}
|
|
1494
|
-
resolve(res);
|
|
1495
|
-
});
|
|
1496
|
-
});
|
|
1497
|
-
});
|
|
1498
|
-
});
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
_upsert(key, points, msDuration, forceExpire = false) {
|
|
1502
|
-
if (!this.tableCreated) {
|
|
1503
|
-
return Promise.reject(Error("Table is not created yet"));
|
|
1504
|
-
}
|
|
1505
|
-
return new Promise((resolve, reject) => {
|
|
1506
|
-
this._getConnection().then((conn) => {
|
|
1507
|
-
this._upsertTransaction(conn, key, points, msDuration, forceExpire).then((res) => {
|
|
1508
|
-
resolve(res);
|
|
1509
|
-
this._releaseConnection(conn);
|
|
1510
|
-
}).catch((err) => {
|
|
1511
|
-
reject(err);
|
|
1512
|
-
this._releaseConnection(conn);
|
|
1513
|
-
});
|
|
1514
|
-
}).catch((err) => {
|
|
1515
|
-
reject(err);
|
|
1516
|
-
});
|
|
1517
|
-
});
|
|
1518
|
-
}
|
|
1519
|
-
_get(rlKey) {
|
|
1520
|
-
if (!this.tableCreated) {
|
|
1521
|
-
return Promise.reject(Error("Table is not created yet"));
|
|
1522
|
-
}
|
|
1523
|
-
return new Promise((resolve, reject) => {
|
|
1524
|
-
this._getConnection().then((conn) => {
|
|
1525
|
-
conn.query(
|
|
1526
|
-
"SELECT points, expire FROM ??.?? WHERE `key` = ? AND (`expire` > ? OR `expire` IS NULL)",
|
|
1527
|
-
[this.dbName, this.tableName, rlKey, Date.now()],
|
|
1528
|
-
(err, res) => {
|
|
1529
|
-
if (err) {
|
|
1530
|
-
reject(err);
|
|
1531
|
-
} else if (res.length === 0) {
|
|
1532
|
-
resolve(null);
|
|
1533
|
-
} else {
|
|
1534
|
-
resolve(res);
|
|
1535
|
-
}
|
|
1536
|
-
this._releaseConnection(conn);
|
|
1537
|
-
}
|
|
1538
|
-
// eslint-disable-line
|
|
1539
|
-
);
|
|
1540
|
-
}).catch((err) => {
|
|
1541
|
-
reject(err);
|
|
1542
|
-
});
|
|
1543
|
-
});
|
|
1544
|
-
}
|
|
1545
|
-
_delete(rlKey) {
|
|
1546
|
-
if (!this.tableCreated) {
|
|
1547
|
-
return Promise.reject(Error("Table is not created yet"));
|
|
1548
|
-
}
|
|
1549
|
-
return new Promise((resolve, reject) => {
|
|
1550
|
-
this._getConnection().then((conn) => {
|
|
1551
|
-
conn.query(
|
|
1552
|
-
"DELETE FROM ??.?? WHERE `key` = ?",
|
|
1553
|
-
[this.dbName, this.tableName, rlKey],
|
|
1554
|
-
(err, res) => {
|
|
1555
|
-
if (err) {
|
|
1556
|
-
reject(err);
|
|
1557
|
-
} else {
|
|
1558
|
-
resolve(res.affectedRows > 0);
|
|
1559
|
-
}
|
|
1560
|
-
this._releaseConnection(conn);
|
|
1561
|
-
}
|
|
1562
|
-
// eslint-disable-line
|
|
1563
|
-
);
|
|
1564
|
-
}).catch((err) => {
|
|
1565
|
-
reject(err);
|
|
1566
|
-
});
|
|
1567
|
-
});
|
|
1568
|
-
}
|
|
1569
|
-
};
|
|
1570
|
-
module2.exports = RateLimiterMySQL;
|
|
1571
|
-
}
|
|
1572
|
-
});
|
|
1573
|
-
|
|
1574
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterPostgres.js
|
|
1575
|
-
var require_RateLimiterPostgres = __commonJS({
|
|
1576
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterPostgres.js"(exports2, module2) {
|
|
1577
|
-
"use strict";
|
|
1578
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
1579
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
1580
|
-
var RateLimiterPostgres = class extends RateLimiterStoreAbstract {
|
|
1581
|
-
/**
|
|
1582
|
-
* @callback callback
|
|
1583
|
-
* @param {Object} err
|
|
1584
|
-
*
|
|
1585
|
-
* @param {Object} opts
|
|
1586
|
-
* @param {callback} cb
|
|
1587
|
-
* Defaults {
|
|
1588
|
-
* ... see other in RateLimiterStoreAbstract
|
|
1589
|
-
*
|
|
1590
|
-
* storeClient: postgresClient,
|
|
1591
|
-
* storeType: 'knex', // required only for Knex instance
|
|
1592
|
-
* tableName: 'string',
|
|
1593
|
-
* schemaName: 'string', // optional
|
|
1594
|
-
* }
|
|
1595
|
-
*/
|
|
1596
|
-
constructor(opts, cb = null) {
|
|
1597
|
-
super(opts);
|
|
1598
|
-
this.client = opts.storeClient;
|
|
1599
|
-
this.clientType = opts.storeType;
|
|
1600
|
-
this.tableName = opts.tableName;
|
|
1601
|
-
this.schemaName = opts.schemaName;
|
|
1602
|
-
this.clearExpiredByTimeout = opts.clearExpiredByTimeout;
|
|
1603
|
-
this.tableCreated = opts.tableCreated;
|
|
1604
|
-
if (!this.tableCreated) {
|
|
1605
|
-
this._createTable().then(() => {
|
|
1606
|
-
this.tableCreated = true;
|
|
1607
|
-
if (this.clearExpiredByTimeout) {
|
|
1608
|
-
this._clearExpiredHourAgo();
|
|
1609
|
-
}
|
|
1610
|
-
if (typeof cb === "function") {
|
|
1611
|
-
cb();
|
|
1612
|
-
}
|
|
1613
|
-
}).catch((err) => {
|
|
1614
|
-
if (typeof cb === "function") {
|
|
1615
|
-
cb(err);
|
|
1616
|
-
} else {
|
|
1617
|
-
throw err;
|
|
1618
|
-
}
|
|
1619
|
-
});
|
|
1620
|
-
} else {
|
|
1621
|
-
if (this.clearExpiredByTimeout) {
|
|
1622
|
-
this._clearExpiredHourAgo();
|
|
1623
|
-
}
|
|
1624
|
-
if (typeof cb === "function") {
|
|
1625
|
-
cb();
|
|
1626
|
-
}
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
_getTableIdentifier() {
|
|
1630
|
-
return this.schemaName ? `"${this.schemaName}"."${this.tableName}"` : `"${this.tableName}"`;
|
|
1631
|
-
}
|
|
1632
|
-
clearExpired(expire) {
|
|
1633
|
-
return new Promise((resolve) => {
|
|
1634
|
-
const q = {
|
|
1635
|
-
name: "rlflx-clear-expired",
|
|
1636
|
-
text: `DELETE FROM ${this._getTableIdentifier()} WHERE expire < $1`,
|
|
1637
|
-
values: [expire]
|
|
1638
|
-
};
|
|
1639
|
-
this._query(q).then(() => {
|
|
1640
|
-
resolve();
|
|
1641
|
-
}).catch(() => {
|
|
1642
|
-
resolve();
|
|
1643
|
-
});
|
|
1644
|
-
});
|
|
1645
|
-
}
|
|
1646
|
-
/**
|
|
1647
|
-
* Delete all rows expired 1 hour ago once per 5 minutes
|
|
1648
|
-
*
|
|
1649
|
-
* @private
|
|
1650
|
-
*/
|
|
1651
|
-
_clearExpiredHourAgo() {
|
|
1652
|
-
if (this._clearExpiredTimeoutId) {
|
|
1653
|
-
clearTimeout(this._clearExpiredTimeoutId);
|
|
1654
|
-
}
|
|
1655
|
-
this._clearExpiredTimeoutId = setTimeout(() => {
|
|
1656
|
-
this.clearExpired(Date.now() - 36e5).then(() => {
|
|
1657
|
-
this._clearExpiredHourAgo();
|
|
1658
|
-
});
|
|
1659
|
-
}, 3e5);
|
|
1660
|
-
this._clearExpiredTimeoutId.unref();
|
|
1661
|
-
}
|
|
1662
|
-
/**
|
|
1663
|
-
*
|
|
1664
|
-
* @return Promise<any>
|
|
1665
|
-
* @private
|
|
1666
|
-
*/
|
|
1667
|
-
_getConnection() {
|
|
1668
|
-
switch (this.clientType) {
|
|
1669
|
-
case "pool":
|
|
1670
|
-
return Promise.resolve(this.client);
|
|
1671
|
-
case "sequelize":
|
|
1672
|
-
return this._getSequelizeConnectionManager().getConnection();
|
|
1673
|
-
case "knex":
|
|
1674
|
-
return this.client.client.acquireConnection();
|
|
1675
|
-
case "typeorm":
|
|
1676
|
-
return Promise.resolve(this.client.driver.master);
|
|
1677
|
-
default:
|
|
1678
|
-
return Promise.resolve(this.client);
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
_releaseConnection(conn) {
|
|
1682
|
-
switch (this.clientType) {
|
|
1683
|
-
case "pool":
|
|
1684
|
-
return true;
|
|
1685
|
-
case "sequelize":
|
|
1686
|
-
return this._getSequelizeConnectionManager().releaseConnection(conn);
|
|
1687
|
-
case "knex":
|
|
1688
|
-
return this.client.client.releaseConnection(conn);
|
|
1689
|
-
case "typeorm":
|
|
1690
|
-
return true;
|
|
1691
|
-
default:
|
|
1692
|
-
return true;
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
_getSequelizeConnectionManager() {
|
|
1696
|
-
let connectionManager;
|
|
1697
|
-
let accessError;
|
|
1698
|
-
try {
|
|
1699
|
-
connectionManager = this.client.connectionManager;
|
|
1700
|
-
} catch (err) {
|
|
1701
|
-
accessError = err;
|
|
1702
|
-
}
|
|
1703
|
-
if (connectionManager) {
|
|
1704
|
-
return connectionManager;
|
|
1705
|
-
}
|
|
1706
|
-
if (this.client.dialect && this.client.dialect.connectionManager) {
|
|
1707
|
-
return this.client.dialect.connectionManager;
|
|
1708
|
-
}
|
|
1709
|
-
if (accessError) {
|
|
1710
|
-
throw accessError;
|
|
1711
|
-
}
|
|
1712
|
-
throw new Error("Sequelize connection manager is not available");
|
|
1713
|
-
}
|
|
1714
|
-
/**
|
|
1715
|
-
*
|
|
1716
|
-
* @returns {Promise<any>}
|
|
1717
|
-
* @private
|
|
1718
|
-
*/
|
|
1719
|
-
_createTable() {
|
|
1720
|
-
return new Promise((resolve, reject) => {
|
|
1721
|
-
this._query({
|
|
1722
|
-
text: this._getCreateTableStmt()
|
|
1723
|
-
}).then(() => {
|
|
1724
|
-
resolve();
|
|
1725
|
-
}).catch((err) => {
|
|
1726
|
-
if (err.code === "23505") {
|
|
1727
|
-
resolve();
|
|
1728
|
-
} else {
|
|
1729
|
-
reject(err);
|
|
1730
|
-
}
|
|
1731
|
-
});
|
|
1732
|
-
});
|
|
1733
|
-
}
|
|
1734
|
-
_getCreateTableStmt() {
|
|
1735
|
-
return `CREATE TABLE IF NOT EXISTS ${this._getTableIdentifier()} (
|
|
1736
|
-
key varchar(255) PRIMARY KEY,
|
|
1737
|
-
points integer NOT NULL DEFAULT 0,
|
|
1738
|
-
expire bigint
|
|
1739
|
-
);`;
|
|
1740
|
-
}
|
|
1741
|
-
get clientType() {
|
|
1742
|
-
return this._clientType;
|
|
1743
|
-
}
|
|
1744
|
-
set clientType(value) {
|
|
1745
|
-
const constructorName = this.client.constructor.name;
|
|
1746
|
-
if (typeof value === "undefined") {
|
|
1747
|
-
if (constructorName === "Client") {
|
|
1748
|
-
value = "client";
|
|
1749
|
-
} else if (constructorName === "Pool" || constructorName === "BoundPool") {
|
|
1750
|
-
value = "pool";
|
|
1751
|
-
} else if (constructorName === "Sequelize") {
|
|
1752
|
-
value = "sequelize";
|
|
1753
|
-
} else {
|
|
1754
|
-
throw new Error("storeType is not defined");
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
this._clientType = value.toLowerCase();
|
|
1758
|
-
}
|
|
1759
|
-
get tableName() {
|
|
1760
|
-
return this._tableName;
|
|
1761
|
-
}
|
|
1762
|
-
set tableName(value) {
|
|
1763
|
-
this._tableName = typeof value === "undefined" ? this.keyPrefix : value;
|
|
1764
|
-
}
|
|
1765
|
-
get schemaName() {
|
|
1766
|
-
return this._schemaName;
|
|
1767
|
-
}
|
|
1768
|
-
set schemaName(value) {
|
|
1769
|
-
this._schemaName = value;
|
|
1770
|
-
}
|
|
1771
|
-
get tableCreated() {
|
|
1772
|
-
return this._tableCreated;
|
|
1773
|
-
}
|
|
1774
|
-
set tableCreated(value) {
|
|
1775
|
-
this._tableCreated = typeof value === "undefined" ? false : !!value;
|
|
1776
|
-
}
|
|
1777
|
-
get clearExpiredByTimeout() {
|
|
1778
|
-
return this._clearExpiredByTimeout;
|
|
1779
|
-
}
|
|
1780
|
-
set clearExpiredByTimeout(value) {
|
|
1781
|
-
this._clearExpiredByTimeout = typeof value === "undefined" ? true : Boolean(value);
|
|
1782
|
-
}
|
|
1783
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
1784
|
-
const res = new RateLimiterRes2();
|
|
1785
|
-
const row = result.rows[0];
|
|
1786
|
-
res.isFirstInDuration = changedPoints === row.points;
|
|
1787
|
-
res.consumedPoints = res.isFirstInDuration ? changedPoints : row.points;
|
|
1788
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
1789
|
-
res.msBeforeNext = row.expire ? Math.max(row.expire - Date.now(), 0) : -1;
|
|
1790
|
-
return res;
|
|
1791
|
-
}
|
|
1792
|
-
_query(q) {
|
|
1793
|
-
const prefix = this.tableName.toLowerCase();
|
|
1794
|
-
const queryObj = { name: `${prefix}:${q.name}`, text: q.text, values: q.values };
|
|
1795
|
-
return new Promise((resolve, reject) => {
|
|
1796
|
-
this._getConnection().then((conn) => {
|
|
1797
|
-
conn.query(queryObj).then((res) => {
|
|
1798
|
-
resolve(res);
|
|
1799
|
-
this._releaseConnection(conn);
|
|
1800
|
-
}).catch((err) => {
|
|
1801
|
-
reject(err);
|
|
1802
|
-
this._releaseConnection(conn);
|
|
1803
|
-
});
|
|
1804
|
-
}).catch((err) => {
|
|
1805
|
-
reject(err);
|
|
1806
|
-
});
|
|
1807
|
-
});
|
|
1808
|
-
}
|
|
1809
|
-
_upsert(key, points, msDuration, forceExpire = false) {
|
|
1810
|
-
if (!this.tableCreated) {
|
|
1811
|
-
return Promise.reject(Error("Table is not created yet"));
|
|
1812
|
-
}
|
|
1813
|
-
const newExpire = msDuration > 0 ? Date.now() + msDuration : null;
|
|
1814
|
-
const expireQ = forceExpire ? " $3 " : ` CASE
|
|
1815
|
-
WHEN ${this._getTableIdentifier()}.expire <= $4 THEN $3
|
|
1816
|
-
ELSE ${this._getTableIdentifier()}.expire
|
|
1817
|
-
END `;
|
|
1818
|
-
return this._query({
|
|
1819
|
-
name: forceExpire ? "rlflx-upsert-force" : "rlflx-upsert",
|
|
1820
|
-
text: `
|
|
1821
|
-
INSERT INTO ${this._getTableIdentifier()} VALUES ($1, $2, $3)
|
|
1822
|
-
ON CONFLICT(key) DO UPDATE SET
|
|
1823
|
-
points = CASE
|
|
1824
|
-
WHEN (${this._getTableIdentifier()}.expire <= $4 OR 1=${forceExpire ? 1 : 0}) THEN $2
|
|
1825
|
-
ELSE ${this._getTableIdentifier()}.points + ($2)
|
|
1826
|
-
END,
|
|
1827
|
-
expire = ${expireQ}
|
|
1828
|
-
RETURNING points, expire;`,
|
|
1829
|
-
values: [key, points, newExpire, Date.now()]
|
|
1830
|
-
});
|
|
1831
|
-
}
|
|
1832
|
-
_get(rlKey) {
|
|
1833
|
-
if (!this.tableCreated) {
|
|
1834
|
-
return Promise.reject(Error("Table is not created yet"));
|
|
1835
|
-
}
|
|
1836
|
-
return new Promise((resolve, reject) => {
|
|
1837
|
-
this._query({
|
|
1838
|
-
name: "rlflx-get",
|
|
1839
|
-
text: `
|
|
1840
|
-
SELECT points, expire FROM ${this._getTableIdentifier()} WHERE key = $1 AND (expire > $2 OR expire IS NULL);`,
|
|
1841
|
-
values: [rlKey, Date.now()]
|
|
1842
|
-
}).then((res) => {
|
|
1843
|
-
if (res.rowCount === 0) {
|
|
1844
|
-
res = null;
|
|
1845
|
-
}
|
|
1846
|
-
resolve(res);
|
|
1847
|
-
}).catch((err) => {
|
|
1848
|
-
reject(err);
|
|
1849
|
-
});
|
|
1850
|
-
});
|
|
1851
|
-
}
|
|
1852
|
-
_delete(rlKey) {
|
|
1853
|
-
if (!this.tableCreated) {
|
|
1854
|
-
return Promise.reject(Error("Table is not created yet"));
|
|
1855
|
-
}
|
|
1856
|
-
return this._query({
|
|
1857
|
-
name: "rlflx-delete",
|
|
1858
|
-
text: `DELETE FROM ${this._getTableIdentifier()} WHERE key = $1`,
|
|
1859
|
-
values: [rlKey]
|
|
1860
|
-
}).then((res) => res.rowCount > 0);
|
|
1861
|
-
}
|
|
1862
|
-
};
|
|
1863
|
-
module2.exports = RateLimiterPostgres;
|
|
1864
|
-
}
|
|
1865
|
-
});
|
|
1866
|
-
|
|
1867
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/MemoryStorage/Record.js
|
|
1868
|
-
var require_Record = __commonJS({
|
|
1869
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/MemoryStorage/Record.js"(exports2, module2) {
|
|
1870
|
-
"use strict";
|
|
1871
|
-
module2.exports = class Record {
|
|
1872
|
-
/**
|
|
1873
|
-
*
|
|
1874
|
-
* @param value int
|
|
1875
|
-
* @param expiresAt Number|Date
|
|
1876
|
-
* @param timeoutId
|
|
1877
|
-
*/
|
|
1878
|
-
constructor(value, expiresAt, timeoutId = null) {
|
|
1879
|
-
this.value = value;
|
|
1880
|
-
this.expiresAt = expiresAt;
|
|
1881
|
-
this.timeoutId = timeoutId;
|
|
1882
|
-
}
|
|
1883
|
-
get value() {
|
|
1884
|
-
return this._value;
|
|
1885
|
-
}
|
|
1886
|
-
set value(value) {
|
|
1887
|
-
this._value = parseInt(value, 10);
|
|
1888
|
-
}
|
|
1889
|
-
get expiresAt() {
|
|
1890
|
-
return this._expiresAt;
|
|
1891
|
-
}
|
|
1892
|
-
set expiresAt(value) {
|
|
1893
|
-
if (value instanceof Date) {
|
|
1894
|
-
this._expiresAt = value.getTime();
|
|
1895
|
-
} else {
|
|
1896
|
-
this._expiresAt = value;
|
|
1897
|
-
}
|
|
1898
|
-
}
|
|
1899
|
-
get timeoutId() {
|
|
1900
|
-
return this._timeoutId;
|
|
1901
|
-
}
|
|
1902
|
-
set timeoutId(value) {
|
|
1903
|
-
this._timeoutId = value;
|
|
1904
|
-
}
|
|
1905
|
-
};
|
|
1906
|
-
}
|
|
1907
|
-
});
|
|
1908
|
-
|
|
1909
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/MemoryStorage/MemoryStorage.js
|
|
1910
|
-
var require_MemoryStorage = __commonJS({
|
|
1911
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/MemoryStorage/MemoryStorage.js"(exports2, module2) {
|
|
1912
|
-
"use strict";
|
|
1913
|
-
var Record = require_Record();
|
|
1914
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
1915
|
-
module2.exports = class MemoryStorage {
|
|
1916
|
-
constructor() {
|
|
1917
|
-
this._storage = /* @__PURE__ */ new Map();
|
|
1918
|
-
}
|
|
1919
|
-
incrby(key, value, durationSec) {
|
|
1920
|
-
const record2 = this._storage.get(key);
|
|
1921
|
-
if (record2) {
|
|
1922
|
-
const msBeforeExpires = record2.expiresAt ? record2.expiresAt - Date.now() : -1;
|
|
1923
|
-
if (!record2.expiresAt || msBeforeExpires > 0) {
|
|
1924
|
-
record2.value = record2.value + value;
|
|
1925
|
-
return new RateLimiterRes2(0, msBeforeExpires, record2.value, false);
|
|
1926
|
-
}
|
|
1927
|
-
return this.set(key, value, durationSec);
|
|
1928
|
-
}
|
|
1929
|
-
return this.set(key, value, durationSec);
|
|
1930
|
-
}
|
|
1931
|
-
set(key, value, durationSec) {
|
|
1932
|
-
const durationMs = durationSec * 1e3;
|
|
1933
|
-
const existingRecord = this._storage.get(key);
|
|
1934
|
-
if (existingRecord && existingRecord.timeoutId) {
|
|
1935
|
-
clearTimeout(existingRecord.timeoutId);
|
|
1936
|
-
}
|
|
1937
|
-
const record2 = new Record(
|
|
1938
|
-
value,
|
|
1939
|
-
durationMs > 0 ? Date.now() + durationMs : null
|
|
1940
|
-
);
|
|
1941
|
-
this._storage.set(key, record2);
|
|
1942
|
-
if (durationMs > 0) {
|
|
1943
|
-
record2.timeoutId = setTimeout(() => {
|
|
1944
|
-
this._storage.delete(key);
|
|
1945
|
-
}, durationMs);
|
|
1946
|
-
if (record2.timeoutId.unref) {
|
|
1947
|
-
record2.timeoutId.unref();
|
|
1948
|
-
}
|
|
1949
|
-
}
|
|
1950
|
-
return new RateLimiterRes2(0, durationMs === 0 ? -1 : durationMs, record2.value, true);
|
|
1951
|
-
}
|
|
1952
|
-
/**
|
|
1953
|
-
*
|
|
1954
|
-
* @param key
|
|
1955
|
-
* @returns {*}
|
|
1956
|
-
*/
|
|
1957
|
-
get(key) {
|
|
1958
|
-
const record2 = this._storage.get(key);
|
|
1959
|
-
if (record2) {
|
|
1960
|
-
const msBeforeExpires = record2.expiresAt ? record2.expiresAt - Date.now() : -1;
|
|
1961
|
-
return new RateLimiterRes2(0, msBeforeExpires, record2.value, false);
|
|
1962
|
-
}
|
|
1963
|
-
return null;
|
|
1964
|
-
}
|
|
1965
|
-
/**
|
|
1966
|
-
*
|
|
1967
|
-
* @param key
|
|
1968
|
-
* @returns {boolean}
|
|
1969
|
-
*/
|
|
1970
|
-
delete(key) {
|
|
1971
|
-
const record2 = this._storage.get(key);
|
|
1972
|
-
if (record2) {
|
|
1973
|
-
if (record2.timeoutId) {
|
|
1974
|
-
clearTimeout(record2.timeoutId);
|
|
1975
|
-
}
|
|
1976
|
-
this._storage.delete(key);
|
|
1977
|
-
return true;
|
|
1978
|
-
}
|
|
1979
|
-
return false;
|
|
1980
|
-
}
|
|
1981
|
-
};
|
|
1982
|
-
}
|
|
1983
|
-
});
|
|
1984
|
-
|
|
1985
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterMemory.js
|
|
1986
|
-
var require_RateLimiterMemory = __commonJS({
|
|
1987
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterMemory.js"(exports2, module2) {
|
|
1988
|
-
"use strict";
|
|
1989
|
-
var RateLimiterAbstract = require_RateLimiterAbstract();
|
|
1990
|
-
var MemoryStorage = require_MemoryStorage();
|
|
1991
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
1992
|
-
var RateLimiterMemory2 = class extends RateLimiterAbstract {
|
|
1993
|
-
constructor(opts = {}) {
|
|
1994
|
-
super(opts);
|
|
1995
|
-
this._memoryStorage = new MemoryStorage();
|
|
1996
|
-
}
|
|
1997
|
-
/**
|
|
1998
|
-
*
|
|
1999
|
-
* @param key
|
|
2000
|
-
* @param pointsToConsume
|
|
2001
|
-
* @param {Object} options
|
|
2002
|
-
* @returns {Promise<RateLimiterRes>}
|
|
2003
|
-
*/
|
|
2004
|
-
consume(key, pointsToConsume = 1, options = {}) {
|
|
2005
|
-
return new Promise((resolve, reject) => {
|
|
2006
|
-
const rlKey = this.getKey(key);
|
|
2007
|
-
const secDuration = this._getKeySecDuration(options);
|
|
2008
|
-
let res = this._memoryStorage.incrby(rlKey, pointsToConsume, secDuration);
|
|
2009
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
2010
|
-
if (res.consumedPoints > this.points) {
|
|
2011
|
-
if (this.blockDuration > 0 && res.consumedPoints <= this.points + pointsToConsume) {
|
|
2012
|
-
res = this._memoryStorage.set(rlKey, res.consumedPoints, this.blockDuration);
|
|
2013
|
-
}
|
|
2014
|
-
reject(res);
|
|
2015
|
-
} else if (this.execEvenly && res.msBeforeNext > 0 && !res.isFirstInDuration) {
|
|
2016
|
-
let delay = Math.ceil(res.msBeforeNext / (res.remainingPoints + 2));
|
|
2017
|
-
if (delay < this.execEvenlyMinDelayMs) {
|
|
2018
|
-
delay = res.consumedPoints * this.execEvenlyMinDelayMs;
|
|
2019
|
-
}
|
|
2020
|
-
setTimeout(resolve, delay, res);
|
|
2021
|
-
} else {
|
|
2022
|
-
resolve(res);
|
|
2023
|
-
}
|
|
2024
|
-
});
|
|
2025
|
-
}
|
|
2026
|
-
penalty(key, points = 1, options = {}) {
|
|
2027
|
-
const rlKey = this.getKey(key);
|
|
2028
|
-
return new Promise((resolve) => {
|
|
2029
|
-
const secDuration = this._getKeySecDuration(options);
|
|
2030
|
-
const res = this._memoryStorage.incrby(rlKey, points, secDuration);
|
|
2031
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
2032
|
-
resolve(res);
|
|
2033
|
-
});
|
|
2034
|
-
}
|
|
2035
|
-
reward(key, points = 1, options = {}) {
|
|
2036
|
-
const rlKey = this.getKey(key);
|
|
2037
|
-
return new Promise((resolve) => {
|
|
2038
|
-
const secDuration = this._getKeySecDuration(options);
|
|
2039
|
-
const res = this._memoryStorage.incrby(rlKey, -points, secDuration);
|
|
2040
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
2041
|
-
resolve(res);
|
|
2042
|
-
});
|
|
2043
|
-
}
|
|
2044
|
-
/**
|
|
2045
|
-
* Block any key for secDuration seconds
|
|
2046
|
-
*
|
|
2047
|
-
* @param key
|
|
2048
|
-
* @param secDuration
|
|
2049
|
-
*/
|
|
2050
|
-
block(key, secDuration) {
|
|
2051
|
-
const msDuration = secDuration * 1e3;
|
|
2052
|
-
const initPoints = this.points + 1;
|
|
2053
|
-
this._memoryStorage.set(this.getKey(key), initPoints, secDuration);
|
|
2054
|
-
return Promise.resolve(
|
|
2055
|
-
new RateLimiterRes2(0, msDuration === 0 ? -1 : msDuration, initPoints)
|
|
2056
|
-
);
|
|
2057
|
-
}
|
|
2058
|
-
set(key, points, secDuration) {
|
|
2059
|
-
const msDuration = (secDuration >= 0 ? secDuration : this.duration) * 1e3;
|
|
2060
|
-
this._memoryStorage.set(this.getKey(key), points, secDuration);
|
|
2061
|
-
return Promise.resolve(
|
|
2062
|
-
new RateLimiterRes2(0, msDuration === 0 ? -1 : msDuration, points)
|
|
2063
|
-
);
|
|
2064
|
-
}
|
|
2065
|
-
get(key) {
|
|
2066
|
-
const res = this._memoryStorage.get(this.getKey(key));
|
|
2067
|
-
if (res !== null) {
|
|
2068
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
2069
|
-
}
|
|
2070
|
-
return Promise.resolve(res);
|
|
2071
|
-
}
|
|
2072
|
-
delete(key) {
|
|
2073
|
-
return Promise.resolve(this._memoryStorage.delete(this.getKey(key)));
|
|
2074
|
-
}
|
|
2075
|
-
};
|
|
2076
|
-
module2.exports = RateLimiterMemory2;
|
|
2077
|
-
}
|
|
2078
|
-
});
|
|
2079
|
-
|
|
2080
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterCluster.js
|
|
2081
|
-
var require_RateLimiterCluster = __commonJS({
|
|
2082
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterCluster.js"(exports2, module2) {
|
|
2083
|
-
"use strict";
|
|
2084
|
-
var cluster = require("cluster");
|
|
2085
|
-
var crypto = require("crypto");
|
|
2086
|
-
var RateLimiterAbstract = require_RateLimiterAbstract();
|
|
2087
|
-
var RateLimiterMemory2 = require_RateLimiterMemory();
|
|
2088
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
2089
|
-
var channel = "rate_limiter_flexible";
|
|
2090
|
-
var masterInstance = null;
|
|
2091
|
-
var masterSendToWorker = function(worker, msg, type, res) {
|
|
2092
|
-
let data;
|
|
2093
|
-
if (res === null || res === true || res === false) {
|
|
2094
|
-
data = res;
|
|
2095
|
-
} else {
|
|
2096
|
-
data = {
|
|
2097
|
-
remainingPoints: res.remainingPoints,
|
|
2098
|
-
msBeforeNext: res.msBeforeNext,
|
|
2099
|
-
consumedPoints: res.consumedPoints,
|
|
2100
|
-
isFirstInDuration: res.isFirstInDuration
|
|
2101
|
-
};
|
|
2102
|
-
}
|
|
2103
|
-
worker.send({
|
|
2104
|
-
channel,
|
|
2105
|
-
keyPrefix: msg.keyPrefix,
|
|
2106
|
-
// which rate limiter exactly
|
|
2107
|
-
promiseId: msg.promiseId,
|
|
2108
|
-
type,
|
|
2109
|
-
data
|
|
2110
|
-
});
|
|
2111
|
-
};
|
|
2112
|
-
var workerWaitInit = function(payload) {
|
|
2113
|
-
setTimeout(() => {
|
|
2114
|
-
if (this._initiated) {
|
|
2115
|
-
process.send(payload);
|
|
2116
|
-
} else if (typeof this._promises[payload.promiseId] !== "undefined") {
|
|
2117
|
-
workerWaitInit.call(this, payload);
|
|
2118
|
-
}
|
|
2119
|
-
}, 30);
|
|
2120
|
-
};
|
|
2121
|
-
var workerSendToMaster = function(func, promiseId, key, arg, opts) {
|
|
2122
|
-
const payload = {
|
|
2123
|
-
channel,
|
|
2124
|
-
keyPrefix: this.keyPrefix,
|
|
2125
|
-
func,
|
|
2126
|
-
promiseId,
|
|
2127
|
-
data: {
|
|
2128
|
-
key,
|
|
2129
|
-
arg,
|
|
2130
|
-
opts
|
|
2131
|
-
}
|
|
2132
|
-
};
|
|
2133
|
-
if (!this._initiated) {
|
|
2134
|
-
workerWaitInit.call(this, payload);
|
|
2135
|
-
} else {
|
|
2136
|
-
process.send(payload);
|
|
2137
|
-
}
|
|
2138
|
-
};
|
|
2139
|
-
var masterProcessMsg = function(worker, msg) {
|
|
2140
|
-
if (!msg || msg.channel !== channel || typeof this._rateLimiters[msg.keyPrefix] === "undefined") {
|
|
2141
|
-
return false;
|
|
2142
|
-
}
|
|
2143
|
-
let promise2;
|
|
2144
|
-
switch (msg.func) {
|
|
2145
|
-
case "consume":
|
|
2146
|
-
promise2 = this._rateLimiters[msg.keyPrefix].consume(msg.data.key, msg.data.arg, msg.data.opts);
|
|
2147
|
-
break;
|
|
2148
|
-
case "penalty":
|
|
2149
|
-
promise2 = this._rateLimiters[msg.keyPrefix].penalty(msg.data.key, msg.data.arg, msg.data.opts);
|
|
2150
|
-
break;
|
|
2151
|
-
case "reward":
|
|
2152
|
-
promise2 = this._rateLimiters[msg.keyPrefix].reward(msg.data.key, msg.data.arg, msg.data.opts);
|
|
2153
|
-
break;
|
|
2154
|
-
case "block":
|
|
2155
|
-
promise2 = this._rateLimiters[msg.keyPrefix].block(msg.data.key, msg.data.arg, msg.data.opts);
|
|
2156
|
-
break;
|
|
2157
|
-
case "get":
|
|
2158
|
-
promise2 = this._rateLimiters[msg.keyPrefix].get(msg.data.key, msg.data.opts);
|
|
2159
|
-
break;
|
|
2160
|
-
case "delete":
|
|
2161
|
-
promise2 = this._rateLimiters[msg.keyPrefix].delete(msg.data.key, msg.data.opts);
|
|
2162
|
-
break;
|
|
2163
|
-
default:
|
|
2164
|
-
return false;
|
|
2165
|
-
}
|
|
2166
|
-
if (promise2) {
|
|
2167
|
-
promise2.then((res) => {
|
|
2168
|
-
masterSendToWorker(worker, msg, "resolve", res);
|
|
2169
|
-
}).catch((rejRes) => {
|
|
2170
|
-
masterSendToWorker(worker, msg, "reject", rejRes);
|
|
2171
|
-
});
|
|
2172
|
-
}
|
|
2173
|
-
};
|
|
2174
|
-
var workerProcessMsg = function(msg) {
|
|
2175
|
-
if (!msg || msg.channel !== channel || msg.keyPrefix !== this.keyPrefix) {
|
|
2176
|
-
return false;
|
|
2177
|
-
}
|
|
2178
|
-
if (this._promises[msg.promiseId]) {
|
|
2179
|
-
clearTimeout(this._promises[msg.promiseId].timeoutId);
|
|
2180
|
-
let res;
|
|
2181
|
-
if (msg.data === null || msg.data === true || msg.data === false) {
|
|
2182
|
-
res = msg.data;
|
|
2183
|
-
} else {
|
|
2184
|
-
res = new RateLimiterRes2(
|
|
2185
|
-
msg.data.remainingPoints,
|
|
2186
|
-
msg.data.msBeforeNext,
|
|
2187
|
-
msg.data.consumedPoints,
|
|
2188
|
-
msg.data.isFirstInDuration
|
|
2189
|
-
// eslint-disable-line comma-dangle
|
|
2190
|
-
);
|
|
2191
|
-
}
|
|
2192
|
-
switch (msg.type) {
|
|
2193
|
-
case "resolve":
|
|
2194
|
-
this._promises[msg.promiseId].resolve(res);
|
|
2195
|
-
break;
|
|
2196
|
-
case "reject":
|
|
2197
|
-
this._promises[msg.promiseId].reject(res);
|
|
2198
|
-
break;
|
|
2199
|
-
default:
|
|
2200
|
-
throw new Error(`RateLimiterCluster: no such message type '${msg.type}'`);
|
|
2201
|
-
}
|
|
2202
|
-
delete this._promises[msg.promiseId];
|
|
2203
|
-
}
|
|
2204
|
-
};
|
|
2205
|
-
var getOpts = function() {
|
|
2206
|
-
return {
|
|
2207
|
-
points: this.points,
|
|
2208
|
-
duration: this.duration,
|
|
2209
|
-
blockDuration: this.blockDuration,
|
|
2210
|
-
execEvenly: this.execEvenly,
|
|
2211
|
-
execEvenlyMinDelayMs: this.execEvenlyMinDelayMs,
|
|
2212
|
-
keyPrefix: this.keyPrefix
|
|
2213
|
-
};
|
|
2214
|
-
};
|
|
2215
|
-
var savePromise = function(resolve, reject) {
|
|
2216
|
-
const hrtime = process.hrtime();
|
|
2217
|
-
let promiseId = hrtime[0].toString() + hrtime[1].toString();
|
|
2218
|
-
if (typeof this._promises[promiseId] !== "undefined") {
|
|
2219
|
-
promiseId += crypto.randomBytes(12).toString("base64");
|
|
2220
|
-
}
|
|
2221
|
-
this._promises[promiseId] = {
|
|
2222
|
-
resolve,
|
|
2223
|
-
reject,
|
|
2224
|
-
timeoutId: setTimeout(() => {
|
|
2225
|
-
delete this._promises[promiseId];
|
|
2226
|
-
reject(new Error("RateLimiterCluster timeout: no answer from master in time"));
|
|
2227
|
-
}, this.timeoutMs)
|
|
2228
|
-
};
|
|
2229
|
-
return promiseId;
|
|
2230
|
-
};
|
|
2231
|
-
var RateLimiterClusterMaster = class {
|
|
2232
|
-
constructor() {
|
|
2233
|
-
if (masterInstance) {
|
|
2234
|
-
return masterInstance;
|
|
2235
|
-
}
|
|
2236
|
-
this._rateLimiters = {};
|
|
2237
|
-
cluster.setMaxListeners(0);
|
|
2238
|
-
cluster.on("message", (worker, msg) => {
|
|
2239
|
-
if (msg && msg.channel === channel && msg.type === "init") {
|
|
2240
|
-
if (typeof this._rateLimiters[msg.opts.keyPrefix] === "undefined") {
|
|
2241
|
-
this._rateLimiters[msg.opts.keyPrefix] = new RateLimiterMemory2(msg.opts);
|
|
2242
|
-
}
|
|
2243
|
-
worker.send({
|
|
2244
|
-
channel,
|
|
2245
|
-
type: "init",
|
|
2246
|
-
keyPrefix: msg.opts.keyPrefix
|
|
2247
|
-
});
|
|
2248
|
-
} else {
|
|
2249
|
-
masterProcessMsg.call(this, worker, msg);
|
|
2250
|
-
}
|
|
2251
|
-
});
|
|
2252
|
-
masterInstance = this;
|
|
2253
|
-
}
|
|
2254
|
-
};
|
|
2255
|
-
var RateLimiterClusterMasterPM2 = class {
|
|
2256
|
-
constructor(pm2) {
|
|
2257
|
-
if (masterInstance) {
|
|
2258
|
-
return masterInstance;
|
|
2259
|
-
}
|
|
2260
|
-
this._rateLimiters = {};
|
|
2261
|
-
pm2.launchBus((err, pm2Bus) => {
|
|
2262
|
-
pm2Bus.on("process:msg", (packet) => {
|
|
2263
|
-
const msg = packet.raw;
|
|
2264
|
-
if (msg && msg.channel === channel && msg.type === "init") {
|
|
2265
|
-
if (typeof this._rateLimiters[msg.opts.keyPrefix] === "undefined") {
|
|
2266
|
-
this._rateLimiters[msg.opts.keyPrefix] = new RateLimiterMemory2(msg.opts);
|
|
2267
|
-
}
|
|
2268
|
-
pm2.sendDataToProcessId(packet.process.pm_id, {
|
|
2269
|
-
data: {},
|
|
2270
|
-
topic: channel,
|
|
2271
|
-
channel,
|
|
2272
|
-
type: "init",
|
|
2273
|
-
keyPrefix: msg.opts.keyPrefix
|
|
2274
|
-
}, (sendErr, res) => {
|
|
2275
|
-
if (sendErr) {
|
|
2276
|
-
console.log(sendErr, res);
|
|
2277
|
-
}
|
|
2278
|
-
});
|
|
2279
|
-
} else {
|
|
2280
|
-
const worker = {
|
|
2281
|
-
send: (msgData) => {
|
|
2282
|
-
const pm2Message = msgData;
|
|
2283
|
-
pm2Message.topic = channel;
|
|
2284
|
-
if (typeof pm2Message.data === "undefined") {
|
|
2285
|
-
pm2Message.data = {};
|
|
2286
|
-
}
|
|
2287
|
-
pm2.sendDataToProcessId(packet.process.pm_id, pm2Message, (sendErr, res) => {
|
|
2288
|
-
if (sendErr) {
|
|
2289
|
-
console.log(sendErr, res);
|
|
2290
|
-
}
|
|
2291
|
-
});
|
|
2292
|
-
}
|
|
2293
|
-
};
|
|
2294
|
-
masterProcessMsg.call(this, worker, msg);
|
|
2295
|
-
}
|
|
2296
|
-
});
|
|
2297
|
-
});
|
|
2298
|
-
masterInstance = this;
|
|
2299
|
-
}
|
|
2300
|
-
};
|
|
2301
|
-
var RateLimiterClusterWorker = class extends RateLimiterAbstract {
|
|
2302
|
-
get timeoutMs() {
|
|
2303
|
-
return this._timeoutMs;
|
|
2304
|
-
}
|
|
2305
|
-
set timeoutMs(value) {
|
|
2306
|
-
this._timeoutMs = typeof value === "undefined" ? 5e3 : Math.abs(parseInt(value));
|
|
2307
|
-
}
|
|
2308
|
-
constructor(opts = {}) {
|
|
2309
|
-
super(opts);
|
|
2310
|
-
process.setMaxListeners(0);
|
|
2311
|
-
this.timeoutMs = opts.timeoutMs;
|
|
2312
|
-
this._initiated = false;
|
|
2313
|
-
process.on("message", (msg) => {
|
|
2314
|
-
if (msg && msg.channel === channel && msg.type === "init" && msg.keyPrefix === this.keyPrefix) {
|
|
2315
|
-
this._initiated = true;
|
|
2316
|
-
} else {
|
|
2317
|
-
workerProcessMsg.call(this, msg);
|
|
2318
|
-
}
|
|
2319
|
-
});
|
|
2320
|
-
process.send({
|
|
2321
|
-
channel,
|
|
2322
|
-
type: "init",
|
|
2323
|
-
opts: getOpts.call(this)
|
|
2324
|
-
});
|
|
2325
|
-
this._promises = {};
|
|
2326
|
-
}
|
|
2327
|
-
consume(key, pointsToConsume = 1, options = {}) {
|
|
2328
|
-
return new Promise((resolve, reject) => {
|
|
2329
|
-
const promiseId = savePromise.call(this, resolve, reject);
|
|
2330
|
-
workerSendToMaster.call(this, "consume", promiseId, key, pointsToConsume, options);
|
|
2331
|
-
});
|
|
2332
|
-
}
|
|
2333
|
-
penalty(key, points = 1, options = {}) {
|
|
2334
|
-
return new Promise((resolve, reject) => {
|
|
2335
|
-
const promiseId = savePromise.call(this, resolve, reject);
|
|
2336
|
-
workerSendToMaster.call(this, "penalty", promiseId, key, points, options);
|
|
2337
|
-
});
|
|
2338
|
-
}
|
|
2339
|
-
reward(key, points = 1, options = {}) {
|
|
2340
|
-
return new Promise((resolve, reject) => {
|
|
2341
|
-
const promiseId = savePromise.call(this, resolve, reject);
|
|
2342
|
-
workerSendToMaster.call(this, "reward", promiseId, key, points, options);
|
|
2343
|
-
});
|
|
2344
|
-
}
|
|
2345
|
-
block(key, secDuration, options = {}) {
|
|
2346
|
-
return new Promise((resolve, reject) => {
|
|
2347
|
-
const promiseId = savePromise.call(this, resolve, reject);
|
|
2348
|
-
workerSendToMaster.call(this, "block", promiseId, key, secDuration, options);
|
|
2349
|
-
});
|
|
2350
|
-
}
|
|
2351
|
-
get(key, options = {}) {
|
|
2352
|
-
return new Promise((resolve, reject) => {
|
|
2353
|
-
const promiseId = savePromise.call(this, resolve, reject);
|
|
2354
|
-
workerSendToMaster.call(this, "get", promiseId, key, options);
|
|
2355
|
-
});
|
|
2356
|
-
}
|
|
2357
|
-
delete(key, options = {}) {
|
|
2358
|
-
return new Promise((resolve, reject) => {
|
|
2359
|
-
const promiseId = savePromise.call(this, resolve, reject);
|
|
2360
|
-
workerSendToMaster.call(this, "delete", promiseId, key, options);
|
|
2361
|
-
});
|
|
2362
|
-
}
|
|
2363
|
-
};
|
|
2364
|
-
module2.exports = {
|
|
2365
|
-
RateLimiterClusterMaster,
|
|
2366
|
-
RateLimiterClusterMasterPM2,
|
|
2367
|
-
RateLimiterCluster: RateLimiterClusterWorker
|
|
2368
|
-
};
|
|
2369
|
-
}
|
|
2370
|
-
});
|
|
2371
|
-
|
|
2372
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterMemcache.js
|
|
2373
|
-
var require_RateLimiterMemcache = __commonJS({
|
|
2374
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterMemcache.js"(exports2, module2) {
|
|
2375
|
-
"use strict";
|
|
2376
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
2377
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
2378
|
-
var RateLimiterMemcache = class extends RateLimiterStoreAbstract {
|
|
2379
|
-
/**
|
|
2380
|
-
*
|
|
2381
|
-
* @param {Object} opts
|
|
2382
|
-
* Defaults {
|
|
2383
|
-
* ... see other in RateLimiterStoreAbstract
|
|
2384
|
-
*
|
|
2385
|
-
* storeClient: memcacheClient
|
|
2386
|
-
* }
|
|
2387
|
-
*/
|
|
2388
|
-
constructor(opts) {
|
|
2389
|
-
super(opts);
|
|
2390
|
-
this.client = opts.storeClient;
|
|
2391
|
-
}
|
|
2392
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
2393
|
-
const res = new RateLimiterRes2();
|
|
2394
|
-
res.consumedPoints = parseInt(result.consumedPoints);
|
|
2395
|
-
res.isFirstInDuration = result.consumedPoints === changedPoints;
|
|
2396
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
2397
|
-
res.msBeforeNext = result.msBeforeNext;
|
|
2398
|
-
return res;
|
|
2399
|
-
}
|
|
2400
|
-
_upsert(rlKey, points, msDuration, forceExpire = false, options = {}) {
|
|
2401
|
-
return new Promise((resolve, reject) => {
|
|
2402
|
-
const nowMs = Date.now();
|
|
2403
|
-
const secDuration = Math.floor(msDuration / 1e3);
|
|
2404
|
-
if (forceExpire) {
|
|
2405
|
-
this.client.set(rlKey, points, secDuration, (err) => {
|
|
2406
|
-
if (!err) {
|
|
2407
|
-
this.client.set(
|
|
2408
|
-
`${rlKey}_expire`,
|
|
2409
|
-
secDuration > 0 ? nowMs + secDuration * 1e3 : -1,
|
|
2410
|
-
secDuration,
|
|
2411
|
-
() => {
|
|
2412
|
-
const res = {
|
|
2413
|
-
consumedPoints: points,
|
|
2414
|
-
msBeforeNext: secDuration > 0 ? secDuration * 1e3 : -1
|
|
2415
|
-
};
|
|
2416
|
-
resolve(res);
|
|
2417
|
-
}
|
|
2418
|
-
);
|
|
2419
|
-
} else {
|
|
2420
|
-
reject(err);
|
|
2421
|
-
}
|
|
2422
|
-
});
|
|
2423
|
-
} else {
|
|
2424
|
-
this.client.incr(rlKey, points, (err, consumedPoints) => {
|
|
2425
|
-
if (err || consumedPoints === false) {
|
|
2426
|
-
this.client.add(rlKey, points, secDuration, (errAddKey, createdNew) => {
|
|
2427
|
-
if (errAddKey || !createdNew) {
|
|
2428
|
-
if (typeof options.attemptNumber === "undefined" || options.attemptNumber < 3) {
|
|
2429
|
-
const nextOptions = Object.assign({}, options);
|
|
2430
|
-
nextOptions.attemptNumber = nextOptions.attemptNumber ? nextOptions.attemptNumber + 1 : 1;
|
|
2431
|
-
this._upsert(rlKey, points, msDuration, forceExpire, nextOptions).then((resUpsert) => resolve(resUpsert)).catch((errUpsert) => reject(errUpsert));
|
|
2432
|
-
} else {
|
|
2433
|
-
reject(new Error("Can not add key"));
|
|
2434
|
-
}
|
|
2435
|
-
} else {
|
|
2436
|
-
this.client.add(
|
|
2437
|
-
`${rlKey}_expire`,
|
|
2438
|
-
secDuration > 0 ? nowMs + secDuration * 1e3 : -1,
|
|
2439
|
-
secDuration,
|
|
2440
|
-
() => {
|
|
2441
|
-
const res = {
|
|
2442
|
-
consumedPoints: points,
|
|
2443
|
-
msBeforeNext: secDuration > 0 ? secDuration * 1e3 : -1
|
|
2444
|
-
};
|
|
2445
|
-
resolve(res);
|
|
2446
|
-
}
|
|
2447
|
-
);
|
|
2448
|
-
}
|
|
2449
|
-
});
|
|
2450
|
-
} else {
|
|
2451
|
-
this.client.get(`${rlKey}_expire`, (errGetExpire, resGetExpireMs) => {
|
|
2452
|
-
if (errGetExpire) {
|
|
2453
|
-
reject(errGetExpire);
|
|
2454
|
-
} else {
|
|
2455
|
-
const expireMs = resGetExpireMs === false ? 0 : resGetExpireMs;
|
|
2456
|
-
const res = {
|
|
2457
|
-
consumedPoints,
|
|
2458
|
-
msBeforeNext: expireMs >= 0 ? Math.max(expireMs - nowMs, 0) : -1
|
|
2459
|
-
};
|
|
2460
|
-
resolve(res);
|
|
2461
|
-
}
|
|
2462
|
-
});
|
|
2463
|
-
}
|
|
2464
|
-
});
|
|
2465
|
-
}
|
|
2466
|
-
});
|
|
2467
|
-
}
|
|
2468
|
-
_get(rlKey) {
|
|
2469
|
-
return new Promise((resolve, reject) => {
|
|
2470
|
-
const nowMs = Date.now();
|
|
2471
|
-
this.client.get(rlKey, (err, consumedPoints) => {
|
|
2472
|
-
if (!consumedPoints) {
|
|
2473
|
-
resolve(null);
|
|
2474
|
-
} else {
|
|
2475
|
-
this.client.get(`${rlKey}_expire`, (errGetExpire, resGetExpireMs) => {
|
|
2476
|
-
if (errGetExpire) {
|
|
2477
|
-
reject(errGetExpire);
|
|
2478
|
-
} else {
|
|
2479
|
-
const expireMs = resGetExpireMs === false ? 0 : resGetExpireMs;
|
|
2480
|
-
const res = {
|
|
2481
|
-
consumedPoints,
|
|
2482
|
-
msBeforeNext: expireMs >= 0 ? Math.max(expireMs - nowMs, 0) : -1
|
|
2483
|
-
};
|
|
2484
|
-
resolve(res);
|
|
2485
|
-
}
|
|
2486
|
-
});
|
|
2487
|
-
}
|
|
2488
|
-
});
|
|
2489
|
-
});
|
|
2490
|
-
}
|
|
2491
|
-
_delete(rlKey) {
|
|
2492
|
-
return new Promise((resolve, reject) => {
|
|
2493
|
-
this.client.del(rlKey, (err, res) => {
|
|
2494
|
-
if (err) {
|
|
2495
|
-
reject(err);
|
|
2496
|
-
} else if (res === false) {
|
|
2497
|
-
resolve(res);
|
|
2498
|
-
} else {
|
|
2499
|
-
this.client.del(`${rlKey}_expire`, (errDelExpire) => {
|
|
2500
|
-
if (errDelExpire) {
|
|
2501
|
-
reject(errDelExpire);
|
|
2502
|
-
} else {
|
|
2503
|
-
resolve(res);
|
|
2504
|
-
}
|
|
2505
|
-
});
|
|
2506
|
-
}
|
|
2507
|
-
});
|
|
2508
|
-
});
|
|
2509
|
-
}
|
|
2510
|
-
};
|
|
2511
|
-
module2.exports = RateLimiterMemcache;
|
|
2512
|
-
}
|
|
2513
|
-
});
|
|
2514
|
-
|
|
2515
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RLWrapperBlackAndWhite.js
|
|
2516
|
-
var require_RLWrapperBlackAndWhite = __commonJS({
|
|
2517
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RLWrapperBlackAndWhite.js"(exports2, module2) {
|
|
2518
|
-
"use strict";
|
|
2519
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
2520
|
-
module2.exports = class RLWrapperBlackAndWhite {
|
|
2521
|
-
constructor(opts = {}) {
|
|
2522
|
-
this.limiter = opts.limiter;
|
|
2523
|
-
this.blackList = opts.blackList;
|
|
2524
|
-
this.whiteList = opts.whiteList;
|
|
2525
|
-
this.isBlackListed = opts.isBlackListed;
|
|
2526
|
-
this.isWhiteListed = opts.isWhiteListed;
|
|
2527
|
-
this.runActionAnyway = opts.runActionAnyway;
|
|
2528
|
-
}
|
|
2529
|
-
get limiter() {
|
|
2530
|
-
return this._limiter;
|
|
2531
|
-
}
|
|
2532
|
-
set limiter(value) {
|
|
2533
|
-
if (typeof value === "undefined") {
|
|
2534
|
-
throw new Error("limiter is not set");
|
|
2535
|
-
}
|
|
2536
|
-
this._limiter = value;
|
|
2537
|
-
}
|
|
2538
|
-
get runActionAnyway() {
|
|
2539
|
-
return this._runActionAnyway;
|
|
2540
|
-
}
|
|
2541
|
-
set runActionAnyway(value) {
|
|
2542
|
-
this._runActionAnyway = typeof value === "undefined" ? false : value;
|
|
2543
|
-
}
|
|
2544
|
-
get blackList() {
|
|
2545
|
-
return this._blackList;
|
|
2546
|
-
}
|
|
2547
|
-
set blackList(value) {
|
|
2548
|
-
this._blackList = Array.isArray(value) ? value : [];
|
|
2549
|
-
}
|
|
2550
|
-
get isBlackListed() {
|
|
2551
|
-
return this._isBlackListed;
|
|
2552
|
-
}
|
|
2553
|
-
set isBlackListed(func) {
|
|
2554
|
-
if (typeof func === "undefined") {
|
|
2555
|
-
func = () => false;
|
|
2556
|
-
}
|
|
2557
|
-
if (typeof func !== "function") {
|
|
2558
|
-
throw new Error("isBlackListed must be function");
|
|
2559
|
-
}
|
|
2560
|
-
this._isBlackListed = func;
|
|
2561
|
-
}
|
|
2562
|
-
get whiteList() {
|
|
2563
|
-
return this._whiteList;
|
|
2564
|
-
}
|
|
2565
|
-
set whiteList(value) {
|
|
2566
|
-
this._whiteList = Array.isArray(value) ? value : [];
|
|
2567
|
-
}
|
|
2568
|
-
get isWhiteListed() {
|
|
2569
|
-
return this._isWhiteListed;
|
|
2570
|
-
}
|
|
2571
|
-
set isWhiteListed(func) {
|
|
2572
|
-
if (typeof func === "undefined") {
|
|
2573
|
-
func = () => false;
|
|
2574
|
-
}
|
|
2575
|
-
if (typeof func !== "function") {
|
|
2576
|
-
throw new Error("isWhiteListed must be function");
|
|
2577
|
-
}
|
|
2578
|
-
this._isWhiteListed = func;
|
|
2579
|
-
}
|
|
2580
|
-
isBlackListedSomewhere(key) {
|
|
2581
|
-
return this.blackList.indexOf(key) >= 0 || this.isBlackListed(key);
|
|
2582
|
-
}
|
|
2583
|
-
isWhiteListedSomewhere(key) {
|
|
2584
|
-
return this.whiteList.indexOf(key) >= 0 || this.isWhiteListed(key);
|
|
2585
|
-
}
|
|
2586
|
-
getBlackRes() {
|
|
2587
|
-
return new RateLimiterRes2(0, Number.MAX_SAFE_INTEGER, 0, false);
|
|
2588
|
-
}
|
|
2589
|
-
getWhiteRes() {
|
|
2590
|
-
return new RateLimiterRes2(Number.MAX_SAFE_INTEGER, 0, 0, false);
|
|
2591
|
-
}
|
|
2592
|
-
rejectBlack() {
|
|
2593
|
-
return Promise.reject(this.getBlackRes());
|
|
2594
|
-
}
|
|
2595
|
-
resolveBlack() {
|
|
2596
|
-
return Promise.resolve(this.getBlackRes());
|
|
2597
|
-
}
|
|
2598
|
-
resolveWhite() {
|
|
2599
|
-
return Promise.resolve(this.getWhiteRes());
|
|
2600
|
-
}
|
|
2601
|
-
consume(key, pointsToConsume = 1) {
|
|
2602
|
-
let res;
|
|
2603
|
-
if (this.isWhiteListedSomewhere(key)) {
|
|
2604
|
-
res = this.resolveWhite();
|
|
2605
|
-
} else if (this.isBlackListedSomewhere(key)) {
|
|
2606
|
-
res = this.rejectBlack();
|
|
2607
|
-
}
|
|
2608
|
-
if (typeof res === "undefined") {
|
|
2609
|
-
return this.limiter.consume(key, pointsToConsume);
|
|
2610
|
-
}
|
|
2611
|
-
if (this.runActionAnyway) {
|
|
2612
|
-
this.limiter.consume(key, pointsToConsume).catch(() => {
|
|
2613
|
-
});
|
|
2614
|
-
}
|
|
2615
|
-
return res;
|
|
2616
|
-
}
|
|
2617
|
-
block(key, secDuration) {
|
|
2618
|
-
let res;
|
|
2619
|
-
if (this.isWhiteListedSomewhere(key)) {
|
|
2620
|
-
res = this.resolveWhite();
|
|
2621
|
-
} else if (this.isBlackListedSomewhere(key)) {
|
|
2622
|
-
res = this.resolveBlack();
|
|
2623
|
-
}
|
|
2624
|
-
if (typeof res === "undefined") {
|
|
2625
|
-
return this.limiter.block(key, secDuration);
|
|
2626
|
-
}
|
|
2627
|
-
if (this.runActionAnyway) {
|
|
2628
|
-
this.limiter.block(key, secDuration).catch(() => {
|
|
2629
|
-
});
|
|
2630
|
-
}
|
|
2631
|
-
return res;
|
|
2632
|
-
}
|
|
2633
|
-
penalty(key, points) {
|
|
2634
|
-
let res;
|
|
2635
|
-
if (this.isWhiteListedSomewhere(key)) {
|
|
2636
|
-
res = this.resolveWhite();
|
|
2637
|
-
} else if (this.isBlackListedSomewhere(key)) {
|
|
2638
|
-
res = this.resolveBlack();
|
|
2639
|
-
}
|
|
2640
|
-
if (typeof res === "undefined") {
|
|
2641
|
-
return this.limiter.penalty(key, points);
|
|
2642
|
-
}
|
|
2643
|
-
if (this.runActionAnyway) {
|
|
2644
|
-
this.limiter.penalty(key, points).catch(() => {
|
|
2645
|
-
});
|
|
2646
|
-
}
|
|
2647
|
-
return res;
|
|
2648
|
-
}
|
|
2649
|
-
reward(key, points) {
|
|
2650
|
-
let res;
|
|
2651
|
-
if (this.isWhiteListedSomewhere(key)) {
|
|
2652
|
-
res = this.resolveWhite();
|
|
2653
|
-
} else if (this.isBlackListedSomewhere(key)) {
|
|
2654
|
-
res = this.resolveBlack();
|
|
2655
|
-
}
|
|
2656
|
-
if (typeof res === "undefined") {
|
|
2657
|
-
return this.limiter.reward(key, points);
|
|
2658
|
-
}
|
|
2659
|
-
if (this.runActionAnyway) {
|
|
2660
|
-
this.limiter.reward(key, points).catch(() => {
|
|
2661
|
-
});
|
|
2662
|
-
}
|
|
2663
|
-
return res;
|
|
2664
|
-
}
|
|
2665
|
-
get(key) {
|
|
2666
|
-
let res;
|
|
2667
|
-
if (this.isWhiteListedSomewhere(key)) {
|
|
2668
|
-
res = this.resolveWhite();
|
|
2669
|
-
} else if (this.isBlackListedSomewhere(key)) {
|
|
2670
|
-
res = this.resolveBlack();
|
|
2671
|
-
}
|
|
2672
|
-
if (typeof res === "undefined" || this.runActionAnyway) {
|
|
2673
|
-
return this.limiter.get(key);
|
|
2674
|
-
}
|
|
2675
|
-
return res;
|
|
2676
|
-
}
|
|
2677
|
-
delete(key) {
|
|
2678
|
-
return this.limiter.delete(key);
|
|
2679
|
-
}
|
|
2680
|
-
};
|
|
2681
|
-
}
|
|
2682
|
-
});
|
|
2683
|
-
|
|
2684
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RLWrapperTimeouts.js
|
|
2685
|
-
var require_RLWrapperTimeouts = __commonJS({
|
|
2686
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RLWrapperTimeouts.js"(exports2, module2) {
|
|
2687
|
-
"use strict";
|
|
2688
|
-
var RateLimiterAbstract = require_RateLimiterAbstract();
|
|
2689
|
-
var RateLimiterInsuredAbstract = require_RateLimiterInsuredAbstract();
|
|
2690
|
-
module2.exports = class RLWrapperTimeouts extends RateLimiterInsuredAbstract {
|
|
2691
|
-
constructor(opts = {}) {
|
|
2692
|
-
super(opts);
|
|
2693
|
-
this.limiter = opts.limiter;
|
|
2694
|
-
this.timeoutMs = opts.timeoutMs || 0;
|
|
2695
|
-
}
|
|
2696
|
-
get limiter() {
|
|
2697
|
-
return this._limiter;
|
|
2698
|
-
}
|
|
2699
|
-
set limiter(limiter) {
|
|
2700
|
-
if (!(limiter instanceof RateLimiterAbstract)) {
|
|
2701
|
-
throw new TypeError("limiter must be an instance of RateLimiterAbstract");
|
|
2702
|
-
}
|
|
2703
|
-
this._limiter = limiter;
|
|
2704
|
-
if (!this.insuranceLimiter && limiter instanceof RateLimiterInsuredAbstract) {
|
|
2705
|
-
this.insuranceLimiter = limiter.insuranceLimiter;
|
|
2706
|
-
}
|
|
2707
|
-
}
|
|
2708
|
-
get timeoutMs() {
|
|
2709
|
-
return this._timeoutMs;
|
|
2710
|
-
}
|
|
2711
|
-
set timeoutMs(value) {
|
|
2712
|
-
if (typeof value !== "number" || value < 0) {
|
|
2713
|
-
throw new TypeError("timeoutMs must be a non-negative number");
|
|
2714
|
-
}
|
|
2715
|
-
this._timeoutMs = value;
|
|
2716
|
-
}
|
|
2717
|
-
_run(funcName, params) {
|
|
2718
|
-
return new Promise(async (resolve, reject) => {
|
|
2719
|
-
const timeout = setTimeout(() => {
|
|
2720
|
-
return reject(new Error("Operation timed out"));
|
|
2721
|
-
}, this.timeoutMs);
|
|
2722
|
-
await this.limiter[funcName](...params).then((result) => {
|
|
2723
|
-
clearTimeout(timeout);
|
|
2724
|
-
resolve(result);
|
|
2725
|
-
}).catch((err) => {
|
|
2726
|
-
clearTimeout(timeout);
|
|
2727
|
-
reject(err);
|
|
2728
|
-
});
|
|
2729
|
-
});
|
|
2730
|
-
}
|
|
2731
|
-
_consume(key, pointsToConsume = 1, options = {}) {
|
|
2732
|
-
return this._run("consume", [key, pointsToConsume, options]);
|
|
2733
|
-
}
|
|
2734
|
-
_penalty(key, points = 1, options = {}) {
|
|
2735
|
-
return this._run("penalty", [key, points, options]);
|
|
2736
|
-
}
|
|
2737
|
-
_reward(key, points = 1, options = {}) {
|
|
2738
|
-
return this._run("reward", [key, points, options]);
|
|
2739
|
-
}
|
|
2740
|
-
_get(key, options = {}) {
|
|
2741
|
-
return this._run("get", [key, options]);
|
|
2742
|
-
}
|
|
2743
|
-
_set(key, points, secDuration, options = {}) {
|
|
2744
|
-
return this._run("set", [key, points, secDuration, options]);
|
|
2745
|
-
}
|
|
2746
|
-
_block(key, secDuration, options = {}) {
|
|
2747
|
-
return this._run("block", [key, secDuration, options]);
|
|
2748
|
-
}
|
|
2749
|
-
_delete(key, options = {}) {
|
|
2750
|
-
return this._run("delete", [key, options]);
|
|
2751
|
-
}
|
|
2752
|
-
};
|
|
2753
|
-
}
|
|
2754
|
-
});
|
|
2755
|
-
|
|
2756
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterUnion.js
|
|
2757
|
-
var require_RateLimiterUnion = __commonJS({
|
|
2758
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterUnion.js"(exports2, module2) {
|
|
2759
|
-
"use strict";
|
|
2760
|
-
var RateLimiterAbstract = require_RateLimiterAbstract();
|
|
2761
|
-
module2.exports = class RateLimiterUnion {
|
|
2762
|
-
constructor(...limiters) {
|
|
2763
|
-
if (limiters.length < 1) {
|
|
2764
|
-
throw new Error("RateLimiterUnion: at least one limiter have to be passed");
|
|
2765
|
-
}
|
|
2766
|
-
limiters.forEach((limiter) => {
|
|
2767
|
-
if (!(limiter instanceof RateLimiterAbstract)) {
|
|
2768
|
-
throw new Error("RateLimiterUnion: all limiters have to be instance of RateLimiterAbstract");
|
|
2769
|
-
}
|
|
2770
|
-
});
|
|
2771
|
-
this._limiters = limiters;
|
|
2772
|
-
}
|
|
2773
|
-
consume(key, points = 1) {
|
|
2774
|
-
return new Promise((resolve, reject) => {
|
|
2775
|
-
const promises = [];
|
|
2776
|
-
this._limiters.forEach((limiter) => {
|
|
2777
|
-
promises.push(limiter.consume(key, points).catch((rej) => ({ rejected: true, rej })));
|
|
2778
|
-
});
|
|
2779
|
-
Promise.all(promises).then((res) => {
|
|
2780
|
-
const resObj = {};
|
|
2781
|
-
let rejected = false;
|
|
2782
|
-
res.forEach((item) => {
|
|
2783
|
-
if (item.rejected === true) {
|
|
2784
|
-
rejected = true;
|
|
2785
|
-
}
|
|
2786
|
-
});
|
|
2787
|
-
for (let i = 0; i < res.length; i++) {
|
|
2788
|
-
if (rejected && res[i].rejected === true) {
|
|
2789
|
-
resObj[this._limiters[i].keyPrefix] = res[i].rej;
|
|
2790
|
-
} else if (!rejected) {
|
|
2791
|
-
resObj[this._limiters[i].keyPrefix] = res[i];
|
|
2792
|
-
}
|
|
2793
|
-
}
|
|
2794
|
-
if (rejected) {
|
|
2795
|
-
reject(resObj);
|
|
2796
|
-
} else {
|
|
2797
|
-
resolve(resObj);
|
|
2798
|
-
}
|
|
2799
|
-
});
|
|
2800
|
-
});
|
|
2801
|
-
}
|
|
2802
|
-
};
|
|
2803
|
-
}
|
|
2804
|
-
});
|
|
2805
|
-
|
|
2806
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/RateLimiterQueueError.js
|
|
2807
|
-
var require_RateLimiterQueueError = __commonJS({
|
|
2808
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/RateLimiterQueueError.js"(exports2, module2) {
|
|
2809
|
-
"use strict";
|
|
2810
|
-
module2.exports = class RateLimiterQueueError extends Error {
|
|
2811
|
-
constructor(message, extra) {
|
|
2812
|
-
super();
|
|
2813
|
-
if (Error.captureStackTrace) {
|
|
2814
|
-
Error.captureStackTrace(this, this.constructor);
|
|
2815
|
-
}
|
|
2816
|
-
this.name = "CustomError";
|
|
2817
|
-
this.message = message;
|
|
2818
|
-
if (extra) {
|
|
2819
|
-
this.extra = extra;
|
|
2820
|
-
}
|
|
2821
|
-
}
|
|
2822
|
-
};
|
|
2823
|
-
}
|
|
2824
|
-
});
|
|
2825
|
-
|
|
2826
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterQueue.js
|
|
2827
|
-
var require_RateLimiterQueue = __commonJS({
|
|
2828
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterQueue.js"(exports2, module2) {
|
|
2829
|
-
"use strict";
|
|
2830
|
-
var RateLimiterQueueError = require_RateLimiterQueueError();
|
|
2831
|
-
var MAX_QUEUE_SIZE = 4294967295;
|
|
2832
|
-
var KEY_DEFAULT = "limiter";
|
|
2833
|
-
module2.exports = class RateLimiterQueue {
|
|
2834
|
-
constructor(limiterFlexible, opts = {}) {
|
|
2835
|
-
const maxQueueSize = opts.maxQueueSize !== void 0 ? opts.maxQueueSize : MAX_QUEUE_SIZE;
|
|
2836
|
-
this._queueLimiters = {
|
|
2837
|
-
KEY_DEFAULT: new RateLimiterQueueInternal(limiterFlexible, {
|
|
2838
|
-
...opts,
|
|
2839
|
-
maxQueueSize,
|
|
2840
|
-
key: KEY_DEFAULT
|
|
2841
|
-
})
|
|
2842
|
-
};
|
|
2843
|
-
this._limiterFlexible = limiterFlexible;
|
|
2844
|
-
this._maxQueueSize = maxQueueSize;
|
|
2845
|
-
}
|
|
2846
|
-
getTokensRemaining(key = KEY_DEFAULT) {
|
|
2847
|
-
if (this._queueLimiters[key]) {
|
|
2848
|
-
return this._queueLimiters[key].getTokensRemaining();
|
|
2849
|
-
} else {
|
|
2850
|
-
return Promise.resolve(this._limiterFlexible.points);
|
|
2851
|
-
}
|
|
2852
|
-
}
|
|
2853
|
-
removeTokens(tokens, key = KEY_DEFAULT) {
|
|
2854
|
-
if (!this._queueLimiters[key]) {
|
|
2855
|
-
this._queueLimiters[key] = new RateLimiterQueueInternal(
|
|
2856
|
-
this._limiterFlexible,
|
|
2857
|
-
{
|
|
2858
|
-
key,
|
|
2859
|
-
maxQueueSize: this._maxQueueSize
|
|
2860
|
-
}
|
|
2861
|
-
);
|
|
2862
|
-
}
|
|
2863
|
-
return this._queueLimiters[key].removeTokens(tokens);
|
|
2864
|
-
}
|
|
2865
|
-
};
|
|
2866
|
-
var RateLimiterQueueInternal = class {
|
|
2867
|
-
constructor(limiterFlexible, opts = {
|
|
2868
|
-
maxQueueSize: MAX_QUEUE_SIZE,
|
|
2869
|
-
key: KEY_DEFAULT
|
|
2870
|
-
}) {
|
|
2871
|
-
this._key = opts.key;
|
|
2872
|
-
this._waitTimeout = null;
|
|
2873
|
-
this._queue = [];
|
|
2874
|
-
this._limiterFlexible = limiterFlexible;
|
|
2875
|
-
this._maxQueueSize = opts.maxQueueSize;
|
|
2876
|
-
}
|
|
2877
|
-
getTokensRemaining() {
|
|
2878
|
-
return this._limiterFlexible.get(this._key).then((rlRes) => {
|
|
2879
|
-
return rlRes !== null ? rlRes.remainingPoints : this._limiterFlexible.points;
|
|
2880
|
-
});
|
|
2881
|
-
}
|
|
2882
|
-
removeTokens(tokens) {
|
|
2883
|
-
const _this = this;
|
|
2884
|
-
return new Promise((resolve, reject) => {
|
|
2885
|
-
if (tokens > _this._limiterFlexible.points) {
|
|
2886
|
-
reject(new RateLimiterQueueError(`Requested tokens ${tokens} exceeds maximum ${_this._limiterFlexible.points} tokens per interval`));
|
|
2887
|
-
return;
|
|
2888
|
-
}
|
|
2889
|
-
if (_this._queue.length > 0) {
|
|
2890
|
-
_this._queueRequest.call(_this, resolve, reject, tokens);
|
|
2891
|
-
} else {
|
|
2892
|
-
_this._limiterFlexible.consume(_this._key, tokens).then((res) => {
|
|
2893
|
-
resolve(res.remainingPoints);
|
|
2894
|
-
}).catch((rej) => {
|
|
2895
|
-
if (rej instanceof Error) {
|
|
2896
|
-
reject(rej);
|
|
2897
|
-
} else {
|
|
2898
|
-
_this._queueRequest.call(_this, resolve, reject, tokens);
|
|
2899
|
-
if (_this._waitTimeout === null) {
|
|
2900
|
-
_this._waitTimeout = setTimeout(_this._processFIFO.bind(_this), rej.msBeforeNext);
|
|
2901
|
-
}
|
|
2902
|
-
}
|
|
2903
|
-
});
|
|
2904
|
-
}
|
|
2905
|
-
});
|
|
2906
|
-
}
|
|
2907
|
-
_queueRequest(resolve, reject, tokens) {
|
|
2908
|
-
const _this = this;
|
|
2909
|
-
if (_this._queue.length < _this._maxQueueSize) {
|
|
2910
|
-
_this._queue.push({ resolve, reject, tokens });
|
|
2911
|
-
} else {
|
|
2912
|
-
reject(new RateLimiterQueueError(`Number of requests reached it's maximum ${_this._maxQueueSize}`));
|
|
2913
|
-
}
|
|
2914
|
-
}
|
|
2915
|
-
_processFIFO() {
|
|
2916
|
-
const _this = this;
|
|
2917
|
-
if (_this._waitTimeout !== null) {
|
|
2918
|
-
clearTimeout(_this._waitTimeout);
|
|
2919
|
-
_this._waitTimeout = null;
|
|
2920
|
-
}
|
|
2921
|
-
if (_this._queue.length === 0) {
|
|
2922
|
-
return;
|
|
2923
|
-
}
|
|
2924
|
-
const item = _this._queue.shift();
|
|
2925
|
-
_this._limiterFlexible.consume(_this._key, item.tokens).then((res) => {
|
|
2926
|
-
item.resolve(res.remainingPoints);
|
|
2927
|
-
_this._processFIFO.call(_this);
|
|
2928
|
-
}).catch((rej) => {
|
|
2929
|
-
if (rej instanceof Error) {
|
|
2930
|
-
item.reject(rej);
|
|
2931
|
-
_this._processFIFO.call(_this);
|
|
2932
|
-
} else {
|
|
2933
|
-
_this._queue.unshift(item);
|
|
2934
|
-
if (_this._waitTimeout === null) {
|
|
2935
|
-
_this._waitTimeout = setTimeout(_this._processFIFO.bind(_this), rej.msBeforeNext);
|
|
2936
|
-
}
|
|
2937
|
-
}
|
|
2938
|
-
});
|
|
2939
|
-
}
|
|
2940
|
-
};
|
|
2941
|
-
}
|
|
2942
|
-
});
|
|
2943
|
-
|
|
2944
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/BurstyRateLimiter.js
|
|
2945
|
-
var require_BurstyRateLimiter = __commonJS({
|
|
2946
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/BurstyRateLimiter.js"(exports2, module2) {
|
|
2947
|
-
"use strict";
|
|
2948
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
2949
|
-
module2.exports = class BurstyRateLimiter {
|
|
2950
|
-
constructor(rateLimiter, burstLimiter) {
|
|
2951
|
-
this._rateLimiter = rateLimiter;
|
|
2952
|
-
this._burstLimiter = burstLimiter;
|
|
2953
|
-
}
|
|
2954
|
-
/**
|
|
2955
|
-
* Merge rate limiter response objects. Responses can be null
|
|
2956
|
-
*
|
|
2957
|
-
* @param {RateLimiterRes} [rlRes] Rate limiter response
|
|
2958
|
-
* @param {RateLimiterRes} [blRes] Bursty limiter response
|
|
2959
|
-
*/
|
|
2960
|
-
_combineRes(rlRes, blRes) {
|
|
2961
|
-
if (!rlRes) {
|
|
2962
|
-
return null;
|
|
2963
|
-
}
|
|
2964
|
-
return new RateLimiterRes2(
|
|
2965
|
-
rlRes.remainingPoints,
|
|
2966
|
-
Math.min(rlRes.msBeforeNext, blRes ? blRes.msBeforeNext : 0),
|
|
2967
|
-
rlRes.consumedPoints,
|
|
2968
|
-
rlRes.isFirstInDuration
|
|
2969
|
-
);
|
|
2970
|
-
}
|
|
2971
|
-
/**
|
|
2972
|
-
* @param key
|
|
2973
|
-
* @param pointsToConsume
|
|
2974
|
-
* @param options
|
|
2975
|
-
* @returns {Promise<any>}
|
|
2976
|
-
*/
|
|
2977
|
-
consume(key, pointsToConsume = 1, options = {}) {
|
|
2978
|
-
return this._rateLimiter.consume(key, pointsToConsume, options).catch((rlRej) => {
|
|
2979
|
-
if (rlRej instanceof RateLimiterRes2) {
|
|
2980
|
-
return this._burstLimiter.consume(key, pointsToConsume, options).then((blRes) => {
|
|
2981
|
-
return Promise.resolve(this._combineRes(rlRej, blRes));
|
|
2982
|
-
}).catch(
|
|
2983
|
-
(blRej) => {
|
|
2984
|
-
if (blRej instanceof RateLimiterRes2) {
|
|
2985
|
-
return Promise.reject(this._combineRes(rlRej, blRej));
|
|
2986
|
-
} else {
|
|
2987
|
-
return Promise.reject(blRej);
|
|
2988
|
-
}
|
|
2989
|
-
}
|
|
2990
|
-
);
|
|
2991
|
-
} else {
|
|
2992
|
-
return Promise.reject(rlRej);
|
|
2993
|
-
}
|
|
2994
|
-
});
|
|
2995
|
-
}
|
|
2996
|
-
/**
|
|
2997
|
-
* It doesn't expose available points from burstLimiter
|
|
2998
|
-
*
|
|
2999
|
-
* @param key
|
|
3000
|
-
* @returns {Promise<RateLimiterRes>}
|
|
3001
|
-
*/
|
|
3002
|
-
get(key) {
|
|
3003
|
-
return Promise.all([
|
|
3004
|
-
this._rateLimiter.get(key),
|
|
3005
|
-
this._burstLimiter.get(key)
|
|
3006
|
-
]).then(([rlRes, blRes]) => {
|
|
3007
|
-
return this._combineRes(rlRes, blRes);
|
|
3008
|
-
});
|
|
3009
|
-
}
|
|
3010
|
-
get points() {
|
|
3011
|
-
return this._rateLimiter.points;
|
|
3012
|
-
}
|
|
3013
|
-
};
|
|
3014
|
-
}
|
|
3015
|
-
});
|
|
3016
|
-
|
|
3017
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterDynamo.js
|
|
3018
|
-
var require_RateLimiterDynamo = __commonJS({
|
|
3019
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterDynamo.js"(exports2, module2) {
|
|
3020
|
-
"use strict";
|
|
3021
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
3022
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
3023
|
-
var DynamoItem = class {
|
|
3024
|
-
/**
|
|
3025
|
-
* Create a DynamoItem.
|
|
3026
|
-
* @param {string} rlKey - The key for the rate limiter.
|
|
3027
|
-
* @param {number} points - The number of points.
|
|
3028
|
-
* @param {number} expire - The expiration time in seconds.
|
|
3029
|
-
*/
|
|
3030
|
-
constructor(rlKey, points, expire) {
|
|
3031
|
-
this.key = rlKey;
|
|
3032
|
-
this.points = points;
|
|
3033
|
-
this.expire = expire;
|
|
3034
|
-
}
|
|
3035
|
-
};
|
|
3036
|
-
var DEFAULT_READ_CAPACITY_UNITS = 25;
|
|
3037
|
-
var DEFAULT_WRITE_CAPACITY_UNITS = 25;
|
|
3038
|
-
var RateLimiterDynamo = class extends RateLimiterStoreAbstract {
|
|
3039
|
-
/**
|
|
3040
|
-
* Constructs a new instance of the class.
|
|
3041
|
-
* The storeClient MUST be an instance of AWS.DynamoDB NOT of AWS.DynamoDBClient.
|
|
3042
|
-
*
|
|
3043
|
-
* @param {Object} opts - The options for the constructor.
|
|
3044
|
-
* @param {function} cb - The callback function (optional).
|
|
3045
|
-
* @return {void}
|
|
3046
|
-
*/
|
|
3047
|
-
constructor(opts, cb = null) {
|
|
3048
|
-
super(opts);
|
|
3049
|
-
this.client = opts.storeClient;
|
|
3050
|
-
this.tableName = opts.tableName;
|
|
3051
|
-
this.tableCreated = opts.tableCreated;
|
|
3052
|
-
this.ttlManuallySet = opts.ttlSet;
|
|
3053
|
-
if (!this.tableCreated) {
|
|
3054
|
-
this._createTable(opts.dynamoTableOpts).then((data) => {
|
|
3055
|
-
this.tableCreated = true;
|
|
3056
|
-
this._setTTL().finally(() => {
|
|
3057
|
-
if (typeof cb === "function") {
|
|
3058
|
-
cb();
|
|
3059
|
-
}
|
|
3060
|
-
});
|
|
3061
|
-
}).catch((err) => {
|
|
3062
|
-
if (typeof cb === "function") {
|
|
3063
|
-
cb(err);
|
|
3064
|
-
} else {
|
|
3065
|
-
throw err;
|
|
3066
|
-
}
|
|
3067
|
-
});
|
|
3068
|
-
} else {
|
|
3069
|
-
this._setTTL().finally(() => {
|
|
3070
|
-
if (typeof cb === "function") {
|
|
3071
|
-
cb();
|
|
3072
|
-
}
|
|
3073
|
-
});
|
|
3074
|
-
}
|
|
3075
|
-
}
|
|
3076
|
-
get tableName() {
|
|
3077
|
-
return this._tableName;
|
|
3078
|
-
}
|
|
3079
|
-
set tableName(value) {
|
|
3080
|
-
this._tableName = typeof value === "undefined" ? "node-rate-limiter-flexible" : value;
|
|
3081
|
-
}
|
|
3082
|
-
get tableCreated() {
|
|
3083
|
-
return this._tableCreated;
|
|
3084
|
-
}
|
|
3085
|
-
set tableCreated(value) {
|
|
3086
|
-
this._tableCreated = typeof value === "undefined" ? false : !!value;
|
|
3087
|
-
}
|
|
3088
|
-
/**
|
|
3089
|
-
* Creates a table in the database. Return null if the table already exists.
|
|
3090
|
-
*
|
|
3091
|
-
* @param {{readCapacityUnits: number, writeCapacityUnits: number}} tableOpts
|
|
3092
|
-
* @return {Promise} A promise that resolves with the result of creating the table.
|
|
3093
|
-
*/
|
|
3094
|
-
async _createTable(tableOpts) {
|
|
3095
|
-
const params = {
|
|
3096
|
-
TableName: this.tableName,
|
|
3097
|
-
AttributeDefinitions: [
|
|
3098
|
-
{
|
|
3099
|
-
AttributeName: "key",
|
|
3100
|
-
AttributeType: "S"
|
|
3101
|
-
}
|
|
3102
|
-
],
|
|
3103
|
-
KeySchema: [
|
|
3104
|
-
{
|
|
3105
|
-
AttributeName: "key",
|
|
3106
|
-
KeyType: "HASH"
|
|
3107
|
-
}
|
|
3108
|
-
],
|
|
3109
|
-
ProvisionedThroughput: {
|
|
3110
|
-
ReadCapacityUnits: tableOpts && tableOpts.readCapacityUnits ? tableOpts.readCapacityUnits : DEFAULT_READ_CAPACITY_UNITS,
|
|
3111
|
-
WriteCapacityUnits: tableOpts && tableOpts.writeCapacityUnits ? tableOpts.writeCapacityUnits : DEFAULT_WRITE_CAPACITY_UNITS
|
|
3112
|
-
}
|
|
3113
|
-
};
|
|
3114
|
-
try {
|
|
3115
|
-
const data = await this.client.createTable(params);
|
|
3116
|
-
return data;
|
|
3117
|
-
} catch (err) {
|
|
3118
|
-
if (err.__type && err.__type.includes("ResourceInUseException")) {
|
|
3119
|
-
return null;
|
|
3120
|
-
} else {
|
|
3121
|
-
throw err;
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
|
-
}
|
|
3125
|
-
/**
|
|
3126
|
-
* Retrieves an item from the table based on the provided key.
|
|
3127
|
-
*
|
|
3128
|
-
* @param {string} rlKey - The key used to retrieve the item.
|
|
3129
|
-
* @throws {Error} Throws an error if the table is not created yet.
|
|
3130
|
-
* @return {DynamoItem|null} - The retrieved item, or null if it doesn't exist.
|
|
3131
|
-
*/
|
|
3132
|
-
async _get(rlKey) {
|
|
3133
|
-
if (!this.tableCreated) {
|
|
3134
|
-
throw new Error("Table is not created yet");
|
|
3135
|
-
}
|
|
3136
|
-
const params = {
|
|
3137
|
-
TableName: this.tableName,
|
|
3138
|
-
Key: {
|
|
3139
|
-
key: { S: rlKey }
|
|
3140
|
-
}
|
|
3141
|
-
};
|
|
3142
|
-
const data = await this.client.getItem(params);
|
|
3143
|
-
if (!data.Item) {
|
|
3144
|
-
return null;
|
|
3145
|
-
}
|
|
3146
|
-
const item = new DynamoItem(
|
|
3147
|
-
data.Item.key.S,
|
|
3148
|
-
Number(data.Item.points.N),
|
|
3149
|
-
Number(data.Item.expire.N)
|
|
3150
|
-
);
|
|
3151
|
-
const dateNowSec = Date.now() / 1e3;
|
|
3152
|
-
if (item.expire !== -1 && item.expire <= dateNowSec) {
|
|
3153
|
-
return null;
|
|
3154
|
-
}
|
|
3155
|
-
return item;
|
|
3156
|
-
}
|
|
3157
|
-
/**
|
|
3158
|
-
* Deletes an item from the table based on the given rlKey.
|
|
3159
|
-
*
|
|
3160
|
-
* @param {string} rlKey - The rlKey of the item to delete.
|
|
3161
|
-
* @throws {Error} Throws an error if the table is not created yet.
|
|
3162
|
-
* @return {boolean} Returns true if the item was successfully deleted, otherwise false.
|
|
3163
|
-
*/
|
|
3164
|
-
async _delete(rlKey) {
|
|
3165
|
-
if (!this.tableCreated) {
|
|
3166
|
-
throw new Error("Table is not created yet");
|
|
3167
|
-
}
|
|
3168
|
-
const params = {
|
|
3169
|
-
TableName: this.tableName,
|
|
3170
|
-
Key: {
|
|
3171
|
-
key: { S: rlKey }
|
|
3172
|
-
},
|
|
3173
|
-
ConditionExpression: "attribute_exists(#k)",
|
|
3174
|
-
ExpressionAttributeNames: {
|
|
3175
|
-
"#k": "key"
|
|
3176
|
-
}
|
|
3177
|
-
};
|
|
3178
|
-
try {
|
|
3179
|
-
const data = await this._client.deleteItem(params);
|
|
3180
|
-
return data.$metadata.httpStatusCode === 200;
|
|
3181
|
-
} catch (err) {
|
|
3182
|
-
if (err.__type && err.__type.includes("ConditionalCheckFailedException")) {
|
|
3183
|
-
return false;
|
|
3184
|
-
} else {
|
|
3185
|
-
throw err;
|
|
3186
|
-
}
|
|
3187
|
-
}
|
|
3188
|
-
}
|
|
3189
|
-
/**
|
|
3190
|
-
* Implemented with DynamoDB Atomic Counters. 3 calls are made to DynamoDB but each call is atomic.
|
|
3191
|
-
* From the documentation: "UpdateItem calls are naturally serialized within DynamoDB,
|
|
3192
|
-
* so there are no race condition concerns with making multiple simultaneous calls."
|
|
3193
|
-
* See: https://aws.amazon.com/it/blogs/database/implement-resource-counters-with-amazon-dynamodb/
|
|
3194
|
-
* @param {*} rlKey
|
|
3195
|
-
* @param {*} points
|
|
3196
|
-
* @param {*} msDuration
|
|
3197
|
-
* @param {*} forceExpire
|
|
3198
|
-
* @param {*} options
|
|
3199
|
-
* @returns
|
|
3200
|
-
*/
|
|
3201
|
-
async _upsert(rlKey, points, msDuration, forceExpire = false, options = {}) {
|
|
3202
|
-
if (!this.tableCreated) {
|
|
3203
|
-
throw new Error("Table is not created yet");
|
|
3204
|
-
}
|
|
3205
|
-
const dateNow = Date.now();
|
|
3206
|
-
const dateNowSec = dateNow / 1e3;
|
|
3207
|
-
const newExpireSec = msDuration > 0 ? (dateNow + msDuration) / 1e3 : -1;
|
|
3208
|
-
if (forceExpire) {
|
|
3209
|
-
return await this._baseUpsert({
|
|
3210
|
-
TableName: this.tableName,
|
|
3211
|
-
Key: { key: { S: rlKey } },
|
|
3212
|
-
UpdateExpression: "SET points = :points, expire = :expire",
|
|
3213
|
-
ExpressionAttributeValues: {
|
|
3214
|
-
":points": { N: points.toString() },
|
|
3215
|
-
":expire": { N: newExpireSec.toString() }
|
|
3216
|
-
},
|
|
3217
|
-
ReturnValues: "ALL_NEW"
|
|
3218
|
-
});
|
|
3219
|
-
}
|
|
3220
|
-
try {
|
|
3221
|
-
return await this._baseUpsert({
|
|
3222
|
-
TableName: this.tableName,
|
|
3223
|
-
Key: { key: { S: rlKey } },
|
|
3224
|
-
UpdateExpression: "SET points = :new_points, expire = :new_expire",
|
|
3225
|
-
ExpressionAttributeValues: {
|
|
3226
|
-
":new_points": { N: points.toString() },
|
|
3227
|
-
":new_expire": { N: newExpireSec.toString() },
|
|
3228
|
-
":where_expire": { N: dateNowSec.toString() }
|
|
3229
|
-
},
|
|
3230
|
-
ConditionExpression: "expire <= :where_expire OR attribute_not_exists(points)",
|
|
3231
|
-
ReturnValues: "ALL_NEW"
|
|
3232
|
-
});
|
|
3233
|
-
} catch (err) {
|
|
3234
|
-
return await this._baseUpsert({
|
|
3235
|
-
TableName: this.tableName,
|
|
3236
|
-
Key: { key: { S: rlKey } },
|
|
3237
|
-
UpdateExpression: "SET points = points + :new_points",
|
|
3238
|
-
ExpressionAttributeValues: {
|
|
3239
|
-
":new_points": { N: points.toString() },
|
|
3240
|
-
":where_expire": { N: dateNowSec.toString() }
|
|
3241
|
-
},
|
|
3242
|
-
ConditionExpression: "expire > :where_expire",
|
|
3243
|
-
ReturnValues: "ALL_NEW"
|
|
3244
|
-
});
|
|
3245
|
-
}
|
|
3246
|
-
}
|
|
3247
|
-
/**
|
|
3248
|
-
* Asynchronously upserts data into the table. params is a DynamoDB params object.
|
|
3249
|
-
*
|
|
3250
|
-
* @param {Object} params - The parameters for the upsert operation.
|
|
3251
|
-
* @throws {Error} Throws an error if the table is not created yet.
|
|
3252
|
-
* @return {DynamoItem} Returns a DynamoItem object with the updated data.
|
|
3253
|
-
*/
|
|
3254
|
-
async _baseUpsert(params) {
|
|
3255
|
-
if (!this.tableCreated) {
|
|
3256
|
-
throw new Error("Table is not created yet");
|
|
3257
|
-
}
|
|
3258
|
-
try {
|
|
3259
|
-
const data = await this.client.updateItem(params);
|
|
3260
|
-
return new DynamoItem(
|
|
3261
|
-
data.Attributes.key.S,
|
|
3262
|
-
Number(data.Attributes.points.N),
|
|
3263
|
-
Number(data.Attributes.expire.N)
|
|
3264
|
-
);
|
|
3265
|
-
} catch (err) {
|
|
3266
|
-
throw err;
|
|
3267
|
-
}
|
|
3268
|
-
}
|
|
3269
|
-
/**
|
|
3270
|
-
* Sets the Time-to-Live (TTL) for the table. TTL use the expire field in the table.
|
|
3271
|
-
* See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/howitworks-ttl.html
|
|
3272
|
-
*
|
|
3273
|
-
* @return {Promise} A promise that resolves when the TTL is successfully set.
|
|
3274
|
-
* @throws {Error} Throws an error if the table is not created yet.
|
|
3275
|
-
* @returns {Promise}
|
|
3276
|
-
*/
|
|
3277
|
-
async _setTTL() {
|
|
3278
|
-
if (!this.tableCreated) {
|
|
3279
|
-
throw new Error("Table is not created yet");
|
|
3280
|
-
}
|
|
3281
|
-
try {
|
|
3282
|
-
const isTTLSet = await this._isTTLSet();
|
|
3283
|
-
if (isTTLSet) {
|
|
3284
|
-
return;
|
|
3285
|
-
}
|
|
3286
|
-
const params = {
|
|
3287
|
-
TableName: this.tableName,
|
|
3288
|
-
TimeToLiveSpecification: {
|
|
3289
|
-
AttributeName: "expire",
|
|
3290
|
-
Enabled: true
|
|
3291
|
-
}
|
|
3292
|
-
};
|
|
3293
|
-
const res = await this.client.updateTimeToLive(params);
|
|
3294
|
-
return res;
|
|
3295
|
-
} catch (err) {
|
|
3296
|
-
throw err;
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
3299
|
-
/**
|
|
3300
|
-
* Checks if the Time To Live (TTL) feature is set for the DynamoDB table.
|
|
3301
|
-
*
|
|
3302
|
-
* @return {boolean} Returns true if the TTL feature is enabled for the table, otherwise false.
|
|
3303
|
-
* @throws {Error} Throws an error if the table is not created yet or if there is an error while checking the TTL status.
|
|
3304
|
-
*/
|
|
3305
|
-
async _isTTLSet() {
|
|
3306
|
-
if (!this.tableCreated) {
|
|
3307
|
-
throw new Error("Table is not created yet");
|
|
3308
|
-
}
|
|
3309
|
-
if (this.ttlManuallySet) {
|
|
3310
|
-
return true;
|
|
3311
|
-
}
|
|
3312
|
-
try {
|
|
3313
|
-
const res = await this.client.describeTimeToLive({ TableName: this.tableName });
|
|
3314
|
-
return res.$metadata.httpStatusCode == 200 && res.TimeToLiveDescription.TimeToLiveStatus === "ENABLED" && res.TimeToLiveDescription.AttributeName === "expire";
|
|
3315
|
-
} catch (err) {
|
|
3316
|
-
throw err;
|
|
3317
|
-
}
|
|
3318
|
-
}
|
|
3319
|
-
/**
|
|
3320
|
-
* Generate a RateLimiterRes object based on the provided parameters.
|
|
3321
|
-
*
|
|
3322
|
-
* @param {string} rlKey - The key for the rate limiter.
|
|
3323
|
-
* @param {number} changedPoints - The number of points that have changed.
|
|
3324
|
-
* @param {DynamoItem} result - The result object of _get() method.
|
|
3325
|
-
* @returns {RateLimiterRes} - The generated RateLimiterRes object.
|
|
3326
|
-
*/
|
|
3327
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
3328
|
-
const res = new RateLimiterRes2();
|
|
3329
|
-
res.isFirstInDuration = changedPoints === result.points;
|
|
3330
|
-
res.consumedPoints = res.isFirstInDuration ? changedPoints : result.points;
|
|
3331
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
3332
|
-
res.msBeforeNext = result.expire != -1 ? Math.max(result.expire * 1e3 - Date.now(), 0) : -1;
|
|
3333
|
-
return res;
|
|
3334
|
-
}
|
|
3335
|
-
};
|
|
3336
|
-
module2.exports = RateLimiterDynamo;
|
|
3337
|
-
}
|
|
3338
|
-
});
|
|
3339
|
-
|
|
3340
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterPrisma.js
|
|
3341
|
-
var require_RateLimiterPrisma = __commonJS({
|
|
3342
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterPrisma.js"(exports2, module2) {
|
|
3343
|
-
"use strict";
|
|
3344
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
3345
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
3346
|
-
var RateLimiterPrisma = class extends RateLimiterStoreAbstract {
|
|
3347
|
-
/**
|
|
3348
|
-
* Constructor for the rate limiter
|
|
3349
|
-
* @param {Object} opts - Options for the rate limiter
|
|
3350
|
-
*/
|
|
3351
|
-
constructor(opts) {
|
|
3352
|
-
super(opts);
|
|
3353
|
-
this.modelName = opts.tableName || "RateLimiterFlexible";
|
|
3354
|
-
this.prismaClient = opts.storeClient;
|
|
3355
|
-
this.clearExpiredByTimeout = opts.clearExpiredByTimeout || true;
|
|
3356
|
-
if (!this.prismaClient) {
|
|
3357
|
-
throw new Error("Prisma client is not provided");
|
|
3358
|
-
}
|
|
3359
|
-
if (this.clearExpiredByTimeout) {
|
|
3360
|
-
this._clearExpiredHourAgo();
|
|
3361
|
-
}
|
|
3362
|
-
}
|
|
3363
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
3364
|
-
const res = new RateLimiterRes2();
|
|
3365
|
-
let doc = result;
|
|
3366
|
-
res.isFirstInDuration = doc.points === changedPoints;
|
|
3367
|
-
res.consumedPoints = doc.points;
|
|
3368
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
3369
|
-
res.msBeforeNext = doc.expire !== null ? Math.max(new Date(doc.expire).getTime() - Date.now(), 0) : -1;
|
|
3370
|
-
return res;
|
|
3371
|
-
}
|
|
3372
|
-
_upsert(key, points, msDuration, forceExpire = false) {
|
|
3373
|
-
if (!this.prismaClient) {
|
|
3374
|
-
return Promise.reject(new Error("Prisma client is not established"));
|
|
3375
|
-
}
|
|
3376
|
-
const now = /* @__PURE__ */ new Date();
|
|
3377
|
-
const newExpire = msDuration > 0 ? new Date(now.getTime() + msDuration) : null;
|
|
3378
|
-
return this.prismaClient.$transaction(async (prisma) => {
|
|
3379
|
-
const existingRecord = await prisma[this.modelName].findFirst({
|
|
3380
|
-
where: { key }
|
|
3381
|
-
});
|
|
3382
|
-
if (existingRecord) {
|
|
3383
|
-
const shouldUpdateExpire = forceExpire || !existingRecord.expire || existingRecord.expire <= now || newExpire === null;
|
|
3384
|
-
return prisma[this.modelName].update({
|
|
3385
|
-
where: { key },
|
|
3386
|
-
data: {
|
|
3387
|
-
points: !shouldUpdateExpire ? existingRecord.points + points : points,
|
|
3388
|
-
...shouldUpdateExpire && { expire: newExpire }
|
|
3389
|
-
}
|
|
3390
|
-
});
|
|
3391
|
-
} else {
|
|
3392
|
-
return prisma[this.modelName].create({
|
|
3393
|
-
data: {
|
|
3394
|
-
key,
|
|
3395
|
-
points,
|
|
3396
|
-
expire: newExpire
|
|
3397
|
-
}
|
|
3398
|
-
});
|
|
3399
|
-
}
|
|
3400
|
-
});
|
|
3401
|
-
}
|
|
3402
|
-
_get(rlKey) {
|
|
3403
|
-
if (!this.prismaClient) {
|
|
3404
|
-
return Promise.reject(new Error("Prisma client is not established"));
|
|
3405
|
-
}
|
|
3406
|
-
return this.prismaClient[this.modelName].findFirst({
|
|
3407
|
-
where: {
|
|
3408
|
-
AND: [
|
|
3409
|
-
{ key: rlKey },
|
|
3410
|
-
{
|
|
3411
|
-
OR: [
|
|
3412
|
-
{ expire: { gt: /* @__PURE__ */ new Date() } },
|
|
3413
|
-
{ expire: null }
|
|
3414
|
-
]
|
|
3415
|
-
}
|
|
3416
|
-
]
|
|
3417
|
-
}
|
|
3418
|
-
});
|
|
3419
|
-
}
|
|
3420
|
-
_delete(rlKey) {
|
|
3421
|
-
if (!this.prismaClient) {
|
|
3422
|
-
return Promise.reject(new Error("Prisma client is not established"));
|
|
3423
|
-
}
|
|
3424
|
-
return this.prismaClient[this.modelName].deleteMany({
|
|
3425
|
-
where: {
|
|
3426
|
-
key: rlKey
|
|
3427
|
-
}
|
|
3428
|
-
}).then((res) => res.count > 0);
|
|
3429
|
-
}
|
|
3430
|
-
_clearExpiredHourAgo() {
|
|
3431
|
-
if (this._clearExpiredTimeoutId) {
|
|
3432
|
-
clearTimeout(this._clearExpiredTimeoutId);
|
|
3433
|
-
}
|
|
3434
|
-
this._clearExpiredTimeoutId = setTimeout(async () => {
|
|
3435
|
-
await this.prismaClient[this.modelName].deleteMany({
|
|
3436
|
-
where: {
|
|
3437
|
-
expire: {
|
|
3438
|
-
lt: new Date(Date.now() - 36e5)
|
|
3439
|
-
}
|
|
3440
|
-
}
|
|
3441
|
-
});
|
|
3442
|
-
this._clearExpiredHourAgo();
|
|
3443
|
-
}, 3e5);
|
|
3444
|
-
this._clearExpiredTimeoutId.unref();
|
|
3445
|
-
}
|
|
3446
|
-
};
|
|
3447
|
-
module2.exports = RateLimiterPrisma;
|
|
3448
|
-
}
|
|
3449
|
-
});
|
|
3450
|
-
|
|
3451
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterDrizzle.js
|
|
3452
|
-
var require_RateLimiterDrizzle = __commonJS({
|
|
3453
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterDrizzle.js"(exports2, module2) {
|
|
3454
|
-
"use strict";
|
|
3455
|
-
var drizzleOperators = null;
|
|
3456
|
-
var CLEANUP_INTERVAL_MS = 3e5;
|
|
3457
|
-
var EXPIRED_THRESHOLD_MS = 36e5;
|
|
3458
|
-
var RateLimiterDrizzleError = class extends Error {
|
|
3459
|
-
constructor(message) {
|
|
3460
|
-
super(message);
|
|
3461
|
-
this.name = "RateLimiterDrizzleError";
|
|
3462
|
-
}
|
|
3463
|
-
};
|
|
3464
|
-
async function getDrizzleOperators() {
|
|
3465
|
-
if (drizzleOperators) return drizzleOperators;
|
|
3466
|
-
try {
|
|
3467
|
-
let getPackageName2 = function() {
|
|
3468
|
-
return ["drizzle", "orm"].join("-");
|
|
3469
|
-
};
|
|
3470
|
-
var getPackageName = getPackageName2;
|
|
3471
|
-
const drizzleOrm = await import(`${getPackageName2()}`);
|
|
3472
|
-
const { and, or, gt, lt, eq, isNull, sql } = drizzleOrm.default || drizzleOrm;
|
|
3473
|
-
drizzleOperators = { and, or, gt, lt, eq, isNull, sql };
|
|
3474
|
-
return drizzleOperators;
|
|
3475
|
-
} catch (error48) {
|
|
3476
|
-
throw new RateLimiterDrizzleError(
|
|
3477
|
-
"drizzle-orm is not installed. Please install drizzle-orm to use RateLimiterDrizzle."
|
|
3478
|
-
);
|
|
3479
|
-
}
|
|
3480
|
-
}
|
|
3481
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
3482
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
3483
|
-
var RateLimiterDrizzle = class extends RateLimiterStoreAbstract {
|
|
3484
|
-
constructor(opts) {
|
|
3485
|
-
super(opts);
|
|
3486
|
-
if (!opts?.schema) {
|
|
3487
|
-
throw new RateLimiterDrizzleError("Drizzle schema is required");
|
|
3488
|
-
}
|
|
3489
|
-
if (!opts?.storeClient) {
|
|
3490
|
-
throw new RateLimiterDrizzleError("Drizzle client is required");
|
|
3491
|
-
}
|
|
3492
|
-
this.schema = opts.schema;
|
|
3493
|
-
this.drizzleClient = opts.storeClient;
|
|
3494
|
-
this.clearExpiredByTimeout = opts.clearExpiredByTimeout ?? true;
|
|
3495
|
-
if (this.clearExpiredByTimeout) {
|
|
3496
|
-
this._clearExpiredHourAgo();
|
|
3497
|
-
}
|
|
3498
|
-
}
|
|
3499
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
3500
|
-
const res = new RateLimiterRes2();
|
|
3501
|
-
let doc = result;
|
|
3502
|
-
res.isFirstInDuration = doc.points === changedPoints;
|
|
3503
|
-
res.consumedPoints = doc.points;
|
|
3504
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
3505
|
-
res.msBeforeNext = doc.expire !== null ? Math.max(new Date(doc.expire).getTime() - Date.now(), 0) : -1;
|
|
3506
|
-
return res;
|
|
3507
|
-
}
|
|
3508
|
-
async _upsert(key, points, msDuration, forceExpire = false) {
|
|
3509
|
-
if (!this.drizzleClient) {
|
|
3510
|
-
return Promise.reject(new RateLimiterDrizzleError("Drizzle client is not established"));
|
|
3511
|
-
}
|
|
3512
|
-
const { eq, sql } = await getDrizzleOperators();
|
|
3513
|
-
const now = /* @__PURE__ */ new Date();
|
|
3514
|
-
const newExpire = msDuration > 0 ? new Date(now.getTime() + msDuration) : null;
|
|
3515
|
-
const query = await this.drizzleClient.transaction(async (tx) => {
|
|
3516
|
-
const [existingRecord] = await tx.select().from(this.schema).where(eq(this.schema.key, key)).limit(1);
|
|
3517
|
-
const shouldUpdateExpire = forceExpire || !existingRecord?.expire || existingRecord?.expire <= now || newExpire === null;
|
|
3518
|
-
const [data] = await tx.insert(this.schema).values({
|
|
3519
|
-
key,
|
|
3520
|
-
points,
|
|
3521
|
-
expire: newExpire
|
|
3522
|
-
}).onConflictDoUpdate({
|
|
3523
|
-
target: this.schema.key,
|
|
3524
|
-
set: {
|
|
3525
|
-
points: !shouldUpdateExpire ? sql`${this.schema.points} + ${points}` : points,
|
|
3526
|
-
...shouldUpdateExpire && { expire: newExpire }
|
|
3527
|
-
}
|
|
3528
|
-
}).returning();
|
|
3529
|
-
return data;
|
|
3530
|
-
});
|
|
3531
|
-
return query;
|
|
3532
|
-
}
|
|
3533
|
-
async _get(rlKey) {
|
|
3534
|
-
if (!this.drizzleClient) {
|
|
3535
|
-
return Promise.reject(new RateLimiterDrizzleError("Drizzle client is not established"));
|
|
3536
|
-
}
|
|
3537
|
-
const { and, or, gt, eq, isNull } = await getDrizzleOperators();
|
|
3538
|
-
const [response] = await this.drizzleClient.select().from(this.schema).where(
|
|
3539
|
-
and(
|
|
3540
|
-
eq(this.schema.key, rlKey),
|
|
3541
|
-
or(gt(this.schema.expire, /* @__PURE__ */ new Date()), isNull(this.schema.expire))
|
|
3542
|
-
)
|
|
3543
|
-
).limit(1);
|
|
3544
|
-
return response || null;
|
|
3545
|
-
}
|
|
3546
|
-
async _delete(rlKey) {
|
|
3547
|
-
if (!this.drizzleClient) {
|
|
3548
|
-
return Promise.reject(new RateLimiterDrizzleError("Drizzle client is not established"));
|
|
3549
|
-
}
|
|
3550
|
-
const { eq } = await getDrizzleOperators();
|
|
3551
|
-
const [result] = await this.drizzleClient.delete(this.schema).where(eq(this.schema.key, rlKey)).returning({ key: this.schema.key });
|
|
3552
|
-
return !!result?.key;
|
|
3553
|
-
}
|
|
3554
|
-
_clearExpiredHourAgo() {
|
|
3555
|
-
if (this._clearExpiredTimeoutId) {
|
|
3556
|
-
clearTimeout(this._clearExpiredTimeoutId);
|
|
3557
|
-
}
|
|
3558
|
-
this._clearExpiredTimeoutId = setTimeout(async () => {
|
|
3559
|
-
try {
|
|
3560
|
-
const { lt } = await getDrizzleOperators();
|
|
3561
|
-
await this.drizzleClient.delete(this.schema).where(lt(this.schema.expire, new Date(Date.now() - EXPIRED_THRESHOLD_MS)));
|
|
3562
|
-
} catch (error48) {
|
|
3563
|
-
console.warn("Failed to clear expired records:", error48);
|
|
3564
|
-
}
|
|
3565
|
-
this._clearExpiredHourAgo();
|
|
3566
|
-
}, CLEANUP_INTERVAL_MS);
|
|
3567
|
-
this._clearExpiredTimeoutId.unref();
|
|
3568
|
-
}
|
|
3569
|
-
};
|
|
3570
|
-
module2.exports = RateLimiterDrizzle;
|
|
3571
|
-
}
|
|
3572
|
-
});
|
|
3573
|
-
|
|
3574
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterDrizzleNonAtomic.js
|
|
3575
|
-
var require_RateLimiterDrizzleNonAtomic = __commonJS({
|
|
3576
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterDrizzleNonAtomic.js"(exports2, module2) {
|
|
3577
|
-
"use strict";
|
|
3578
|
-
var drizzleOperators = null;
|
|
3579
|
-
var CLEANUP_INTERVAL_MS = 3e5;
|
|
3580
|
-
var EXPIRED_THRESHOLD_MS = 36e5;
|
|
3581
|
-
var RateLimiterDrizzleError = class extends Error {
|
|
3582
|
-
constructor(message) {
|
|
3583
|
-
super(message);
|
|
3584
|
-
this.name = "RateLimiterDrizzleError";
|
|
3585
|
-
}
|
|
3586
|
-
};
|
|
3587
|
-
async function getDrizzleOperators() {
|
|
3588
|
-
if (drizzleOperators) return drizzleOperators;
|
|
3589
|
-
try {
|
|
3590
|
-
let getPackageName2 = function() {
|
|
3591
|
-
return ["drizzle", "orm"].join("-");
|
|
3592
|
-
};
|
|
3593
|
-
var getPackageName = getPackageName2;
|
|
3594
|
-
const drizzleOrm = await import(`${getPackageName2()}`);
|
|
3595
|
-
const { and, or, gt, lt, eq, isNull, sql } = drizzleOrm.default || drizzleOrm;
|
|
3596
|
-
drizzleOperators = { and, or, gt, lt, eq, isNull, sql };
|
|
3597
|
-
return drizzleOperators;
|
|
3598
|
-
} catch (error48) {
|
|
3599
|
-
throw new RateLimiterDrizzleError(
|
|
3600
|
-
"drizzle-orm is not installed. Please install drizzle-orm to use RateLimiterDrizzleNonAtomic."
|
|
3601
|
-
);
|
|
3602
|
-
}
|
|
3603
|
-
}
|
|
3604
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
3605
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
3606
|
-
var RateLimiterDrizzleNonAtomic = class extends RateLimiterStoreAbstract {
|
|
3607
|
-
constructor(opts) {
|
|
3608
|
-
super(opts);
|
|
3609
|
-
if (!opts?.schema) {
|
|
3610
|
-
throw new RateLimiterDrizzleError("Drizzle schema is required");
|
|
3611
|
-
}
|
|
3612
|
-
if (!opts?.storeClient) {
|
|
3613
|
-
throw new RateLimiterDrizzleError("Drizzle client is required");
|
|
3614
|
-
}
|
|
3615
|
-
this.schema = opts.schema;
|
|
3616
|
-
this.drizzleClient = opts.storeClient;
|
|
3617
|
-
this.clearExpiredByTimeout = opts.clearExpiredByTimeout ?? true;
|
|
3618
|
-
if (this.clearExpiredByTimeout) {
|
|
3619
|
-
this._clearExpiredHourAgo();
|
|
3620
|
-
}
|
|
3621
|
-
}
|
|
3622
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
3623
|
-
const res = new RateLimiterRes2();
|
|
3624
|
-
let doc = result;
|
|
3625
|
-
res.isFirstInDuration = doc.points === changedPoints;
|
|
3626
|
-
res.consumedPoints = doc.points;
|
|
3627
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
3628
|
-
res.msBeforeNext = doc.expire !== null ? Math.max(new Date(doc.expire).getTime() - Date.now(), 0) : -1;
|
|
3629
|
-
return res;
|
|
3630
|
-
}
|
|
3631
|
-
async _upsert(key, points, msDuration, forceExpire = false) {
|
|
3632
|
-
if (!this.drizzleClient) {
|
|
3633
|
-
return Promise.reject(new RateLimiterDrizzleError("Drizzle client is not established"));
|
|
3634
|
-
}
|
|
3635
|
-
const { eq } = await getDrizzleOperators();
|
|
3636
|
-
const now = /* @__PURE__ */ new Date();
|
|
3637
|
-
const newExpire = msDuration > 0 ? new Date(now.getTime() + msDuration) : null;
|
|
3638
|
-
const [existingRecord] = await this.drizzleClient.select().from(this.schema).where(eq(this.schema.key, key)).limit(1);
|
|
3639
|
-
const shouldUpdateExpire = forceExpire || !existingRecord || !existingRecord.expire || existingRecord.expire <= now || newExpire === null;
|
|
3640
|
-
let newPoints;
|
|
3641
|
-
if (existingRecord && !shouldUpdateExpire) {
|
|
3642
|
-
newPoints = existingRecord.points + points;
|
|
3643
|
-
} else {
|
|
3644
|
-
newPoints = points;
|
|
3645
|
-
}
|
|
3646
|
-
const [data] = await this.drizzleClient.insert(this.schema).values({
|
|
3647
|
-
key,
|
|
3648
|
-
points: newPoints,
|
|
3649
|
-
expire: newExpire
|
|
3650
|
-
}).onConflictDoUpdate({
|
|
3651
|
-
target: this.schema.key,
|
|
3652
|
-
set: {
|
|
3653
|
-
points: newPoints,
|
|
3654
|
-
...shouldUpdateExpire && { expire: newExpire }
|
|
3655
|
-
}
|
|
3656
|
-
}).returning();
|
|
3657
|
-
return data;
|
|
3658
|
-
}
|
|
3659
|
-
async _get(rlKey) {
|
|
3660
|
-
if (!this.drizzleClient) {
|
|
3661
|
-
return Promise.reject(new RateLimiterDrizzleError("Drizzle client is not established"));
|
|
3662
|
-
}
|
|
3663
|
-
const { and, or, gt, eq, isNull } = await getDrizzleOperators();
|
|
3664
|
-
const [response] = await this.drizzleClient.select().from(this.schema).where(
|
|
3665
|
-
and(
|
|
3666
|
-
eq(this.schema.key, rlKey),
|
|
3667
|
-
or(gt(this.schema.expire, /* @__PURE__ */ new Date()), isNull(this.schema.expire))
|
|
3668
|
-
)
|
|
3669
|
-
).limit(1);
|
|
3670
|
-
return response || null;
|
|
3671
|
-
}
|
|
3672
|
-
async _delete(rlKey) {
|
|
3673
|
-
if (!this.drizzleClient) {
|
|
3674
|
-
return Promise.reject(new RateLimiterDrizzleError("Drizzle client is not established"));
|
|
3675
|
-
}
|
|
3676
|
-
const { eq } = await getDrizzleOperators();
|
|
3677
|
-
const [result] = await this.drizzleClient.delete(this.schema).where(eq(this.schema.key, rlKey)).returning({ key: this.schema.key });
|
|
3678
|
-
return !!(result && result.key);
|
|
3679
|
-
}
|
|
3680
|
-
_clearExpiredHourAgo() {
|
|
3681
|
-
if (this._clearExpiredTimeoutId) {
|
|
3682
|
-
clearTimeout(this._clearExpiredTimeoutId);
|
|
3683
|
-
}
|
|
3684
|
-
this._clearExpiredTimeoutId = setTimeout(async () => {
|
|
3685
|
-
try {
|
|
3686
|
-
const { lt } = await getDrizzleOperators();
|
|
3687
|
-
await this.drizzleClient.delete(this.schema).where(lt(this.schema.expire, new Date(Date.now() - EXPIRED_THRESHOLD_MS)));
|
|
3688
|
-
} catch (error48) {
|
|
3689
|
-
console.warn("Failed to clear expired records:", error48);
|
|
3690
|
-
}
|
|
3691
|
-
this._clearExpiredHourAgo();
|
|
3692
|
-
}, CLEANUP_INTERVAL_MS);
|
|
3693
|
-
this._clearExpiredTimeoutId.unref();
|
|
3694
|
-
}
|
|
3695
|
-
};
|
|
3696
|
-
module2.exports = RateLimiterDrizzleNonAtomic;
|
|
3697
|
-
}
|
|
3698
|
-
});
|
|
3699
|
-
|
|
3700
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterValkey.js
|
|
3701
|
-
var require_RateLimiterValkey = __commonJS({
|
|
3702
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterValkey.js"(exports2, module2) {
|
|
3703
|
-
"use strict";
|
|
3704
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
3705
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
3706
|
-
var incrTtlLuaScript = `
|
|
3707
|
-
server.call('set', KEYS[1], 0, 'EX', ARGV[2], 'NX')
|
|
3708
|
-
local consumed = server.call('incrby', KEYS[1], ARGV[1])
|
|
3709
|
-
local ttl = server.call('pttl', KEYS[1])
|
|
3710
|
-
return {consumed, ttl}
|
|
3711
|
-
`;
|
|
3712
|
-
var RateLimiterValkey = class extends RateLimiterStoreAbstract {
|
|
3713
|
-
/**
|
|
3714
|
-
*
|
|
3715
|
-
* @param {Object} opts
|
|
3716
|
-
* Defaults {
|
|
3717
|
-
* ... see other in RateLimiterStoreAbstract
|
|
3718
|
-
*
|
|
3719
|
-
* storeClient: ValkeyClient
|
|
3720
|
-
* rejectIfValkeyNotReady: boolean = false - reject / invoke insuranceLimiter immediately when valkey connection is not "ready"
|
|
3721
|
-
* }
|
|
3722
|
-
*/
|
|
3723
|
-
constructor(opts) {
|
|
3724
|
-
super(opts);
|
|
3725
|
-
this.client = opts.storeClient;
|
|
3726
|
-
this._rejectIfValkeyNotReady = !!opts.rejectIfValkeyNotReady;
|
|
3727
|
-
this._incrTtlLuaScript = opts.customIncrTtlLuaScript || incrTtlLuaScript;
|
|
3728
|
-
this.client.defineCommand("rlflxIncr", {
|
|
3729
|
-
numberOfKeys: 1,
|
|
3730
|
-
lua: this._incrTtlLuaScript
|
|
3731
|
-
});
|
|
3732
|
-
}
|
|
3733
|
-
/**
|
|
3734
|
-
* Prevent actual valkey call if valkey connection is not ready
|
|
3735
|
-
* @return {boolean}
|
|
3736
|
-
* @private
|
|
3737
|
-
*/
|
|
3738
|
-
_isValkeyReady() {
|
|
3739
|
-
if (!this._rejectIfValkeyNotReady) {
|
|
3740
|
-
return true;
|
|
3741
|
-
}
|
|
3742
|
-
return this.client.status === "ready";
|
|
3743
|
-
}
|
|
3744
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
3745
|
-
let consumed;
|
|
3746
|
-
let resTtlMs;
|
|
3747
|
-
if (Array.isArray(result[0])) {
|
|
3748
|
-
[[, consumed], [, resTtlMs]] = result;
|
|
3749
|
-
} else {
|
|
3750
|
-
[consumed, resTtlMs] = result;
|
|
3751
|
-
}
|
|
3752
|
-
const res = new RateLimiterRes2();
|
|
3753
|
-
res.consumedPoints = +consumed;
|
|
3754
|
-
res.isFirstInDuration = res.consumedPoints === changedPoints;
|
|
3755
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
3756
|
-
res.msBeforeNext = resTtlMs;
|
|
3757
|
-
return res;
|
|
3758
|
-
}
|
|
3759
|
-
_upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
3760
|
-
if (!this._isValkeyReady()) {
|
|
3761
|
-
throw new Error("Valkey connection is not ready");
|
|
3762
|
-
}
|
|
3763
|
-
const secDuration = Math.floor(msDuration / 1e3);
|
|
3764
|
-
if (forceExpire) {
|
|
3765
|
-
const multi = this.client.multi();
|
|
3766
|
-
if (secDuration > 0) {
|
|
3767
|
-
multi.set(rlKey, points, "EX", secDuration);
|
|
3768
|
-
} else {
|
|
3769
|
-
multi.set(rlKey, points);
|
|
3770
|
-
}
|
|
3771
|
-
return multi.pttl(rlKey).exec();
|
|
3772
|
-
}
|
|
3773
|
-
if (secDuration > 0) {
|
|
3774
|
-
return this.client.rlflxIncr([rlKey, String(points), String(secDuration), String(this.points), String(this.duration)]);
|
|
3775
|
-
}
|
|
3776
|
-
return this.client.multi().incrby(rlKey, points).pttl(rlKey).exec();
|
|
3777
|
-
}
|
|
3778
|
-
_get(rlKey) {
|
|
3779
|
-
if (!this._isValkeyReady()) {
|
|
3780
|
-
throw new Error("Valkey connection is not ready");
|
|
3781
|
-
}
|
|
3782
|
-
return this.client.multi().get(rlKey).pttl(rlKey).exec().then((result) => {
|
|
3783
|
-
const [[, points]] = result;
|
|
3784
|
-
if (points === null) return null;
|
|
3785
|
-
return result;
|
|
3786
|
-
});
|
|
3787
|
-
}
|
|
3788
|
-
_delete(rlKey) {
|
|
3789
|
-
return this.client.del(rlKey).then((result) => result > 0);
|
|
3790
|
-
}
|
|
3791
|
-
};
|
|
3792
|
-
module2.exports = RateLimiterValkey;
|
|
3793
|
-
}
|
|
3794
|
-
});
|
|
3795
|
-
|
|
3796
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterValkeyGlide.js
|
|
3797
|
-
var require_RateLimiterValkeyGlide = __commonJS({
|
|
3798
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterValkeyGlide.js"(exports2, module2) {
|
|
3799
|
-
"use strict";
|
|
3800
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
3801
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
3802
|
-
var DEFAULT_LIBRARY_NAME = "ratelimiterflexible";
|
|
3803
|
-
var DEFAULT_VALKEY_SCRIPT = `local key = KEYS[1]
|
|
3804
|
-
local pointsToConsume = tonumber(ARGV[1])
|
|
3805
|
-
if tonumber(ARGV[2]) > 0 then
|
|
3806
|
-
server.call('set', key, "0", 'EX', ARGV[2], 'NX')
|
|
3807
|
-
local consumed = server.call('incrby', key, pointsToConsume)
|
|
3808
|
-
local pttl = server.call('pttl', key)
|
|
3809
|
-
return {consumed, pttl}
|
|
3810
|
-
end
|
|
3811
|
-
local consumed = server.call('incrby', key, pointsToConsume)
|
|
3812
|
-
local pttl = server.call('pttl', key)
|
|
3813
|
-
return {consumed, pttl}`;
|
|
3814
|
-
var GET_VALKEY_SCRIPT = `local key = KEYS[1]
|
|
3815
|
-
local value = server.call('get', key)
|
|
3816
|
-
if value == nil then
|
|
3817
|
-
return value
|
|
3818
|
-
end
|
|
3819
|
-
local pttl = server.call('pttl', key)
|
|
3820
|
-
return {tonumber(value), pttl}`;
|
|
3821
|
-
var RateLimiterValkeyGlide = class extends RateLimiterStoreAbstract {
|
|
3822
|
-
/**
|
|
3823
|
-
* Constructor for RateLimiterValkeyGlide
|
|
3824
|
-
*
|
|
3825
|
-
* @param {Object} opts - Configuration options
|
|
3826
|
-
* @param {GlideClient|GlideClusterClient} opts.storeClient - Valkey Glide client instance (required)
|
|
3827
|
-
* @param {number} opts.points - Maximum number of points that can be consumed over duration (required)
|
|
3828
|
-
* @param {number} opts.duration - Duration in seconds before points are reset (required, 0 = never expires)
|
|
3829
|
-
* @param {number} [opts.blockDuration=0] - Duration in seconds that a key will be blocked for if consumed more than points
|
|
3830
|
-
* @param {boolean} [opts.rejectIfValkeyNotReady=false] - Whether to reject requests if Valkey is not ready
|
|
3831
|
-
* @param {boolean} [opts.execEvenly=false] - Delay actions to distribute them evenly over duration
|
|
3832
|
-
* @param {number} [opts.execEvenlyMinDelayMs] - Minimum delay between actions when execEvenly is true
|
|
3833
|
-
* @param {string} [opts.customFunction] - Custom Lua script for rate limiting logic
|
|
3834
|
-
* @param {number} [opts.inMemoryBlockOnConsumed] - Points threshold for in-memory blocking
|
|
3835
|
-
* @param {number} [opts.inMemoryBlockDuration] - Duration in seconds for in-memory blocking
|
|
3836
|
-
* @param {string} [opts.customFunctionLibName] - Custom name for the function library, defaults to 'ratelimiter'.
|
|
3837
|
-
* The name is used to identify the library of the lua function. An custom name should be used only if you
|
|
3838
|
-
* you want to use different libraries for different rate limiters, otherwise it is not needed.
|
|
3839
|
-
* @param {RateLimiterAbstract} [opts.insuranceLimiter] - Backup limiter to use when the primary client fails
|
|
3840
|
-
*
|
|
3841
|
-
* @example
|
|
3842
|
-
* const rateLimiter = new RateLimiterValkeyGlide({
|
|
3843
|
-
* storeClient: glideClient,
|
|
3844
|
-
* points: 5,
|
|
3845
|
-
* duration: 1
|
|
3846
|
-
* });
|
|
3847
|
-
*
|
|
3848
|
-
* @example <caption>With custom Lua function</caption>
|
|
3849
|
-
* const customScript = `local key = KEYS[1]
|
|
3850
|
-
* local pointsToConsume = tonumber(ARGV[1]) or 0
|
|
3851
|
-
* local secDuration = tonumber(ARGV[2]) or 0
|
|
3852
|
-
*
|
|
3853
|
-
* -- Custom implementation
|
|
3854
|
-
* -- ...
|
|
3855
|
-
*
|
|
3856
|
-
* -- Must return exactly two values: [consumed_points, ttl_in_ms]
|
|
3857
|
-
* return {consumed, ttl}`
|
|
3858
|
-
*
|
|
3859
|
-
* const rateLimiter = new RateLimiterValkeyGlide({
|
|
3860
|
-
* storeClient: glideClient,
|
|
3861
|
-
* points: 5,
|
|
3862
|
-
* customFunction: customScript
|
|
3863
|
-
* });
|
|
3864
|
-
*
|
|
3865
|
-
* @example <caption>With insurance limiter</caption>
|
|
3866
|
-
* const rateLimiter = new RateLimiterValkeyGlide({
|
|
3867
|
-
* storeClient: primaryGlideClient,
|
|
3868
|
-
* points: 5,
|
|
3869
|
-
* duration: 2,
|
|
3870
|
-
* insuranceLimiter: new RateLimiterMemory({
|
|
3871
|
-
* points: 5,
|
|
3872
|
-
* duration: 2
|
|
3873
|
-
* })
|
|
3874
|
-
* });
|
|
3875
|
-
*
|
|
3876
|
-
* @description
|
|
3877
|
-
* When providing a custom Lua script via `opts.customFunction`, it must:
|
|
3878
|
-
*
|
|
3879
|
-
* 1. Accept parameters:
|
|
3880
|
-
* - KEYS[1]: The key being rate limited
|
|
3881
|
-
* - ARGV[1]: Points to consume (as string, use tonumber() to convert)
|
|
3882
|
-
* - ARGV[2]: Duration in seconds (as string, use tonumber() to convert)
|
|
3883
|
-
*
|
|
3884
|
-
* 2. Return an array with exactly two elements:
|
|
3885
|
-
* - [0]: Consumed points (number)
|
|
3886
|
-
* - [1]: TTL in milliseconds (number)
|
|
3887
|
-
*
|
|
3888
|
-
* 3. Handle scenarios:
|
|
3889
|
-
* - New key creation: Initialize with expiry for fixed windows
|
|
3890
|
-
* - Key updates: Increment existing counters
|
|
3891
|
-
*/
|
|
3892
|
-
constructor(opts) {
|
|
3893
|
-
super(opts);
|
|
3894
|
-
this.client = opts.storeClient;
|
|
3895
|
-
this._scriptLoaded = false;
|
|
3896
|
-
this._getScriptLoaded = false;
|
|
3897
|
-
this._rejectIfValkeyNotReady = !!opts.rejectIfValkeyNotReady;
|
|
3898
|
-
this._luaScript = opts.customFunction || DEFAULT_VALKEY_SCRIPT;
|
|
3899
|
-
this._libraryName = opts.customFunctionLibName || DEFAULT_LIBRARY_NAME;
|
|
3900
|
-
}
|
|
3901
|
-
/**
|
|
3902
|
-
* Ensure scripts are loaded in the Valkey server
|
|
3903
|
-
* @returns {Promise<boolean>} True if scripts are loaded
|
|
3904
|
-
* @private
|
|
3905
|
-
*/
|
|
3906
|
-
async _loadScripts() {
|
|
3907
|
-
if (this._scriptLoaded && this._getScriptLoaded) {
|
|
3908
|
-
return true;
|
|
3909
|
-
}
|
|
3910
|
-
if (!this.client) {
|
|
3911
|
-
throw new Error("Valkey client is not set");
|
|
3912
|
-
}
|
|
3913
|
-
const promises = [];
|
|
3914
|
-
if (!this._scriptLoaded) {
|
|
3915
|
-
const script = Buffer.from(`#!lua name=${this._libraryName}
|
|
3916
|
-
local function consume(KEYS, ARGV)
|
|
3917
|
-
${this._luaScript.trim()}
|
|
3918
|
-
end
|
|
3919
|
-
server.register_function('consume', consume)`);
|
|
3920
|
-
promises.push(this.client.functionLoad(script, { replace: true }));
|
|
3921
|
-
} else promises.push(Promise.resolve(this._libraryName));
|
|
3922
|
-
if (!this._getScriptLoaded) {
|
|
3923
|
-
const script = Buffer.from(`#!lua name=ratelimiter_get
|
|
3924
|
-
local function getValue(KEYS, ARGV)
|
|
3925
|
-
${GET_VALKEY_SCRIPT.trim()}
|
|
3926
|
-
end
|
|
3927
|
-
server.register_function('getValue', getValue)`);
|
|
3928
|
-
promises.push(this.client.functionLoad(script, { replace: true }));
|
|
3929
|
-
} else promises.push(Promise.resolve("ratelimiter_get"));
|
|
3930
|
-
const results = await Promise.all(promises);
|
|
3931
|
-
this._scriptLoaded = results[0] === this._libraryName;
|
|
3932
|
-
this._getScriptLoaded = results[1] === "ratelimiter_get";
|
|
3933
|
-
if (!this._scriptLoaded || !this._getScriptLoaded) {
|
|
3934
|
-
throw new Error("Valkey connection is not ready, scripts not loaded");
|
|
3935
|
-
}
|
|
3936
|
-
return true;
|
|
3937
|
-
}
|
|
3938
|
-
/**
|
|
3939
|
-
* Update or insert the rate limiter record
|
|
3940
|
-
*
|
|
3941
|
-
* @param {string} rlKey - The rate limiter key
|
|
3942
|
-
* @param {number} pointsToConsume - Points to be consumed
|
|
3943
|
-
* @param {number} msDuration - Duration in milliseconds
|
|
3944
|
-
* @param {boolean} [forceExpire=false] - Whether to force expiration
|
|
3945
|
-
* @param {Object} [options={}] - Additional options
|
|
3946
|
-
* @returns {Promise<Array>} Array containing consumed points and TTL
|
|
3947
|
-
* @private
|
|
3948
|
-
*/
|
|
3949
|
-
async _upsert(rlKey, pointsToConsume, msDuration, forceExpire = false, options = {}) {
|
|
3950
|
-
await this._loadScripts();
|
|
3951
|
-
const secDuration = Math.floor(msDuration / 1e3);
|
|
3952
|
-
if (forceExpire) {
|
|
3953
|
-
if (secDuration > 0) {
|
|
3954
|
-
await this.client.set(
|
|
3955
|
-
rlKey,
|
|
3956
|
-
String(pointsToConsume),
|
|
3957
|
-
{ expiry: { type: "EX", count: secDuration } }
|
|
3958
|
-
);
|
|
3959
|
-
return [pointsToConsume, secDuration * 1e3];
|
|
3960
|
-
}
|
|
3961
|
-
await this.client.set(rlKey, String(pointsToConsume));
|
|
3962
|
-
return [pointsToConsume, -1];
|
|
3963
|
-
}
|
|
3964
|
-
const result = await this.client.fcall(
|
|
3965
|
-
"consume",
|
|
3966
|
-
[rlKey],
|
|
3967
|
-
[String(pointsToConsume), String(secDuration)]
|
|
3968
|
-
);
|
|
3969
|
-
return result;
|
|
3970
|
-
}
|
|
3971
|
-
/**
|
|
3972
|
-
* Get the rate limiter record
|
|
3973
|
-
*
|
|
3974
|
-
* @param {string} rlKey - The rate limiter key
|
|
3975
|
-
* @param {Object} [options={}] - Additional options
|
|
3976
|
-
* @returns {Promise<Array|null>} Array containing consumed points and TTL, or null if not found
|
|
3977
|
-
* @private
|
|
3978
|
-
*/
|
|
3979
|
-
async _get(rlKey, options = {}) {
|
|
3980
|
-
await this._loadScripts();
|
|
3981
|
-
const res = await this.client.fcall("getValue", [rlKey], []);
|
|
3982
|
-
return res.length > 0 ? res : null;
|
|
3983
|
-
}
|
|
3984
|
-
/**
|
|
3985
|
-
* Delete the rate limiter record
|
|
3986
|
-
*
|
|
3987
|
-
* @param {string} rlKey - The rate limiter key
|
|
3988
|
-
* @param {Object} [options={}] - Additional options
|
|
3989
|
-
* @returns {Promise<boolean>} True if successful, false otherwise
|
|
3990
|
-
* @private
|
|
3991
|
-
*/
|
|
3992
|
-
async _delete(rlKey, options = {}) {
|
|
3993
|
-
const result = await this.client.del([rlKey]);
|
|
3994
|
-
return result > 0;
|
|
3995
|
-
}
|
|
3996
|
-
/**
|
|
3997
|
-
* Convert raw result to RateLimiterRes object
|
|
3998
|
-
*
|
|
3999
|
-
* @param {string} rlKey - The rate limiter key
|
|
4000
|
-
* @param {number} changedPoints - Points changed in this operation
|
|
4001
|
-
* @param {Array|null} result - Result from Valkey operation
|
|
4002
|
-
* @returns {RateLimiterRes|null} RateLimiterRes object or null if result is null
|
|
4003
|
-
* @private
|
|
4004
|
-
*/
|
|
4005
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
4006
|
-
if (result === null) {
|
|
4007
|
-
return null;
|
|
4008
|
-
}
|
|
4009
|
-
const res = new RateLimiterRes2();
|
|
4010
|
-
const [consumedPointsStr, pttl] = result;
|
|
4011
|
-
const consumedPoints = Number(consumedPointsStr);
|
|
4012
|
-
res.isFirstInDuration = consumedPoints === changedPoints;
|
|
4013
|
-
res.consumedPoints = consumedPoints;
|
|
4014
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
4015
|
-
res.msBeforeNext = pttl;
|
|
4016
|
-
return res;
|
|
4017
|
-
}
|
|
4018
|
-
/**
|
|
4019
|
-
* Close the rate limiter and release resources
|
|
4020
|
-
* Note: The method won't going to close the Valkey client, as it may be shared with other instances.
|
|
4021
|
-
* @returns {Promise<void>} Promise that resolves when the rate limiter is closed
|
|
4022
|
-
*/
|
|
4023
|
-
async close() {
|
|
4024
|
-
if (this._scriptLoaded) {
|
|
4025
|
-
await this.client.functionDelete(this._libraryName);
|
|
4026
|
-
this._scriptLoaded = false;
|
|
4027
|
-
}
|
|
4028
|
-
if (this._getScriptLoaded) {
|
|
4029
|
-
await this.client.functionDelete("ratelimiter_get");
|
|
4030
|
-
this._getScriptLoaded = false;
|
|
4031
|
-
}
|
|
4032
|
-
if (this.insuranceLimiter) {
|
|
4033
|
-
try {
|
|
4034
|
-
await this.insuranceLimiter.close();
|
|
4035
|
-
} catch (e) {
|
|
4036
|
-
}
|
|
4037
|
-
}
|
|
4038
|
-
this.client = null;
|
|
4039
|
-
this._scriptLoaded = false;
|
|
4040
|
-
this._getScriptLoaded = false;
|
|
4041
|
-
this._rejectIfValkeyNotReady = false;
|
|
4042
|
-
this._luaScript = null;
|
|
4043
|
-
this._libraryName = null;
|
|
4044
|
-
this.insuranceLimiter = null;
|
|
4045
|
-
}
|
|
4046
|
-
};
|
|
4047
|
-
module2.exports = RateLimiterValkeyGlide;
|
|
4048
|
-
}
|
|
4049
|
-
});
|
|
4050
|
-
|
|
4051
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterSQLite.js
|
|
4052
|
-
var require_RateLimiterSQLite = __commonJS({
|
|
4053
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterSQLite.js"(exports2, module2) {
|
|
4054
|
-
"use strict";
|
|
4055
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
4056
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
4057
|
-
var RateLimiterSQLite = class extends RateLimiterStoreAbstract {
|
|
4058
|
-
/**
|
|
4059
|
-
* Internal store type used to determine the SQLite client in use.
|
|
4060
|
-
* It can be one of the following:
|
|
4061
|
-
* - `"sqlite3".
|
|
4062
|
-
* - `"better-sqlite3".
|
|
4063
|
-
*
|
|
4064
|
-
* @type {("sqlite3" | "better-sqlite3" | null)}
|
|
4065
|
-
* @private
|
|
4066
|
-
*/
|
|
4067
|
-
_internalStoreType = null;
|
|
4068
|
-
/**
|
|
4069
|
-
* @callback callback
|
|
4070
|
-
* @param {Object} err
|
|
4071
|
-
*
|
|
4072
|
-
* @param {Object} opts
|
|
4073
|
-
* @param {callback} cb
|
|
4074
|
-
* Defaults {
|
|
4075
|
-
* ... see other in RateLimiterStoreAbstract
|
|
4076
|
-
* storeClient: sqliteClient, // SQLite database instance (sqlite3, better-sqlite3, or knex instance)
|
|
4077
|
-
* storeType: 'sqlite3' | 'better-sqlite3' | 'knex', // Optional, defaults to 'sqlite3'
|
|
4078
|
-
* tableName: 'string',
|
|
4079
|
-
* tableCreated: boolean,
|
|
4080
|
-
* clearExpiredByTimeout: boolean,
|
|
4081
|
-
* }
|
|
4082
|
-
*/
|
|
4083
|
-
constructor(opts, cb = null) {
|
|
4084
|
-
super(opts);
|
|
4085
|
-
this.client = opts.storeClient;
|
|
4086
|
-
this.storeType = opts.storeType || "sqlite3";
|
|
4087
|
-
this.tableName = opts.tableName;
|
|
4088
|
-
this.tableCreated = opts.tableCreated || false;
|
|
4089
|
-
this.clearExpiredByTimeout = opts.clearExpiredByTimeout;
|
|
4090
|
-
this._validateStoreTypes(cb);
|
|
4091
|
-
this._validateStoreClient(cb);
|
|
4092
|
-
this._setInternalStoreType(cb);
|
|
4093
|
-
this._validateTableName(cb);
|
|
4094
|
-
if (!this.tableCreated) {
|
|
4095
|
-
this._createDbAndTable().then(() => {
|
|
4096
|
-
this.tableCreated = true;
|
|
4097
|
-
if (this.clearExpiredByTimeout) this._clearExpiredHourAgo();
|
|
4098
|
-
if (typeof cb === "function") cb();
|
|
4099
|
-
}).catch((err) => {
|
|
4100
|
-
if (typeof cb === "function") cb(err);
|
|
4101
|
-
else throw err;
|
|
4102
|
-
});
|
|
4103
|
-
} else {
|
|
4104
|
-
if (this.clearExpiredByTimeout) this._clearExpiredHourAgo();
|
|
4105
|
-
if (typeof cb === "function") cb();
|
|
4106
|
-
}
|
|
4107
|
-
}
|
|
4108
|
-
_validateStoreTypes(cb) {
|
|
4109
|
-
const validStoreTypes = ["sqlite3", "better-sqlite3", "knex"];
|
|
4110
|
-
if (!validStoreTypes.includes(this.storeType)) {
|
|
4111
|
-
const err = new Error(
|
|
4112
|
-
`storeType must be one of: ${validStoreTypes.join(", ")}`
|
|
4113
|
-
);
|
|
4114
|
-
if (typeof cb === "function") return cb(err);
|
|
4115
|
-
throw err;
|
|
4116
|
-
}
|
|
4117
|
-
}
|
|
4118
|
-
_validateStoreClient(cb) {
|
|
4119
|
-
if (this.storeType === "sqlite3") {
|
|
4120
|
-
if (typeof this.client.run !== "function") {
|
|
4121
|
-
const err = new Error(
|
|
4122
|
-
"storeClient must be an instance of sqlite3.Database when storeType is 'sqlite3' or no storeType was provided"
|
|
4123
|
-
);
|
|
4124
|
-
if (typeof cb === "function") return cb(err);
|
|
4125
|
-
throw err;
|
|
4126
|
-
}
|
|
4127
|
-
} else if (this.storeType === "better-sqlite3") {
|
|
4128
|
-
if (typeof this.client.prepare !== "function" || typeof this.client.run !== "undefined") {
|
|
4129
|
-
const err = new Error(
|
|
4130
|
-
"storeClient must be an instance of better-sqlite3.Database when storeType is 'better-sqlite3'"
|
|
4131
|
-
);
|
|
4132
|
-
if (typeof cb === "function") return cb(err);
|
|
4133
|
-
throw err;
|
|
4134
|
-
}
|
|
4135
|
-
} else if (this.storeType === "knex") {
|
|
4136
|
-
if (typeof this.client.raw !== "function") {
|
|
4137
|
-
const err = new Error(
|
|
4138
|
-
"storeClient must be an instance of Knex when storeType is 'knex'"
|
|
4139
|
-
);
|
|
4140
|
-
if (typeof cb === "function") return cb(err);
|
|
4141
|
-
throw err;
|
|
4142
|
-
}
|
|
4143
|
-
}
|
|
4144
|
-
}
|
|
4145
|
-
_setInternalStoreType(cb) {
|
|
4146
|
-
if (this.storeType === "knex") {
|
|
4147
|
-
const knexClientType = this.client.client.config.client;
|
|
4148
|
-
if (knexClientType === "sqlite3") {
|
|
4149
|
-
this._internalStoreType = "sqlite3";
|
|
4150
|
-
} else if (knexClientType === "better-sqlite3") {
|
|
4151
|
-
this._internalStoreType = "better-sqlite3";
|
|
4152
|
-
} else {
|
|
4153
|
-
const err = new Error(
|
|
4154
|
-
"Knex must be configured with 'sqlite3' or 'better-sqlite3' for RateLimiterSQLite"
|
|
4155
|
-
);
|
|
4156
|
-
if (typeof cb === "function") return cb(err);
|
|
4157
|
-
throw err;
|
|
4158
|
-
}
|
|
4159
|
-
} else {
|
|
4160
|
-
this._internalStoreType = this.storeType;
|
|
4161
|
-
}
|
|
4162
|
-
}
|
|
4163
|
-
_validateTableName(cb) {
|
|
4164
|
-
if (!/^[A-Za-z0-9_]*$/.test(this.tableName)) {
|
|
4165
|
-
const err = new Error("Table name must contain only letters and numbers");
|
|
4166
|
-
if (typeof cb === "function") return cb(err);
|
|
4167
|
-
throw err;
|
|
4168
|
-
}
|
|
4169
|
-
}
|
|
4170
|
-
/**
|
|
4171
|
-
* Acquires the database connection based on the storeType.
|
|
4172
|
-
* @returns {Promise<Object>} The database client or connection
|
|
4173
|
-
*/
|
|
4174
|
-
async _getConnection() {
|
|
4175
|
-
if (this.storeType === "knex") {
|
|
4176
|
-
return this.client.client.acquireConnection();
|
|
4177
|
-
}
|
|
4178
|
-
return this.client;
|
|
4179
|
-
}
|
|
4180
|
-
/**
|
|
4181
|
-
* Releases the database connection if necessary.
|
|
4182
|
-
* @param {Object} conn The database client or connection
|
|
4183
|
-
*/
|
|
4184
|
-
_releaseConnection(conn) {
|
|
4185
|
-
if (this.storeType === "knex") {
|
|
4186
|
-
this.client.client.releaseConnection(conn);
|
|
4187
|
-
}
|
|
4188
|
-
}
|
|
4189
|
-
async _createDbAndTable() {
|
|
4190
|
-
const conn = await this._getConnection();
|
|
4191
|
-
try {
|
|
4192
|
-
switch (this._internalStoreType) {
|
|
4193
|
-
case "sqlite3":
|
|
4194
|
-
await new Promise((resolve, reject) => {
|
|
4195
|
-
conn.run(
|
|
4196
|
-
this._getCreateTableSQL(),
|
|
4197
|
-
(err) => err ? reject(err) : resolve()
|
|
4198
|
-
);
|
|
4199
|
-
});
|
|
4200
|
-
break;
|
|
4201
|
-
case "better-sqlite3":
|
|
4202
|
-
conn.prepare(this._getCreateTableSQL()).run();
|
|
4203
|
-
break;
|
|
4204
|
-
default:
|
|
4205
|
-
throw new Error("Unsupported internalStoreType");
|
|
4206
|
-
}
|
|
4207
|
-
} finally {
|
|
4208
|
-
this._releaseConnection(conn);
|
|
4209
|
-
}
|
|
4210
|
-
}
|
|
4211
|
-
_getCreateTableSQL() {
|
|
4212
|
-
return `CREATE TABLE IF NOT EXISTS ${this.tableName} (
|
|
4213
|
-
key TEXT PRIMARY KEY,
|
|
4214
|
-
points INTEGER NOT NULL DEFAULT 0,
|
|
4215
|
-
expire INTEGER
|
|
4216
|
-
)`;
|
|
4217
|
-
}
|
|
4218
|
-
_clearExpiredHourAgo() {
|
|
4219
|
-
if (this._clearExpiredTimeoutId) clearTimeout(this._clearExpiredTimeoutId);
|
|
4220
|
-
this._clearExpiredTimeoutId = setTimeout(() => {
|
|
4221
|
-
this.clearExpired(Date.now() - 36e5).then(() => this._clearExpiredHourAgo());
|
|
4222
|
-
}, 3e5);
|
|
4223
|
-
this._clearExpiredTimeoutId.unref();
|
|
4224
|
-
}
|
|
4225
|
-
async clearExpired(nowMs) {
|
|
4226
|
-
const sql = `DELETE FROM ${this.tableName} WHERE expire < ?`;
|
|
4227
|
-
const conn = await this._getConnection();
|
|
4228
|
-
try {
|
|
4229
|
-
switch (this._internalStoreType) {
|
|
4230
|
-
case "sqlite3":
|
|
4231
|
-
await new Promise((resolve, reject) => {
|
|
4232
|
-
conn.run(sql, [nowMs], (err) => err ? reject(err) : resolve());
|
|
4233
|
-
});
|
|
4234
|
-
break;
|
|
4235
|
-
case "better-sqlite3":
|
|
4236
|
-
conn.prepare(sql).run(nowMs);
|
|
4237
|
-
break;
|
|
4238
|
-
default:
|
|
4239
|
-
throw new Error("Unsupported internalStoreType");
|
|
4240
|
-
}
|
|
4241
|
-
} finally {
|
|
4242
|
-
this._releaseConnection(conn);
|
|
4243
|
-
}
|
|
4244
|
-
}
|
|
4245
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
4246
|
-
const res = new RateLimiterRes2();
|
|
4247
|
-
res.isFirstInDuration = changedPoints === result.points;
|
|
4248
|
-
res.consumedPoints = res.isFirstInDuration ? changedPoints : result.points;
|
|
4249
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
4250
|
-
res.msBeforeNext = result.expire ? Math.max(result.expire - Date.now(), 0) : -1;
|
|
4251
|
-
return res;
|
|
4252
|
-
}
|
|
4253
|
-
async _upsertTransactionSQLite3(conn, upsertQuery, upsertParams) {
|
|
4254
|
-
return await new Promise((resolve, reject) => {
|
|
4255
|
-
conn.serialize(() => {
|
|
4256
|
-
conn.run("SAVEPOINT rate_limiter_trx;", (err) => {
|
|
4257
|
-
if (err) return reject(err);
|
|
4258
|
-
conn.get(upsertQuery, upsertParams, (err2, row) => {
|
|
4259
|
-
if (err2) {
|
|
4260
|
-
conn.run(
|
|
4261
|
-
"ROLLBACK TO SAVEPOINT rate_limiter_trx;",
|
|
4262
|
-
() => reject(err2)
|
|
4263
|
-
);
|
|
4264
|
-
return;
|
|
4265
|
-
}
|
|
4266
|
-
conn.run("RELEASE SAVEPOINT rate_limiter_trx;", () => resolve(row));
|
|
4267
|
-
});
|
|
4268
|
-
});
|
|
4269
|
-
});
|
|
4270
|
-
});
|
|
4271
|
-
}
|
|
4272
|
-
async _upsertTransactionBetterSQLite3(conn, upsertQuery, upsertParams) {
|
|
4273
|
-
return conn.transaction(
|
|
4274
|
-
() => conn.prepare(upsertQuery).get(...upsertParams)
|
|
4275
|
-
)();
|
|
4276
|
-
}
|
|
4277
|
-
async _upsertTransaction(rlKey, points, msDuration, forceExpire) {
|
|
4278
|
-
const dateNow = Date.now();
|
|
4279
|
-
const newExpire = msDuration > 0 ? dateNow + msDuration : null;
|
|
4280
|
-
const upsertQuery = forceExpire ? `INSERT OR REPLACE INTO ${this.tableName} (key, points, expire) VALUES (?, ?, ?) RETURNING points, expire` : `INSERT INTO ${this.tableName} (key, points, expire)
|
|
4281
|
-
VALUES (?, ?, ?)
|
|
4282
|
-
ON CONFLICT(key) DO UPDATE SET
|
|
4283
|
-
points = CASE WHEN expire IS NULL OR expire > ? THEN points + excluded.points ELSE excluded.points END,
|
|
4284
|
-
expire = CASE WHEN expire IS NULL OR expire > ? THEN expire ELSE excluded.expire END
|
|
4285
|
-
RETURNING points, expire`;
|
|
4286
|
-
const upsertParams = forceExpire ? [rlKey, points, newExpire] : [rlKey, points, newExpire, dateNow, dateNow];
|
|
4287
|
-
const conn = await this._getConnection();
|
|
4288
|
-
try {
|
|
4289
|
-
switch (this._internalStoreType) {
|
|
4290
|
-
case "sqlite3":
|
|
4291
|
-
return this._upsertTransactionSQLite3(
|
|
4292
|
-
conn,
|
|
4293
|
-
upsertQuery,
|
|
4294
|
-
upsertParams
|
|
4295
|
-
);
|
|
4296
|
-
case "better-sqlite3":
|
|
4297
|
-
return this._upsertTransactionBetterSQLite3(
|
|
4298
|
-
conn,
|
|
4299
|
-
upsertQuery,
|
|
4300
|
-
upsertParams
|
|
4301
|
-
);
|
|
4302
|
-
default:
|
|
4303
|
-
throw new Error("Unsupported internalStoreType");
|
|
4304
|
-
}
|
|
4305
|
-
} finally {
|
|
4306
|
-
this._releaseConnection(conn);
|
|
4307
|
-
}
|
|
4308
|
-
}
|
|
4309
|
-
_upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
4310
|
-
if (!this.tableCreated) {
|
|
4311
|
-
return Promise.reject(new Error("Table is not created yet"));
|
|
4312
|
-
}
|
|
4313
|
-
return this._upsertTransaction(rlKey, points, msDuration, forceExpire);
|
|
4314
|
-
}
|
|
4315
|
-
async _get(rlKey) {
|
|
4316
|
-
const sql = `SELECT points, expire FROM ${this.tableName} WHERE key = ? AND (expire > ? OR expire IS NULL)`;
|
|
4317
|
-
const now = Date.now();
|
|
4318
|
-
const conn = await this._getConnection();
|
|
4319
|
-
try {
|
|
4320
|
-
switch (this._internalStoreType) {
|
|
4321
|
-
case "sqlite3":
|
|
4322
|
-
return await new Promise((resolve, reject) => {
|
|
4323
|
-
conn.get(
|
|
4324
|
-
sql,
|
|
4325
|
-
[rlKey, now],
|
|
4326
|
-
(err, row) => err ? reject(err) : resolve(row || null)
|
|
4327
|
-
);
|
|
4328
|
-
});
|
|
4329
|
-
case "better-sqlite3":
|
|
4330
|
-
return conn.prepare(sql).get(rlKey, now) || null;
|
|
4331
|
-
default:
|
|
4332
|
-
throw new Error("Unsupported internalStoreType");
|
|
4333
|
-
}
|
|
4334
|
-
} finally {
|
|
4335
|
-
this._releaseConnection(conn);
|
|
4336
|
-
}
|
|
4337
|
-
}
|
|
4338
|
-
async _delete(rlKey) {
|
|
4339
|
-
if (!this.tableCreated) {
|
|
4340
|
-
return Promise.reject(new Error("Table is not created yet"));
|
|
4341
|
-
}
|
|
4342
|
-
const sql = `DELETE FROM ${this.tableName} WHERE key = ?`;
|
|
4343
|
-
const conn = await this._getConnection();
|
|
4344
|
-
try {
|
|
4345
|
-
switch (this._internalStoreType) {
|
|
4346
|
-
case "sqlite3":
|
|
4347
|
-
return await new Promise((resolve, reject) => {
|
|
4348
|
-
conn.run(sql, [rlKey], function(err) {
|
|
4349
|
-
if (err) reject(err);
|
|
4350
|
-
else resolve(this.changes > 0);
|
|
4351
|
-
});
|
|
4352
|
-
});
|
|
4353
|
-
case "better-sqlite3":
|
|
4354
|
-
const result = conn.prepare(sql).run(rlKey);
|
|
4355
|
-
return result.changes > 0;
|
|
4356
|
-
default:
|
|
4357
|
-
throw new Error("Unsupported internalStoreType");
|
|
4358
|
-
}
|
|
4359
|
-
} finally {
|
|
4360
|
-
this._releaseConnection(conn);
|
|
4361
|
-
}
|
|
4362
|
-
}
|
|
4363
|
-
};
|
|
4364
|
-
module2.exports = RateLimiterSQLite;
|
|
4365
|
-
}
|
|
4366
|
-
});
|
|
4367
|
-
|
|
4368
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/RateLimiterEtcdTransactionFailedError.js
|
|
4369
|
-
var require_RateLimiterEtcdTransactionFailedError = __commonJS({
|
|
4370
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/RateLimiterEtcdTransactionFailedError.js"(exports2, module2) {
|
|
4371
|
-
"use strict";
|
|
4372
|
-
module2.exports = class RateLimiterEtcdTransactionFailedError extends Error {
|
|
4373
|
-
constructor(message) {
|
|
4374
|
-
super();
|
|
4375
|
-
if (Error.captureStackTrace) {
|
|
4376
|
-
Error.captureStackTrace(this, this.constructor);
|
|
4377
|
-
}
|
|
4378
|
-
this.name = "RateLimiterEtcdTransactionFailedError";
|
|
4379
|
-
this.message = message;
|
|
4380
|
-
}
|
|
4381
|
-
};
|
|
4382
|
-
}
|
|
4383
|
-
});
|
|
4384
|
-
|
|
4385
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/RateLimiterSetupError.js
|
|
4386
|
-
var require_RateLimiterSetupError = __commonJS({
|
|
4387
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/component/RateLimiterSetupError.js"(exports2, module2) {
|
|
4388
|
-
"use strict";
|
|
4389
|
-
module2.exports = class RateLimiterSetupError extends Error {
|
|
4390
|
-
constructor(message) {
|
|
4391
|
-
super();
|
|
4392
|
-
if (Error.captureStackTrace) {
|
|
4393
|
-
Error.captureStackTrace(this, this.constructor);
|
|
4394
|
-
}
|
|
4395
|
-
this.name = "RateLimiterSetupError";
|
|
4396
|
-
this.message = message;
|
|
4397
|
-
}
|
|
4398
|
-
};
|
|
4399
|
-
}
|
|
4400
|
-
});
|
|
4401
|
-
|
|
4402
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterEtcdNonAtomic.js
|
|
4403
|
-
var require_RateLimiterEtcdNonAtomic = __commonJS({
|
|
4404
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterEtcdNonAtomic.js"(exports2, module2) {
|
|
4405
|
-
"use strict";
|
|
4406
|
-
var RateLimiterStoreAbstract = require_RateLimiterStoreAbstract();
|
|
4407
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
4408
|
-
var RateLimiterSetupError = require_RateLimiterSetupError();
|
|
4409
|
-
var RateLimiterEtcdNonAtomic = class extends RateLimiterStoreAbstract {
|
|
4410
|
-
/**
|
|
4411
|
-
* @param {Object} opts
|
|
4412
|
-
*/
|
|
4413
|
-
constructor(opts) {
|
|
4414
|
-
super(opts);
|
|
4415
|
-
if (!opts.storeClient) {
|
|
4416
|
-
throw new RateLimiterSetupError('You need to set the option "storeClient" to an instance of class "Etcd3".');
|
|
4417
|
-
}
|
|
4418
|
-
this.client = opts.storeClient;
|
|
4419
|
-
}
|
|
4420
|
-
/**
|
|
4421
|
-
* Get RateLimiterRes object filled depending on storeResult, which specific for exact store.
|
|
4422
|
-
*/
|
|
4423
|
-
_getRateLimiterRes(rlKey, changedPoints, result) {
|
|
4424
|
-
const res = new RateLimiterRes2();
|
|
4425
|
-
res.isFirstInDuration = changedPoints === result.points;
|
|
4426
|
-
res.consumedPoints = res.isFirstInDuration ? changedPoints : result.points;
|
|
4427
|
-
res.remainingPoints = Math.max(this.points - res.consumedPoints, 0);
|
|
4428
|
-
res.msBeforeNext = result.expire ? Math.max(result.expire - Date.now(), 0) : -1;
|
|
4429
|
-
return res;
|
|
4430
|
-
}
|
|
4431
|
-
/**
|
|
4432
|
-
* Resolve with object used for {@link _getRateLimiterRes} to generate {@link RateLimiterRes}.
|
|
4433
|
-
*/
|
|
4434
|
-
async _upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
4435
|
-
const expire = msDuration > 0 ? Date.now() + msDuration : null;
|
|
4436
|
-
let newValue = { points, expire };
|
|
4437
|
-
if (forceExpire) {
|
|
4438
|
-
await this.client.put(rlKey).value(JSON.stringify(newValue));
|
|
4439
|
-
} else {
|
|
4440
|
-
const oldValue = await this._get(rlKey);
|
|
4441
|
-
newValue = { points: (oldValue !== null ? oldValue.points : 0) + points, expire };
|
|
4442
|
-
await this.client.put(rlKey).value(JSON.stringify(newValue));
|
|
4443
|
-
}
|
|
4444
|
-
return newValue;
|
|
4445
|
-
}
|
|
4446
|
-
/**
|
|
4447
|
-
* Resolve with raw result from Store OR null if rlKey is not set
|
|
4448
|
-
* or Reject with error
|
|
4449
|
-
*/
|
|
4450
|
-
async _get(rlKey) {
|
|
4451
|
-
return this.client.get(rlKey).string().then((result) => result !== null ? JSON.parse(result) : null);
|
|
4452
|
-
}
|
|
4453
|
-
/**
|
|
4454
|
-
* Resolve with true OR false if rlKey doesn't exist.
|
|
4455
|
-
* or Reject with error.
|
|
4456
|
-
*/
|
|
4457
|
-
async _delete(rlKey) {
|
|
4458
|
-
return this.client.delete().key(rlKey).then((result) => result.deleted === "1");
|
|
4459
|
-
}
|
|
4460
|
-
};
|
|
4461
|
-
module2.exports = RateLimiterEtcdNonAtomic;
|
|
4462
|
-
}
|
|
4463
|
-
});
|
|
4464
|
-
|
|
4465
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterEtcd.js
|
|
4466
|
-
var require_RateLimiterEtcd = __commonJS({
|
|
4467
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/lib/RateLimiterEtcd.js"(exports2, module2) {
|
|
4468
|
-
"use strict";
|
|
4469
|
-
var RateLimiterEtcdTransactionFailedError = require_RateLimiterEtcdTransactionFailedError();
|
|
4470
|
-
var RateLimiterEtcdNonAtomic = require_RateLimiterEtcdNonAtomic();
|
|
4471
|
-
var MAX_TRANSACTION_TRIES = 5;
|
|
4472
|
-
var RateLimiterEtcd = class extends RateLimiterEtcdNonAtomic {
|
|
4473
|
-
/**
|
|
4474
|
-
* Resolve with object used for {@link _getRateLimiterRes} to generate {@link RateLimiterRes}.
|
|
4475
|
-
*/
|
|
4476
|
-
async _upsert(rlKey, points, msDuration, forceExpire = false) {
|
|
4477
|
-
const expire = msDuration > 0 ? Date.now() + msDuration : null;
|
|
4478
|
-
let newValue = { points, expire };
|
|
4479
|
-
let oldValue;
|
|
4480
|
-
if (forceExpire) {
|
|
4481
|
-
await this.client.put(rlKey).value(JSON.stringify(newValue));
|
|
4482
|
-
} else {
|
|
4483
|
-
const added = await this.client.if(rlKey, "Version", "===", "0").then(this.client.put(rlKey).value(JSON.stringify(newValue))).commit().then((result) => !!result.succeeded);
|
|
4484
|
-
if (!added) {
|
|
4485
|
-
let success2 = false;
|
|
4486
|
-
for (let i = 0; i < MAX_TRANSACTION_TRIES; i++) {
|
|
4487
|
-
oldValue = await this._get(rlKey);
|
|
4488
|
-
newValue = { points: oldValue.points + points, expire };
|
|
4489
|
-
success2 = await this.client.if(rlKey, "Value", "===", JSON.stringify(oldValue)).then(this.client.put(rlKey).value(JSON.stringify(newValue))).commit().then((result) => !!result.succeeded);
|
|
4490
|
-
if (success2) {
|
|
4491
|
-
break;
|
|
4492
|
-
}
|
|
4493
|
-
}
|
|
4494
|
-
if (!success2) {
|
|
4495
|
-
throw new RateLimiterEtcdTransactionFailedError("Could not set new value in a transaction.");
|
|
4496
|
-
}
|
|
4497
|
-
}
|
|
4498
|
-
}
|
|
4499
|
-
return newValue;
|
|
4500
|
-
}
|
|
4501
|
-
};
|
|
4502
|
-
module2.exports = RateLimiterEtcd;
|
|
4503
|
-
}
|
|
4504
|
-
});
|
|
4505
|
-
|
|
4506
|
-
// node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/index.js
|
|
4507
|
-
var require_rate_limiter_flexible = __commonJS({
|
|
4508
|
-
"node_modules/.pnpm/rate-limiter-flexible@10.0.1/node_modules/rate-limiter-flexible/index.js"(exports2, module2) {
|
|
4509
|
-
"use strict";
|
|
4510
|
-
var RateLimiterRedis = require_RateLimiterRedis();
|
|
4511
|
-
var RateLimiterRedisNonAtomic = require_RateLimiterRedisNonAtomic();
|
|
4512
|
-
var RateLimiterMongo = require_RateLimiterMongo();
|
|
4513
|
-
var RateLimiterMySQL = require_RateLimiterMySQL();
|
|
4514
|
-
var RateLimiterPostgres = require_RateLimiterPostgres();
|
|
4515
|
-
var { RateLimiterClusterMaster, RateLimiterClusterMasterPM2, RateLimiterCluster } = require_RateLimiterCluster();
|
|
4516
|
-
var RateLimiterMemory2 = require_RateLimiterMemory();
|
|
4517
|
-
var RateLimiterMemcache = require_RateLimiterMemcache();
|
|
4518
|
-
var RLWrapperBlackAndWhite = require_RLWrapperBlackAndWhite();
|
|
4519
|
-
var RLWrapperTimeouts = require_RLWrapperTimeouts();
|
|
4520
|
-
var RateLimiterUnion = require_RateLimiterUnion();
|
|
4521
|
-
var RateLimiterQueue = require_RateLimiterQueue();
|
|
4522
|
-
var BurstyRateLimiter = require_BurstyRateLimiter();
|
|
4523
|
-
var RateLimiterRes2 = require_RateLimiterRes();
|
|
4524
|
-
var RateLimiterDynamo = require_RateLimiterDynamo();
|
|
4525
|
-
var RateLimiterPrisma = require_RateLimiterPrisma();
|
|
4526
|
-
var RateLimiterDrizzle = require_RateLimiterDrizzle();
|
|
4527
|
-
var RateLimiterDrizzleNonAtomic = require_RateLimiterDrizzleNonAtomic();
|
|
4528
|
-
var RateLimiterValkey = require_RateLimiterValkey();
|
|
4529
|
-
var RateLimiterValkeyGlide = require_RateLimiterValkeyGlide();
|
|
4530
|
-
var RateLimiterSQLite = require_RateLimiterSQLite();
|
|
4531
|
-
var RateLimiterEtcd = require_RateLimiterEtcd();
|
|
4532
|
-
var RateLimiterEtcdNonAtomic = require_RateLimiterEtcdNonAtomic();
|
|
4533
|
-
var RateLimiterQueueError = require_RateLimiterQueueError();
|
|
4534
|
-
var RateLimiterEtcdTransactionFailedError = require_RateLimiterEtcdTransactionFailedError();
|
|
4535
|
-
module2.exports = {
|
|
4536
|
-
RateLimiterRedis,
|
|
4537
|
-
RateLimiterRedisNonAtomic,
|
|
4538
|
-
RateLimiterMongo,
|
|
4539
|
-
RateLimiterMySQL,
|
|
4540
|
-
RateLimiterPostgres,
|
|
4541
|
-
RateLimiterMemory: RateLimiterMemory2,
|
|
4542
|
-
RateLimiterMemcache,
|
|
4543
|
-
RateLimiterClusterMaster,
|
|
4544
|
-
RateLimiterClusterMasterPM2,
|
|
4545
|
-
RateLimiterCluster,
|
|
4546
|
-
RLWrapperBlackAndWhite,
|
|
4547
|
-
RLWrapperTimeouts,
|
|
4548
|
-
RateLimiterUnion,
|
|
4549
|
-
RateLimiterQueue,
|
|
4550
|
-
BurstyRateLimiter,
|
|
4551
|
-
RateLimiterRes: RateLimiterRes2,
|
|
4552
|
-
RateLimiterDynamo,
|
|
4553
|
-
RateLimiterPrisma,
|
|
4554
|
-
RateLimiterValkey,
|
|
4555
|
-
RateLimiterValkeyGlide,
|
|
4556
|
-
RateLimiterSQLite,
|
|
4557
|
-
RateLimiterEtcd,
|
|
4558
|
-
RateLimiterDrizzle,
|
|
4559
|
-
RateLimiterDrizzleNonAtomic,
|
|
4560
|
-
RateLimiterEtcdNonAtomic,
|
|
4561
|
-
RateLimiterQueueError,
|
|
4562
|
-
RateLimiterEtcdTransactionFailedError
|
|
4563
|
-
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
4564
15
|
}
|
|
4565
|
-
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
4566
19
|
|
|
4567
20
|
// src/index.ts
|
|
4568
21
|
var index_exports = {};
|
|
@@ -18557,9 +14010,9 @@ function handleError_default(err) {
|
|
|
18557
14010
|
if (err instanceof external_exports.ZodError) {
|
|
18558
14011
|
return new Errors(err.issues[0].message, "VALIDATION_ERROR", 400);
|
|
18559
14012
|
}
|
|
18560
|
-
const
|
|
18561
|
-
if (
|
|
18562
|
-
return
|
|
14013
|
+
const fbError = firebaseError(err);
|
|
14014
|
+
if (fbError instanceof Errors) {
|
|
14015
|
+
return fbError;
|
|
18563
14016
|
}
|
|
18564
14017
|
return new Errors("Internal server error", "INTERNAL_SERVER_ERROR", 500);
|
|
18565
14018
|
}
|
|
@@ -18582,39 +14035,33 @@ function pathWithParams_default(path, params) {
|
|
|
18582
14035
|
return queryString ? `${basePath}?${queryString}` : basePath;
|
|
18583
14036
|
}
|
|
18584
14037
|
|
|
18585
|
-
// src/withRateLimit.ts
|
|
18586
|
-
var import_rate_limiter_flexible = __toESM(require_rate_limiter_flexible());
|
|
18587
|
-
|
|
18588
14038
|
// src/getIp.ts
|
|
18589
14039
|
function getIp_default(request) {
|
|
18590
14040
|
return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || request.headers.get("CF-Connecting-IP") || request.headers.get("X-Forwarded-For") || "unknown";
|
|
18591
14041
|
}
|
|
18592
14042
|
|
|
18593
14043
|
// src/withRateLimit.ts
|
|
14044
|
+
function isRateLimiterRes(err) {
|
|
14045
|
+
return err && typeof err === "object" && "msBeforeNext" in err && "remainingPoints" in err;
|
|
14046
|
+
}
|
|
18594
14047
|
function withRateLimit_default(handler, limiter) {
|
|
18595
14048
|
return async (event) => {
|
|
18596
14049
|
const ip = getIp_default(event.request);
|
|
18597
14050
|
try {
|
|
18598
14051
|
await limiter.consume(ip);
|
|
18599
14052
|
} catch (err) {
|
|
18600
|
-
if (err
|
|
18601
|
-
Response.
|
|
18602
|
-
|
|
18603
|
-
{
|
|
18604
|
-
|
|
18605
|
-
|
|
18606
|
-
"Retry-After": "1800",
|
|
18607
|
-
"Content-Type": "application/json"
|
|
18608
|
-
}
|
|
14053
|
+
if (isRateLimiterRes(err)) {
|
|
14054
|
+
new Response(JSON.stringify({ error: "Too many requests" }), {
|
|
14055
|
+
status: 429,
|
|
14056
|
+
headers: {
|
|
14057
|
+
"Retry-After": "1800",
|
|
14058
|
+
"Content-Type": "application/json"
|
|
18609
14059
|
}
|
|
18610
|
-
);
|
|
14060
|
+
});
|
|
18611
14061
|
}
|
|
18612
|
-
return Response.
|
|
18613
|
-
|
|
18614
|
-
|
|
18615
|
-
status: 500
|
|
18616
|
-
}
|
|
18617
|
-
);
|
|
14062
|
+
return new Response(JSON.stringify({ error: "Internal server error" }), {
|
|
14063
|
+
status: 500
|
|
14064
|
+
});
|
|
18618
14065
|
}
|
|
18619
14066
|
return handler({ ...event, ip });
|
|
18620
14067
|
};
|
|
@@ -18623,11 +14070,14 @@ function withRateLimit_default(handler, limiter) {
|
|
|
18623
14070
|
// src/validateTurnstile.ts
|
|
18624
14071
|
function validateTurnstile_default(handler, secretKey) {
|
|
18625
14072
|
return async (event) => {
|
|
14073
|
+
if (!secretKey) {
|
|
14074
|
+
return new Response(JSON.stringify({ error: "Invalid secret key" }));
|
|
14075
|
+
}
|
|
18626
14076
|
const body = await event.request.json();
|
|
18627
14077
|
const token = body["cf-turnstile-response"];
|
|
18628
14078
|
const ip = getIp_default(event.request);
|
|
18629
14079
|
if (!token) {
|
|
18630
|
-
return Response.
|
|
14080
|
+
return new Response(JSON.stringify({ error: "Captcha not sent" }));
|
|
18631
14081
|
}
|
|
18632
14082
|
const response = await fetch(
|
|
18633
14083
|
"https://challenges.cloudflare.com/turnstile/v0/siteverify",
|
|
@@ -18644,7 +14094,9 @@ function validateTurnstile_default(handler, secretKey) {
|
|
|
18644
14094
|
}
|
|
18645
14095
|
);
|
|
18646
14096
|
if (!response.ok) {
|
|
18647
|
-
return Response.
|
|
14097
|
+
return new Response(JSON.stringify({ error: "Invalid verification" }), {
|
|
14098
|
+
status: 400
|
|
14099
|
+
});
|
|
18648
14100
|
}
|
|
18649
14101
|
return handler({ ...event, ip });
|
|
18650
14102
|
};
|
|
@@ -18659,7 +14111,6 @@ __export(constants_exports, {
|
|
|
18659
14111
|
LANG_STRATEGY: () => LANG_STRATEGY,
|
|
18660
14112
|
ORG_NAME: () => ORG_NAME,
|
|
18661
14113
|
PROTOCOL: () => PROTOCOL,
|
|
18662
|
-
RATE_LIMIT_DEFAULT_OPTIONS: () => RATE_LIMIT_DEFAULT_OPTIONS,
|
|
18663
14114
|
SUPPORT_EMAIL: () => SUPPORT_EMAIL,
|
|
18664
14115
|
URLS: () => URLS
|
|
18665
14116
|
});
|
|
@@ -18684,11 +14135,6 @@ var LANG_STRATEGY = [
|
|
|
18684
14135
|
"baseLocale",
|
|
18685
14136
|
"globalVariable"
|
|
18686
14137
|
];
|
|
18687
|
-
var RATE_LIMIT_DEFAULT_OPTIONS = {
|
|
18688
|
-
points: 3,
|
|
18689
|
-
duration: 60 * 60,
|
|
18690
|
-
blockDuration: 30 * 60
|
|
18691
|
-
};
|
|
18692
14138
|
// Annotate the CommonJS export names for ESM import in node:
|
|
18693
14139
|
0 && (module.exports = {
|
|
18694
14140
|
Constants,
|