@upstash/ratelimit 2.0.8 → 2.1.0-rc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -78,6 +78,25 @@ For more information on getting started, you can refer to [our documentation](ht
78
78
 
79
79
  See [the documentation](https://upstash.com/docs/redis/sdks/ratelimit-ts/overview) for more information details about this package.
80
80
 
81
+ ## Telemetry
82
+
83
+ The SDK reports its name and version to Upstash as a header on the requests made
84
+ by the redis client you provide, so we know which SDK versions are in use. No
85
+ personal data, keys or identifiers are collected.
86
+
87
+ You can opt out with `enableTelemetry: false`:
88
+
89
+ ```ts
90
+ const ratelimit = new Ratelimit({
91
+ redis: Redis.fromEnv(),
92
+ limiter: Ratelimit.slidingWindow(10, "10 s"),
93
+ enableTelemetry: false,
94
+ });
95
+ ```
96
+
97
+ or by setting the `UPSTASH_DISABLE_TELEMETRY` environment variable. Disabling
98
+ telemetry on the redis client itself also disables it here.
99
+
81
100
  ## Contributing
82
101
 
83
102
  ### Database
package/dist/index.d.mts CHANGED
@@ -495,6 +495,17 @@ type MultiRegionRatelimitConfig = {
495
495
  * @default false
496
496
  */
497
497
  dynamicLimits?: boolean;
498
+ /**
499
+ * Enable telemetry to help us improve the SDK.
500
+ *
501
+ * The sdk name and version are sent to Upstash as a header on the requests
502
+ * made by the redis clients you provide.
503
+ *
504
+ * Can also be disabled with the `UPSTASH_DISABLE_TELEMETRY` env variable.
505
+ *
506
+ * @default true
507
+ */
508
+ enableTelemetry?: boolean;
498
509
  };
499
510
  /**
500
511
  * Ratelimiter using serverless redis from https://upstash.com/
@@ -652,6 +663,17 @@ type RegionRatelimitConfig = {
652
663
  * @default false
653
664
  */
654
665
  dynamicLimits?: boolean;
666
+ /**
667
+ * Enable telemetry to help us improve the SDK.
668
+ *
669
+ * The sdk name and version are sent to Upstash as a header on the requests
670
+ * made by the redis client you provide.
671
+ *
672
+ * Can also be disabled with the `UPSTASH_DISABLE_TELEMETRY` env variable.
673
+ *
674
+ * @default true
675
+ */
676
+ enableTelemetry?: boolean;
655
677
  };
656
678
  /**
657
679
  * Ratelimiter using serverless redis from https://upstash.com/
package/dist/index.d.ts CHANGED
@@ -495,6 +495,17 @@ type MultiRegionRatelimitConfig = {
495
495
  * @default false
496
496
  */
497
497
  dynamicLimits?: boolean;
498
+ /**
499
+ * Enable telemetry to help us improve the SDK.
500
+ *
501
+ * The sdk name and version are sent to Upstash as a header on the requests
502
+ * made by the redis clients you provide.
503
+ *
504
+ * Can also be disabled with the `UPSTASH_DISABLE_TELEMETRY` env variable.
505
+ *
506
+ * @default true
507
+ */
508
+ enableTelemetry?: boolean;
498
509
  };
499
510
  /**
500
511
  * Ratelimiter using serverless redis from https://upstash.com/
@@ -652,6 +663,17 @@ type RegionRatelimitConfig = {
652
663
  * @default false
653
664
  */
654
665
  dynamicLimits?: boolean;
666
+ /**
667
+ * Enable telemetry to help us improve the SDK.
668
+ *
669
+ * The sdk name and version are sent to Upstash as a header on the requests
670
+ * made by the redis client you provide.
671
+ *
672
+ * Can also be disabled with the `UPSTASH_DISABLE_TELEMETRY` env variable.
673
+ *
674
+ * @default true
675
+ */
676
+ enableTelemetry?: boolean;
655
677
  };
656
678
  /**
657
679
  * Ratelimiter using serverless redis from https://upstash.com/
package/dist/index.js CHANGED
@@ -179,7 +179,7 @@ var safeEval = async (ctx, script, keys, args) => {
179
179
  };
180
180
 
181
181
  // src/lua-scripts/single.ts
182
- var fixedWindowLimitScript = `
182
+ var fixedWindowLimitScript = `#!lua flags=allow-key-locking
183
183
  local key = KEYS[1]
184
184
  local dynamicLimitKey = KEYS[2] -- optional: key for dynamic limit in redis
185
185
  local tokens = tonumber(ARGV[1]) -- default limit
@@ -204,7 +204,7 @@ var fixedWindowLimitScript = `
204
204
 
205
205
  return {r, effectiveLimit}
206
206
  `;
207
- var fixedWindowRemainingTokensScript = `
207
+ var fixedWindowRemainingTokensScript = `#!lua flags=allow-key-locking
208
208
  local key = KEYS[1]
209
209
  local dynamicLimitKey = KEYS[2] -- optional: key for dynamic limit in redis
210
210
  local tokens = tonumber(ARGV[1]) -- default limit
@@ -226,7 +226,7 @@ var fixedWindowRemainingTokensScript = `
226
226
 
227
227
  return {effectiveLimit - usedTokens, effectiveLimit}
228
228
  `;
229
- var slidingWindowLimitScript = `
229
+ var slidingWindowLimitScript = `#!lua flags=allow-key-locking
230
230
  local currentKey = KEYS[1] -- identifier including prefixes
231
231
  local previousKey = KEYS[2] -- key of the previous bucket
232
232
  local dynamicLimitKey = KEYS[3] -- optional: key for dynamic limit in redis
@@ -270,7 +270,7 @@ var slidingWindowLimitScript = `
270
270
  end
271
271
  return {effectiveLimit - ( newValue + requestsInPreviousWindow ), effectiveLimit}
272
272
  `;
273
- var slidingWindowRemainingTokensScript = `
273
+ var slidingWindowRemainingTokensScript = `#!lua flags=allow-key-locking
274
274
  local currentKey = KEYS[1] -- identifier including prefixes
275
275
  local previousKey = KEYS[2] -- key of the previous bucket
276
276
  local dynamicLimitKey = KEYS[3] -- optional: key for dynamic limit in redis
@@ -304,7 +304,7 @@ var slidingWindowRemainingTokensScript = `
304
304
  local usedTokens = requestsInPreviousWindow + requestsInCurrentWindow
305
305
  return {effectiveLimit - usedTokens, effectiveLimit}
306
306
  `;
307
- var tokenBucketLimitScript = `
307
+ var tokenBucketLimitScript = `#!lua flags=allow-key-locking
308
308
  local key = KEYS[1] -- identifier including prefixes
309
309
  local dynamicLimitKey = KEYS[2] -- optional: key for dynamic limit in redis
310
310
  local maxTokens = tonumber(ARGV[1]) -- default maximum number of tokens
@@ -358,7 +358,7 @@ var tokenBucketLimitScript = `
358
358
  return {remaining, refilledAt + interval, effectiveLimit}
359
359
  `;
360
360
  var tokenBucketIdentifierNotFound = -1;
361
- var tokenBucketRemainingTokensScript = `
361
+ var tokenBucketRemainingTokensScript = `#!lua flags=allow-key-locking
362
362
  local key = KEYS[1]
363
363
  local dynamicLimitKey = KEYS[2] -- optional: key for dynamic limit in redis
364
364
  local maxTokens = tonumber(ARGV[1]) -- default maximum number of tokens
@@ -380,7 +380,7 @@ var tokenBucketRemainingTokensScript = `
380
380
 
381
381
  return {tonumber(bucket[2]), tonumber(bucket[1]), effectiveLimit}
382
382
  `;
383
- var cachedFixedWindowLimitScript = `
383
+ var cachedFixedWindowLimitScript = `#!lua flags=allow-key-locking
384
384
  local key = KEYS[1]
385
385
  local window = ARGV[1]
386
386
  local incrementBy = ARGV[2] -- increment rate per request at a given value, default is 1
@@ -394,7 +394,7 @@ var cachedFixedWindowLimitScript = `
394
394
 
395
395
  return r
396
396
  `;
397
- var cachedFixedWindowRemainingTokenScript = `
397
+ var cachedFixedWindowRemainingTokenScript = `#!lua flags=allow-key-locking
398
398
  local key = KEYS[1]
399
399
  local tokens = 0
400
400
 
@@ -406,7 +406,7 @@ var cachedFixedWindowRemainingTokenScript = `
406
406
  `;
407
407
 
408
408
  // src/lua-scripts/multi.ts
409
- var fixedWindowLimitScript2 = `
409
+ var fixedWindowLimitScript2 = `#!lua flags=allow-key-locking
410
410
  local key = KEYS[1]
411
411
  local id = ARGV[1]
412
412
  local window = ARGV[2]
@@ -422,7 +422,7 @@ var fixedWindowLimitScript2 = `
422
422
 
423
423
  return fields
424
424
  `;
425
- var fixedWindowRemainingTokensScript2 = `
425
+ var fixedWindowRemainingTokensScript2 = `#!lua flags=allow-key-locking
426
426
  local key = KEYS[1]
427
427
  local tokens = 0
428
428
 
@@ -430,7 +430,7 @@ var fixedWindowRemainingTokensScript2 = `
430
430
 
431
431
  return fields
432
432
  `;
433
- var slidingWindowLimitScript2 = `
433
+ var slidingWindowLimitScript2 = `#!lua flags=allow-key-locking
434
434
  local currentKey = KEYS[1] -- identifier including prefixes
435
435
  local previousKey = KEYS[2] -- key of the previous bucket
436
436
  local tokens = tonumber(ARGV[1]) -- tokens per window
@@ -467,7 +467,7 @@ var slidingWindowLimitScript2 = `
467
467
  end
468
468
  return {currentFields, previousFields, true}
469
469
  `;
470
- var slidingWindowRemainingTokensScript2 = `
470
+ var slidingWindowRemainingTokensScript2 = `#!lua flags=allow-key-locking
471
471
  local currentKey = KEYS[1] -- identifier including prefixes
472
472
  local previousKey = KEYS[2] -- key of the previous bucket
473
473
  local now = ARGV[1] -- current timestamp in milliseconds
@@ -522,41 +522,41 @@ var SCRIPTS = {
522
522
  fixedWindow: {
523
523
  limit: {
524
524
  script: fixedWindowLimitScript,
525
- hash: "472e55443b62f60d0991028456c57815a387066d"
525
+ hash: "4ef8749b9e927b157546ebad13061fa86b9ffc2e"
526
526
  },
527
527
  getRemaining: {
528
528
  script: fixedWindowRemainingTokensScript,
529
- hash: "40515c9dd0a08f8584f5f9b593935f6a87c1c1c3"
529
+ hash: "e62252cb05b4676b27a5d396da02f0ca0d375d88"
530
530
  }
531
531
  },
532
532
  slidingWindow: {
533
533
  limit: {
534
534
  script: slidingWindowLimitScript,
535
- hash: "977fb636fb5ceb7e98a96d1b3a1272ba018efdae"
535
+ hash: "5cd9665be7533e4dfabb3581021737fc69b41ae8"
536
536
  },
537
537
  getRemaining: {
538
538
  script: slidingWindowRemainingTokensScript,
539
- hash: "ee3a3265fad822f83acad23f8a1e2f5c0b156b03"
539
+ hash: "1bdbbdb2082bb557084518c64486d7d5a29d1bfe"
540
540
  }
541
541
  },
542
542
  tokenBucket: {
543
543
  limit: {
544
544
  script: tokenBucketLimitScript,
545
- hash: "b35c5bc0b7fdae7dd0573d4529911cabaf9d1d89"
545
+ hash: "8f7286b9b0f65d631f760ba615f7b3c598a569a3"
546
546
  },
547
547
  getRemaining: {
548
548
  script: tokenBucketRemainingTokensScript,
549
- hash: "deb03663e8af5a968deee895dd081be553d2611b"
549
+ hash: "08d3b3381c507b6f7bfec1bbfa0a6053434b16bd"
550
550
  }
551
551
  },
552
552
  cachedFixedWindow: {
553
553
  limit: {
554
554
  script: cachedFixedWindowLimitScript,
555
- hash: "c26b12703dd137939b9a69a3a9b18e906a2d940f"
555
+ hash: "1861a700bafe96c833a483af6b1c28a8897cfdb0"
556
556
  },
557
557
  getRemaining: {
558
558
  script: cachedFixedWindowRemainingTokenScript,
559
- hash: "8e8f222ccae68b595ee6e3f3bf2199629a62b91a"
559
+ hash: "eb82f0e853d2fc9a236fa9bfbe704fda6ac2fc36"
560
560
  }
561
561
  }
562
562
  },
@@ -564,21 +564,21 @@ var SCRIPTS = {
564
564
  fixedWindow: {
565
565
  limit: {
566
566
  script: fixedWindowLimitScript2,
567
- hash: "a8c14f3835aa87bd70e5e2116081b81664abcf5c"
567
+ hash: "e04b753a75909b7f99aae4c04cf8869a8de02a9e"
568
568
  },
569
569
  getRemaining: {
570
570
  script: fixedWindowRemainingTokensScript2,
571
- hash: "8ab8322d0ed5fe5ac8eb08f0c2e4557f1b4816fd"
571
+ hash: "e066c8ce3eaca142b0894ad1541e0a58c9924819"
572
572
  }
573
573
  },
574
574
  slidingWindow: {
575
575
  limit: {
576
576
  script: slidingWindowLimitScript2,
577
- hash: "1e7ca8dcd2d600a6d0124a67a57ea225ed62921b"
577
+ hash: "aeb4d8f381e8dafc8e69041baae1324d254ded44"
578
578
  },
579
579
  getRemaining: {
580
580
  script: slidingWindowRemainingTokensScript2,
581
- hash: "558c9306b7ec54abb50747fe0b17e5d44bd24868"
581
+ hash: "87828c1088f6a8d1f512a434ea330189982a1c0a"
582
582
  }
583
583
  }
584
584
  }
@@ -1059,6 +1059,27 @@ var Ratelimit = class {
1059
1059
  };
1060
1060
  };
1061
1061
 
1062
+ // src/version.ts
1063
+ var VERSION = "2.1.0-rc";
1064
+
1065
+ // src/telemetry.ts
1066
+ var taggedClients = /* @__PURE__ */ new WeakSet();
1067
+ var getSafeEnv = () => typeof process === "object" && process && typeof process.env === "object" ? process.env : {};
1068
+ var addTelemetry = (redis, enableTelemetry = true) => {
1069
+ if (!enableTelemetry || getSafeEnv().UPSTASH_DISABLE_TELEMETRY)
1070
+ return;
1071
+ if (!redis || typeof redis !== "object")
1072
+ return;
1073
+ if (taggedClients.has(redis))
1074
+ return;
1075
+ taggedClients.add(redis);
1076
+ try {
1077
+ const client = redis;
1078
+ client.addTelemetry?.({ sdk: `@upstash/ratelimit@${VERSION}` });
1079
+ } catch {
1080
+ }
1081
+ };
1082
+
1062
1083
  // src/multi.ts
1063
1084
  function randomId() {
1064
1085
  let result = "";
@@ -1088,6 +1109,9 @@ var MultiRegionRatelimit = class extends Ratelimit {
1088
1109
  cache: config.ephemeralCache ? new Cache(config.ephemeralCache) : void 0
1089
1110
  }
1090
1111
  });
1112
+ for (const redis of config.redis) {
1113
+ addTelemetry(redis, config.enableTelemetry);
1114
+ }
1091
1115
  if (config.dynamicLimits) {
1092
1116
  console.warn(
1093
1117
  "Warning: Dynamic limits are not yet supported for multi-region rate limiters. The dynamicLimits option will be ignored."
@@ -1458,6 +1482,7 @@ var RegionRatelimit = class extends Ratelimit {
1458
1482
  denyListThreshold: config.denyListThreshold,
1459
1483
  dynamicLimits: config.dynamicLimits
1460
1484
  });
1485
+ addTelemetry(config.redis, config.enableTelemetry);
1461
1486
  }
1462
1487
  /**
1463
1488
  * Each request inside a fixed time increases a counter.