summaryrefslogtreecommitdiff
path: root/shared/logger/node_modules/@sentry/utils/esm/ratelimit.js
diff options
context:
space:
mode:
Diffstat (limited to 'shared/logger/node_modules/@sentry/utils/esm/ratelimit.js')
-rw-r--r--shared/logger/node_modules/@sentry/utils/esm/ratelimit.js97
1 files changed, 97 insertions, 0 deletions
diff --git a/shared/logger/node_modules/@sentry/utils/esm/ratelimit.js b/shared/logger/node_modules/@sentry/utils/esm/ratelimit.js
new file mode 100644
index 0000000..becfdf0
--- /dev/null
+++ b/shared/logger/node_modules/@sentry/utils/esm/ratelimit.js
@@ -0,0 +1,97 @@
+// Intentionally keeping the key broad, as we don't know for sure what rate limit headers get returned from backend
+
+const DEFAULT_RETRY_AFTER = 60 * 1000; // 60 seconds
+
+/**
+ * Extracts Retry-After value from the request header or returns default value
+ * @param header string representation of 'Retry-After' header
+ * @param now current unix timestamp
+ *
+ */
+function parseRetryAfterHeader(header, now = Date.now()) {
+ const headerDelay = parseInt(`${header}`, 10);
+ if (!isNaN(headerDelay)) {
+ return headerDelay * 1000;
+ }
+
+ const headerDate = Date.parse(`${header}`);
+ if (!isNaN(headerDate)) {
+ return headerDate - now;
+ }
+
+ return DEFAULT_RETRY_AFTER;
+}
+
+/**
+ * Gets the time that the given category is disabled until for rate limiting.
+ * In case no category-specific limit is set but a general rate limit across all categories is active,
+ * that time is returned.
+ *
+ * @return the time in ms that the category is disabled until or 0 if there's no active rate limit.
+ */
+function disabledUntil(limits, category) {
+ return limits[category] || limits.all || 0;
+}
+
+/**
+ * Checks if a category is rate limited
+ */
+function isRateLimited(limits, category, now = Date.now()) {
+ return disabledUntil(limits, category) > now;
+}
+
+/**
+ * Update ratelimits from incoming headers.
+ *
+ * @return the updated RateLimits object.
+ */
+function updateRateLimits(
+ limits,
+ { statusCode, headers },
+ now = Date.now(),
+) {
+ const updatedRateLimits = {
+ ...limits,
+ };
+
+ // "The name is case-insensitive."
+ // https://developer.mozilla.org/en-US/docs/Web/API/Headers/get
+ const rateLimitHeader = headers && headers['x-sentry-rate-limits'];
+ const retryAfterHeader = headers && headers['retry-after'];
+
+ if (rateLimitHeader) {
+ /**
+ * rate limit headers are of the form
+ * <header>,<header>,..
+ * where each <header> is of the form
+ * <retry_after>: <categories>: <scope>: <reason_code>
+ * where
+ * <retry_after> is a delay in seconds
+ * <categories> is the event type(s) (error, transaction, etc) being rate limited and is of the form
+ * <category>;<category>;...
+ * <scope> is what's being limited (org, project, or key) - ignored by SDK
+ * <reason_code> is an arbitrary string like "org_quota" - ignored by SDK
+ */
+ for (const limit of rateLimitHeader.trim().split(',')) {
+ const [retryAfter, categories] = limit.split(':', 2);
+ const headerDelay = parseInt(retryAfter, 10);
+ const delay = (!isNaN(headerDelay) ? headerDelay : 60) * 1000; // 60sec default
+ if (!categories) {
+ updatedRateLimits.all = now + delay;
+ } else {
+ for (const category of categories.split(';')) {
+ updatedRateLimits[category] = now + delay;
+ }
+ }
+ }
+ } else if (retryAfterHeader) {
+ updatedRateLimits.all = now + parseRetryAfterHeader(retryAfterHeader, now);
+ } else if (statusCode === 429) {
+ updatedRateLimits.all = now + 60 * 1000;
+ }
+
+ return updatedRateLimits;
+}
+
+export { DEFAULT_RETRY_AFTER, disabledUntil, isRateLimited, parseRetryAfterHeader, updateRateLimits };
+//# sourceMappingURL=ratelimit.js.map