### Install Borrow Node.js Package with bun Source: https://borrow.dev/docs/limiter/quick-start Installs the Borrow Node.js package using the bun package manager. Ensure you have Node.js and bun installed. ```bash bun add @borrowdev/node ``` -------------------------------- ### Install Borrow Node.js Package with npm Source: https://borrow.dev/docs/limiter/quick-start Installs the Borrow Node.js package using the npm package manager. Ensure you have Node.js and npm installed. ```bash npm install @borrowdev/node ``` -------------------------------- ### Install Borrow Node.js Package with yarn Source: https://borrow.dev/docs/limiter/quick-start Installs the Borrow Node.js package using the yarn package manager. Ensure you have Node.js and yarn installed. ```bash yarn add @borrowdev/node ``` -------------------------------- ### Install Borrow Node.js Package with pnpm Source: https://borrow.dev/docs/limiter/quick-start Installs the Borrow Node.js package using the pnpm package manager. Ensure you have Node.js and pnpm installed. ```bash pnpm add @borrowdev/node ``` -------------------------------- ### Control Borrow Limiter with cURL Source: https://borrow.dev/docs/limiter/quick-start These cURL commands illustrate how to interact with the Borrow Limiter API to start and end borrow operations. They include setting the necessary headers and payload for the API requests. ```curl # Start the borrow curl https://api.borrow.dev/v1/limiter \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-borrow-api-key: YOUR_API_KEY' \ --data '{ "userId": "current-user-id", "key": "my-limiter-id", "limiters": [ { "borrowAction": "start", "type": "borrow", "timeout": 10 } ] }' # End the borrow when finished curl https://api.borrow.dev/v1/limiter \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-borrow-api-key: YOUR_API_KEY' \ --data '{ "userId": "current-user-id", "key": "my-limiter-id", "limiters": [ { "type": "borrow", "borrowAction": "end", "timeout": 10 } ] }' ``` -------------------------------- ### Implement Fixed Window Rate Limiting in TypeScript Source: https://borrow.dev/docs/limiter/quick-start Applies a fixed window rate limiting algorithm to an endpoint, allowing 10 requests per minute. Requires the @borrowdev/node package. ```typescript import { borrow } from "@borrowdev/node"; const { success, timeLeft } = await borrow.limiter("my-limiter-id", "current-user-id", { limiters: [{ maxRequests: 10, interval: "minute", type: "fixed", }] }); if (!success) { return { message: "Rate limit exceeded." + timeLeft !== null ? ` You can try again in ${timeLeft} seconds.` : "" }; } // ... Your expensive business logic ``` -------------------------------- ### Limiter API Endpoint Source: https://borrow.dev/docs/limiter/quick-start This endpoint allows you to manage borrowing limits. You can initiate a 'start' action to begin a borrow and an 'end' action to conclude it. The endpoint supports rate limiting with configurable timeouts. ```APIDOC ## POST /v1/limiter ### Description Manages borrowing limits by allowing 'start' and 'end' actions for borrows with configurable timeouts and rate limiting. ### Method POST ### Endpoint /v1/limiter ### Parameters #### Query Parameters None #### Request Body - **userId** (string) - Required - The ID of the user performing the borrow action. - **key** (string) - Required - A unique identifier for the limiter. - **limiters** (array) - Required - An array of limiter configurations. - **type** (string) - Required - The type of limiter, e.g., 'borrow'. - **borrowAction** (string) - Required - The action to perform, either 'start' or 'end'. - **timeout** (number) - Required - The timeout duration in seconds for the borrow action. ### Request Example ```json { "userId": "current-user-id", "key": "my-limiter-id", "limiters": [ { "borrowAction": "start", "type": "borrow", "timeout": 10 } ] } ``` ### Response #### Success Response (200) - **success** (boolean) - Indicates if the operation was successful. - **timeLeft** (number | null) - The time remaining in seconds until the limit can be retried, if applicable. #### Response Example ```json { "success": true, "timeLeft": null } ``` #### Error Response (429) - **success** (boolean) - False, indicating rate limit exceeded. - **timeLeft** (number) - The time in seconds until the limit can be retried. #### Error Response Example ```json { "success": false, "timeLeft": 60 } ``` ``` -------------------------------- ### Implement Sliding Window Rate Limiting in TypeScript Source: https://borrow.dev/docs/limiter/quick-start Applies a sliding window rate limiting algorithm to an endpoint, allowing 10 requests per minute. Requires the @borrowdev/node package. ```typescript import { borrow } from "@borrowdev/node"; const { success, timeLeft } = await borrow.limiter("my-limiter-id", "current-user-id", { limiters: [{ maxRequests: 10, interval: "minute", type: "sliding", }] }); if (!success) { return { message: "Rate limit exceeded." + timeLeft !== null ? ` You can try again in ${timeLeft} seconds.` : "" }; } // ... Your expensive business logic ``` -------------------------------- ### Implement Custom Storage Adapter in JavaScript Source: https://borrow.dev/docs/limiter/self-hosting Provides an example of creating a custom storage adapter by extending the StorageAdapter class in JavaScript. It outlines the structure for overriding methods such as get, set, and relative, including an optional getStorageKey method. This requires the '@borrowdev/node/limiter/host' module. ```javascript import { StorageAdapter } from "@borrowdev/node/limiter/host"; class MyCustomAdapter extends StorageAdapter { constructor(db) { super(); this.db = db; } get(key) { // Implement your logic to get a value using the given input. Must not throw. } async set(key, value) { // Implement your logic to set a value using the given inputs. May throw. } async relative(key, field, amount) { // Implement your logic to increment/decrement an integer using the given inputs. May throw. } // (optional) getStorageKey(params) { // Implement your logic to generate a storage key using the given parameters. May throw. } } ``` -------------------------------- ### Install Limiter Dependencies Source: https://borrow.dev/docs/limiter/self-hosting Installs the necessary @borrowdev/node and @upstash/redis packages for the Cloudflare Worker environment. These are essential for the Limiter functionality and Redis integration. ```bash npm install @borrowdev/node @upstash/redis ``` -------------------------------- ### Send Fixed Window Rate Limiting Request via curl Source: https://borrow.dev/docs/limiter/quick-start Sends a POST request to the Borrow API to apply fixed window rate limiting. Configures 10 requests per minute for a given user ID and key. ```bash curl https://api.borrow.dev/v1/limiter \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "userId": "current-user-id", "key": "login", "limiters": [ { "type": "fixed", "maxRequests": 10, "interval": "minute" } ] }' ``` -------------------------------- ### Implement Borrow Limiter in TypeScript Source: https://borrow.dev/docs/limiter/quick-start This snippet shows how to use the @borrowdev/node library to start and end a borrow operation. It checks for rate limit success and handles the response, including retry information if available. ```typescript import { borrow } from "@borrowdev/node"; const { success, timeLeft } = await borrow.limiter("my-limiter-id", "current-user-id", { limiters: [{ borrowAction: "start", type: "borrow", timeout: 10, }] }); if (!success) { return { message: "Rate limit exceeded." + timeLeft !== null ? ` You can try again in ${timeLeft} seconds.` : "" }; } // ... Your expensive business logic const { success: endSuccess } = await borrow.limiter("my-limiter-id", "current-user-id", { limiters: [{ borrowAction: "end", type: "borrow", timeout: 10, }] }); if (!endSuccess) { return { message: "Failed to end borrow." }; } ``` -------------------------------- ### Send Token Bucket Rate Limiting Request via curl Source: https://borrow.dev/docs/limiter/quick-start Sends a POST request to the Borrow API to apply token bucket rate limiting. Configures token replenishment and limits for a given user ID and key. ```bash curl https://api.borrow.dev/v1/limiter \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-borrow-api-key: YOUR_API_KEY' \ --data '{ "userId": "current-user-id", "key": "my-limiter-id", "limiters": [ { "maxTokens": 20, "tokensCost": 5, "tokensPerReplenish": 10, "interval": "minute", "type": "token" } ] }' ``` -------------------------------- ### Send Sliding Window Rate Limiting Request via curl Source: https://borrow.dev/docs/limiter/quick-start Sends a POST request to the Borrow API to apply sliding window rate limiting. Configures 10 requests per minute for a given user ID and key. ```bash curl https://api.borrow.dev/v1/limiter \ --request POST \ --header 'Content-Type: application/json' \ --data '{ "userId": "current-user-id", "key": "login", "limiters": [ { "type": "sliding", "maxRequests": 10, "interval": "minute" } ] }' ``` -------------------------------- ### Implement Token Bucket Rate Limiting in TypeScript Source: https://borrow.dev/docs/limiter/quick-start Applies a token bucket rate limiting algorithm to an endpoint, allowing 10 tokens replenished per minute with a maximum of 20 tokens and a cost of 5 tokens per request. Requires the @borrowdev/node package. ```typescript import { borrow } from "@borrowdev/node"; const { success, timeLeft } = await borrow.limiter("my-limiter-id", "current-user-id", { limiters: [{ maxTokens: 20, tokensCost: 5, tokensPerReplenish: 10, interval: "minute", type: "token", }] }); if (!success) { return { message: "Rate limit exceeded." + timeLeft !== null ? ` You can try again in ${timeLeft} seconds.` : "" }; } // ... Your expensive business logic ``` -------------------------------- ### Implement Custom Storage Adapter in TypeScript Source: https://borrow.dev/docs/limiter/self-hosting Demonstrates how to create a custom storage adapter by extending the StorageAdapter class in TypeScript. It shows the structure for overriding methods like get, set, and relative, along with an optional getStorageKey method. Requires the '@borrowdev/node/limiter/host' module. ```typescript import { StorageAdapter } from "@borrowdev/node/limiter/host"; class MyCustomAdapter extends StorageAdapter { private db: DbType; constructor(db: DbType) { super(); this.db = db; } override get = (key: string) => { // Implement your logic to get a value using the given input. Must not throw. } override set = async (key: string, value: any) => { // Implement your logic to set a value using the given inputs. May throw. } override relative = async (key: string, field: string, amount: number) => { // Implement your logic to increment/decrement an integer using the given inputs. May throw. } // (optional) override getStorageKey = ( params: { limiterType: LimiterType; userId: string | null; key: string | null; } ) => { // Implement your logic to generate a storage key using the given parameters. May throw. } } ``` -------------------------------- ### Call Limiter API with TypeScript Client Source: https://borrow.dev/docs/limiter/self-hosting Demonstrates how to call the Limiter API from a TypeScript application using the `@borrowdev/node` client library. It shows setting up limiter configurations, options like `failBehavior`, API key, and endpoint, and checking the success of the rate limit operation. ```typescript import { borrow } from "@borrowdev/node"; const { success, timeLeft } = await borrow.limiter("my-limiter-id", "current-user-id", { limiters: [{ maxTokens: 20, tokensCost: 5, tokensPerReplenish: 10, interval: "minute", type: "token", }], options: { // Use for testing or if you want to fail closed. failBehavior: "fail", apiKey: "random-secure-string", endpoint: { baseUrl: "http://localhost:8787", } } }); if (!success) { return { message: "Rate limit exceeded." + (timeLeft !== null ? ` You can try again in ${timeLeft} seconds.` : "") }; } // ... Your expensive business logic ``` -------------------------------- ### Configure Local Development Secrets (`.dev.vars`) Source: https://borrow.dev/docs/limiter/self-hosting Sets up environment variables for local development within a `.dev.vars` file. This includes secrets for Limiter invocation and Upstash Redis connection details. **Crucially, this file should not be committed to version control.** ```env BORROW_LIMITER_INVOKE_SECRET="random-secure-string" UPSTASH_REDIS_REST_TOKEN="your-upstash-redis-token" UPSTASH_REDIS_REST_URL="https://your-upstash-redis-url" ``` -------------------------------- ### Cloudflare Worker Implementation (`src/index.ts`) Source: https://borrow.dev/docs/limiter/self-hosting The main Cloudflare Worker file (`src/index.ts`) that handles incoming requests. It initializes a Redis client, creates a storage adapter, processes the request JSON, and calls the Limiter API with authentication and background execution support. It returns the Limiter results as JSON. ```typescript import { limiter, UpstashRedisAdapter } from "@borrowdev/node/limiter/host"; import { Redis } from "@upstash/redis/cloudflare"; export default { async fetch(request, env, ctx) { const redis = Redis.fromEnv(env); const adapters = { storage: new UpstashRedisAdapter(redis) }; const req = await request.json(); // Execute the limiter function, passing: // - invokeSecret from env for authentication // - the Redis-backed storage adapter // - ctx.waitUntil for background updates (or false if you want to execute synchronously) const response = await limiter({ env, req: { ...req || {}, invokeSecret: request.headers.get("X-Borrow-Api-Key") || "", } as any, adapters, backgroundExecute: ctx.waitUntil.bind(ctx), hooks: { beforeResponse: async (r) => console.log("Limiter result: ", r), }, }); if (response.error) { console.error("Limiter error: ", response.message); } // Return JSON result return new Response( JSON.stringify({ result: response.result, timeLeft: response.timeLeft, tokensLeft: response.tokensLeft, }), { status: response.status, headers: { "Content-Type": "application/json" }, }, ); }, } satisfies ExportedHandler; ``` -------------------------------- ### Configure Cloudflare Worker (`wrangler.jsonc`) Source: https://borrow.dev/docs/limiter/self-hosting Configures the Cloudflare Worker using `wrangler.jsonc`. It specifies the schema, worker name, compatibility date, the main entry point (`src/index.ts`), and environment variables like UPSTASH_REDIS_REST_URL for Redis connection. ```json { "$schema": "node_modules/wrangler/config-schema.json", "name": "borrow-limiter", "compatibility_date": "2025-04-25", "main": "src/index.ts", "vars": { // Use this if you're using Upstash Redis. "UPSTASH_REDIS_REST_URL": "https://your-upstash-redis-url" } } ``` -------------------------------- ### Call Limiter API with cURL Source: https://borrow.dev/docs/limiter/self-hosting Provides a cURL command to interact with the Limiter API. It specifies the endpoint, HTTP method (POST), content type, the authentication header (`x-borrow-api-key`), and the JSON payload containing the limiter configuration and user/key details. ```bash curl http://localhost:8787 \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-borrow-api-key: YOUR_INVOKE_SECRET' \ --data '{ "action": "check", "userId": "current-user-id", "key": "my-limiter-id", "limiters": [ { "maxTokens": 20, "tokensCost": 5, "tokensPerReplenish": 10, "interval": "minute", "type": "token" } ] }' ``` -------------------------------- ### Rate Limit Requests with Supabase Source: https://borrow.dev/docs/limiter/integrations/supabase This code demonstrates how to use the Limiter's borrow.limiter function with a Supabase request object. It configures rate limiting rules, such as interval and maximum requests, and returns the success status and time left before the next request can be made. This is useful for protecting API endpoints. ```typescript import { borrow } from "@borrowdev/node"; // ... Your Supabase Edge Function handler const { success, timeLeft } = await borrow.limiter(req, { limiters: [{ interval: 20, maxRequests: 10, type: "fixed", }] }); // ... Your expensive business logic ``` ```javascript import { borrow } from "@borrowdev/node"; // ... Your Supabase Edge Function handler const { success, timeLeft } = await borrow.limiter(req, { limiters: [{ interval: 20, maxRequests: 10, type: "fixed", }] }); // ... Your expensive business logic ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.