{"version":3,"sources":["../src/noop.ts","../src/ratelimit.ts","../src/duration.ts","../src/overrides.ts"],"sourcesContent":["import type { Ratelimiter } from \"./interface\";\nimport type { LimitOptions, RatelimitResponse } from \"./types\";\n\nexport class NoopRatelimit implements Ratelimiter {\n  public limit(_identifier: string, _opts?: LimitOptions): Promise<RatelimitResponse> {\n    return Promise.resolve({\n      limit: 0,\n      remaining: 0,\n      reset: 0,\n      success: true,\n    });\n  }\n}\n","import { Unkey } from \"@unkey/api\";\nimport { APIError } from \"@unkey/api/models/errors\";\nimport { type Duration, ms } from \"./duration\";\nimport type { Ratelimiter } from \"./interface\";\nimport type { Limit, LimitOptions, RatelimitResponse } from \"./types\";\n\nexport type RatelimitConfig = Limit & {\n  /**\n   * @default https://api.unkey.com\n   */\n  baseUrl?: string;\n\n  /**\n   * The unkey root key. You can create one at https://unkey.dev/app/settings/root-keys\n   *\n   * Make sure the root key has permissions to use ratelimiting.\n   */\n  rootKey: string;\n\n  /**\n   * Namespaces allow you to separate different areas of your app and have isolated limits.\n   *\n   * @example tRPC-routes\n   */\n  namespace: string;\n\n  /**\n   * Configure a timeout to prevent network issues from blocking your function for too long.\n   *\n   * Disable it by setting `timeout: false`\n   *\n   * @default\n   * ```ts\n   * {\n   *   // 5 seconds\n   *   ms: 5000,\n   *   fallback: { success: false, limit: 0, remaining: 0, reset: Date.now()}\n   * }\n   * ```\n   */\n  timeout?:\n    | {\n        /**\n         * Time in milliseconds until the response is returned\n         */\n        ms: number | Duration;\n\n        /**\n         * A custom response to return when the timeout is reached.\n         *\n         * The important bit is the `success` value, choose whether you want to let requests pass or not.\n         *\n         * @example With a static response\n         * ```ts\n         * {\n         *   // 5 seconds\n         *   ms: 5000\n         *   fallback: () => ({ success: true, limit: 0, remaining: 0, reset: 0 })\n         * }\n         * ```\n         * @example With a dynamic response\n         * ```ts\n         * {\n         *  // 5 seconds\n         *  ms: 5000\n         *  fallback: (identifier: string) => {\n         *  if (someCheck(identifier)) {\n         *    return { success: false, limit: 0, remaining: 0, reset: 0 }\n         *  }\n         *  return { success: true, limit: 0, remaining: 0, reset: 0 }\n         *  }\n         * }\n         * ```\n         */\n        fallback:\n          | RatelimitResponse\n          | ((identifier: string) => RatelimitResponse | Promise<RatelimitResponse>);\n      }\n    | false;\n\n  /**\n   * Configure what happens for unforeseen errors\n   *\n   * @example Letting requests pass\n   * ```ts\n   *   onError: () => ({ success: true, limit: 0, remaining: 0, reset: 0 })\n   * ```\n   *\n   * @example Rejecting the request\n   * ```ts\n   *   onError: () => ({ success: true, limit: 0, remaining: 0, reset: 0 })\n   * ```\n   *\n   * @example Dynamic response\n   * ```ts\n   *   onError: (error, identifier) => {\n   *     if (someCheck(error, identifier)) {\n   *       return { success: false, limit: 0, remaining: 0, reset: 0 }\n   *     }\n   *     return { success: true, limit: 0, remaining: 0, reset: 0 }\n   *   }\n   * ```\n   */\n  onError?: (err: Error, identifier: string) => RatelimitResponse | Promise<RatelimitResponse>;\n\n  /**\n   * Do not wait for a response from the origin. Faster but less accurate.\n   */\n  async?: boolean;\n\n  /**\n   *\n   * By default telemetry data is enabled, and sends:\n   * runtime (Node.js / Edge)\n   * platform (Node.js / Vercel / AWS)\n   * SDK version\n   */\n  disableTelemetry?: boolean;\n};\n\nexport class Ratelimit implements Ratelimiter {\n  private readonly config: RatelimitConfig;\n  private readonly unkey: Unkey;\n\n  constructor(config: RatelimitConfig) {\n    this.config = config;\n    this.unkey = new Unkey({\n      serverURL: config.baseUrl,\n      rootKey: config.rootKey,\n    });\n  }\n\n  /**\n   * Limit a specific identifier, you can override a lot of things about this specific request using\n   * the 2nd argument.\n   *\n   * @example\n   * ```ts\n   * const identifier = getIpAddress() // or userId or anything else\n   * const res = await unkey.limit(identifier)\n   *\n   * if (!res.success){\n   *   // reject request\n   * }\n   * // handle request\n   * ```\n   */\n  public async limit(identifier: string, opts?: LimitOptions): Promise<RatelimitResponse> {\n    try {\n      return this._limit(identifier, opts);\n    } catch (e) {\n      if (!this.config.onError) {\n        throw e;\n      }\n      const err = e instanceof Error ? e : new Error(String(e));\n\n      return await this.config.onError(err, identifier);\n    }\n  }\n  private async _limit(identifier: string, opts?: LimitOptions): Promise<RatelimitResponse> {\n    const timeout =\n      this.config.timeout === false\n        ? null\n        : (this.config.timeout ?? {\n            ms: 5000,\n            fallback: () => ({ success: false, limit: 0, remaining: 0, reset: Date.now() }),\n          });\n\n    let timeoutId: any = null;\n    try {\n      const ps: Promise<RatelimitResponse>[] = [\n        this.unkey.ratelimit\n          .limit({\n            namespace: this.config.namespace,\n            identifier,\n            limit: opts?.limit?.limit ?? this.config.limit,\n            duration: ms(opts?.limit?.duration ?? this.config.duration),\n            cost: opts?.cost,\n          })\n          .then(async (res) => {\n            return res.data;\n          })\n          .catch((err) => {\n            if (err instanceof APIError) {\n              throw new Error(\n                `Ratelimit failed: [${err.statusCode} - ${err.message}]: ${err.body}`,\n              );\n            }\n\n            throw new Error(`Ratelimit failed: ${err}`);\n          }),\n      ];\n      if (timeout) {\n        ps.push(\n          new Promise((resolve) => {\n            timeoutId = setTimeout(async () => {\n              const resolvedValue =\n                typeof timeout.fallback === \"function\"\n                  ? await timeout.fallback(identifier)\n                  : timeout.fallback;\n              resolve(resolvedValue);\n            }, ms(timeout.ms));\n          }),\n        );\n      }\n\n      return await Promise.race(ps);\n    } finally {\n      if (timeoutId) {\n        clearTimeout(timeoutId);\n      }\n    }\n  }\n}\n","type Unit = \"ms\" | \"s\" | \"m\" | \"h\" | \"d\";\n\nexport type Duration = `${number} ${Unit}` | `${number}${Unit}`;\n\n/**\n * Convert a human readable duration to milliseconds\n */\nexport function ms(d: Duration | number): number {\n  if (typeof d === \"number\") {\n    return d;\n  }\n  const match = d.match(/^(\\d+)\\s?(ms|s|m|h|d)$/);\n  if (!match) {\n    throw new Error(`Unable to parse window size: ${d}`);\n  }\n  const time = Number.parseInt(match[1]);\n  const unit = match[2] as Unit;\n\n  switch (unit) {\n    case \"ms\":\n      return time;\n    case \"s\":\n      return time * 1000;\n    case \"m\":\n      return time * 1000 * 60;\n    case \"h\":\n      return time * 1000 * 60 * 60;\n    case \"d\":\n      return time * 1000 * 60 * 60 * 24;\n\n    default:\n      throw new Error(`Unable to parse window size: ${d}`);\n  }\n}\n","import { Unkey } from \"@unkey/api\";\n\nexport type OverrideConfig = {\n  /**\n   * @default https://api.unkey.com\n   */\n  baseUrl?: string;\n\n  /**\n   * The unkey root key. You can create one at https://app.unkey.com/settings/root-keys\n   *\n   * Make sure the root key has permissions to use overrides.\n   */\n  rootKey: string;\n};\n\nexport class Overrides {\n  private readonly unkey: Unkey;\n\n  constructor(config: OverrideConfig) {\n    this.unkey = new Unkey({\n      serverURL: config.baseUrl,\n      rootKey: config.rootKey,\n    });\n  }\n\n  public get getOverride() {\n    return this.unkey.ratelimit.getOverride;\n  }\n  public get setOverride() {\n    return this.unkey.ratelimit.setOverride;\n  }\n  public get deleteOverride() {\n    return this.unkey.ratelimit.deleteOverride;\n  }\n  public get listOverrides() {\n    return this.unkey.ratelimit.listOverrides;\n  }\n}\n"],"mappings":"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","names":["Unkey"]}