@upstash/ratelimit 1.2.1 → 2.0.1-canary

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.mjs CHANGED
@@ -56,9 +56,10 @@ var Analytics = class {
56
56
  const result = await this.analytics.aggregateBucketsWithPipeline(this.table, groupby, timestampCount);
57
57
  return result;
58
58
  }
59
- async getMostAllowedBlocked(timestampCount, getTop) {
59
+ async getMostAllowedBlocked(timestampCount, getTop, checkAtMost) {
60
60
  getTop = getTop ?? 5;
61
- return this.analytics.getMostAllowedBlocked(this.table, timestampCount, getTop);
61
+ const timestamp = void 0;
62
+ return this.analytics.getMostAllowedBlocked(this.table, timestampCount, getTop, timestamp, checkAtMost);
62
63
  }
63
64
  };
64
65
 
@@ -560,6 +561,14 @@ var Ratelimit = class {
560
561
  const pattern = [this.prefix, identifier].join(":");
561
562
  await this.limiter().resetTokens(this.ctx, pattern);
562
563
  };
564
+ /**
565
+ * Returns the remaining token count together with a reset timestamps
566
+ *
567
+ * @param identifier identifir to check
568
+ * @returns object with `remaining` and reset fields. `remaining` denotes
569
+ * the remaining tokens and reset denotes the timestamp when the
570
+ * tokens reset.
571
+ */
563
572
  getRemaining = async (identifier) => {
564
573
  const pattern = [this.prefix, identifier].join(":");
565
574
  return await this.limiter().getRemaining(this.ctx, pattern);
@@ -844,7 +853,10 @@ var MultiRegionRatelimit = class extends Ratelimit {
844
853
  }
845
854
  return accTokens + parsedToken;
846
855
  }, 0);
847
- return Math.max(0, tokens - usedTokens);
856
+ return {
857
+ remaining: Math.max(0, tokens - usedTokens),
858
+ reset: (bucket + 1) * windowDuration
859
+ };
848
860
  },
849
861
  async resetTokens(ctx, identifier) {
850
862
  const pattern = [identifier, "*"].join(":");
@@ -1006,7 +1018,10 @@ var MultiRegionRatelimit = class extends Ratelimit {
1006
1018
  )
1007
1019
  }));
1008
1020
  const usedTokens = await Promise.any(dbs.map((s) => s.request));
1009
- return Math.max(0, tokens - usedTokens);
1021
+ return {
1022
+ remaining: Math.max(0, tokens - usedTokens),
1023
+ reset: (currentWindow + 1) * windowSize
1024
+ };
1010
1025
  },
1011
1026
  async resetTokens(ctx, identifier) {
1012
1027
  const pattern = [identifier, "*"].join(":");
@@ -1145,17 +1160,18 @@ var tokenBucketLimitScript = `
1145
1160
  redis.call("PEXPIRE", key, expireAt)
1146
1161
  return {remaining, refilledAt + interval}
1147
1162
  `;
1163
+ var tokenBucketIdentifierNotFound = -1;
1148
1164
  var tokenBucketRemainingTokensScript = `
1149
1165
  local key = KEYS[1]
1150
1166
  local maxTokens = tonumber(ARGV[1])
1151
1167
 
1152
- local bucket = redis.call("HMGET", key, "tokens")
1168
+ local bucket = redis.call("HMGET", key, "refilledAt", "tokens")
1153
1169
 
1154
1170
  if bucket[1] == false then
1155
- return maxTokens
1171
+ return {maxTokens, ${tokenBucketIdentifierNotFound}}
1156
1172
  end
1157
1173
 
1158
- return tonumber(bucket[1])
1174
+ return {tonumber(bucket[2]), tonumber(bucket[1])}
1159
1175
  `;
1160
1176
  var cachedFixedWindowLimitScript = `
1161
1177
  local key = KEYS[1]
@@ -1272,7 +1288,10 @@ var RegionRatelimit = class extends Ratelimit {
1272
1288
  [key],
1273
1289
  [null]
1274
1290
  );
1275
- return Math.max(0, tokens - usedTokens);
1291
+ return {
1292
+ remaining: Math.max(0, tokens - usedTokens),
1293
+ reset: (bucket + 1) * windowDuration
1294
+ };
1276
1295
  },
1277
1296
  async resetTokens(ctx, identifier) {
1278
1297
  const pattern = [identifier, "*"].join(":");
@@ -1361,7 +1380,10 @@ var RegionRatelimit = class extends Ratelimit {
1361
1380
  [currentKey, previousKey],
1362
1381
  [now, windowSize]
1363
1382
  );
1364
- return Math.max(0, tokens - usedTokens);
1383
+ return {
1384
+ remaining: Math.max(0, tokens - usedTokens),
1385
+ reset: (currentWindow + 1) * windowSize
1386
+ };
1365
1387
  },
1366
1388
  async resetTokens(ctx, identifier) {
1367
1389
  const pattern = [identifier, "*"].join(":");
@@ -1430,14 +1452,19 @@ var RegionRatelimit = class extends Ratelimit {
1430
1452
  };
1431
1453
  },
1432
1454
  async getRemaining(ctx, identifier) {
1433
- const remainingTokens = await safeEval(
1455
+ const [remainingTokens, refilledAt] = await safeEval(
1434
1456
  ctx,
1435
1457
  tokenBucketRemainingTokensScript,
1436
1458
  "getRemainingHash",
1437
1459
  [identifier],
1438
1460
  [maxTokens]
1439
1461
  );
1440
- return remainingTokens;
1462
+ const freshRefillAt = Date.now() + intervalDuration;
1463
+ const identifierRefillsAt = refilledAt + intervalDuration;
1464
+ return {
1465
+ remaining: remainingTokens,
1466
+ reset: refilledAt === tokenBucketIdentifierNotFound ? freshRefillAt : identifierRefillsAt
1467
+ };
1441
1468
  },
1442
1469
  async resetTokens(ctx, identifier) {
1443
1470
  const pattern = identifier;
@@ -1534,7 +1561,10 @@ var RegionRatelimit = class extends Ratelimit {
1534
1561
  const hit = typeof ctx.cache.get(key) === "number";
1535
1562
  if (hit) {
1536
1563
  const cachedUsedTokens = ctx.cache.get(key) ?? 0;
1537
- return Math.max(0, tokens - cachedUsedTokens);
1564
+ return {
1565
+ remaining: Math.max(0, tokens - cachedUsedTokens),
1566
+ reset: (bucket + 1) * windowDuration
1567
+ };
1538
1568
  }
1539
1569
  const usedTokens = await safeEval(
1540
1570
  ctx,
@@ -1543,7 +1573,10 @@ var RegionRatelimit = class extends Ratelimit {
1543
1573
  [key],
1544
1574
  [null]
1545
1575
  );
1546
- return Math.max(0, tokens - usedTokens);
1576
+ return {
1577
+ remaining: Math.max(0, tokens - usedTokens),
1578
+ reset: (bucket + 1) * windowDuration
1579
+ };
1547
1580
  },
1548
1581
  async resetTokens(ctx, identifier) {
1549
1582
  if (!ctx.cache) {