UNPKG

@unkey/ratelimit

Version:

<div align="center"> <h1 align="center">@unkey/ratelimit</h1> <h5>@unkey/ratelimit is a library for fast global ratelimiting in serverless functions.</h5> </div>

201 lines (195 loc) 5.5 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { NoopRatelimit: () => NoopRatelimit, Overrides: () => Overrides, Ratelimit: () => Ratelimit }); module.exports = __toCommonJS(index_exports); // src/noop.ts var NoopRatelimit = class { limit(_identifier, _opts) { return Promise.resolve({ limit: 0, remaining: 0, reset: 0, success: true }); } }; // src/ratelimit.ts var import_api = require("@unkey/api"); var import_unkeyerror = require("@unkey/api/models/errors/unkeyerror"); // src/duration.ts function ms(d) { if (typeof d === "number") { return d; } const match = d.match(/^(\d+)\s?(ms|s|m|h|d)$/); if (!match) { throw new Error(`Unable to parse window size: ${d}`); } const time = Number.parseInt(match[1]); const unit = match[2]; switch (unit) { case "ms": return time; case "s": return time * 1e3; case "m": return time * 1e3 * 60; case "h": return time * 1e3 * 60 * 60; case "d": return time * 1e3 * 60 * 60 * 24; default: throw new Error(`Unable to parse window size: ${d}`); } } // src/ratelimit.ts var Ratelimit = class { config; unkey; cache; constructor(config) { this.config = config; this.unkey = new import_api.Unkey({ serverURL: config.baseUrl, rootKey: config.rootKey }); this.cache = config.cache ?? /* @__PURE__ */ new Map(); } /** * Limit a specific identifier, you can override a lot of things about this specific request using * the 2nd argument. * * @example * ```ts * const identifier = getIpAddress() // or userId or anything else * const res = await unkey.limit(identifier) * * if (!res.success){ * // reject request * } * // handle request * ``` */ async limit(identifier, opts) { try { return await this._limit( identifier, opts?.limit?.limit ?? this.config.limit, ms(opts?.limit?.duration ?? this.config.duration), opts?.cost ?? 1 ); } catch (e) { if (typeof this.config.onError !== "function") { throw e; } const err = e instanceof import_unkeyerror.UnkeyError ? new Error(e.message) : e instanceof Error ? e : new Error(String(e)); return await this.config.onError(err, identifier); } } // _limit just handles the racing and caching. It must not handle errors, those are handled by limit async _limit(identifier, limit, duration, cost) { const cacheKey = `${this.config.namespace}:${identifier}:${limit}:${duration}`; const naughty = this.cache.get(cacheKey); if (naughty) { if (naughty.reset > Date.now()) { return naughty; } else { this.cache.delete(cacheKey); } } const timeout = this.config.timeout === false ? null : this.config.timeout ?? { ms: 5e3, fallback: () => ({ success: false, limit: 0, remaining: 0, reset: Date.now() }) }; let timeoutId = null; try { const ps = [ this.unkey.ratelimit.limit({ namespace: this.config.namespace, identifier, limit, duration, cost }).then(async (res2) => { return res2.data; }) ]; if (timeout) { ps.push( new Promise((resolve) => { timeoutId = setTimeout(async () => { const resolvedValue = typeof timeout.fallback === "function" ? await timeout.fallback(identifier) : timeout.fallback; resolve(resolvedValue); }, ms(timeout.ms)); }) ); } const res = await Promise.race(ps); if (!res.success) { this.cache.set(cacheKey, res); } return res; } finally { if (timeoutId) { clearTimeout(timeoutId); } } } }; // src/overrides.ts var import_api2 = require("@unkey/api"); var Overrides = class { unkey; constructor(config) { this.unkey = new import_api2.Unkey({ serverURL: config.baseUrl, rootKey: config.rootKey }); } getOverride(request, options) { return this.unkey.ratelimit.getOverride(request, options); } setOverride(request, options) { return this.unkey.ratelimit.setOverride(request, options); } deleteOverride(request, options) { return this.unkey.ratelimit.deleteOverride(request, options); } listOverrides(request, options) { return this.unkey.ratelimit.listOverrides(request, options); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { NoopRatelimit, Overrides, Ratelimit }); //# sourceMappingURL=index.js.map