### Install @fastify/throttle Source: https://github.com/fastify/fastify-throttle/blob/main/README.md Use npm to install the @fastify/throttle package. ```sh npm i @fastify/throttle ``` -------------------------------- ### Global Throttling Configuration Example Source: https://github.com/fastify/fastify-throttle/blob/main/README.md Configure throttling globally when registering the plugin. This example sets bytesPerSecond to 1KB/s and serves a read stream. ```javascript const fastify = require('fastify')() await fastify.register(import('@fastify/throttle'), { bytesPerSecond: 1024 // 1KB/s }) fastify.get('/', (req, reply) => { reply.send(createReadStream(resolve(__dirname, __filename))) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Handle Initial Setup Errors Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/implementation-details.md Catches errors during the initial setup of the throttle stream. Emits an error event if the rate function fails on initial call. ```javascript try { this.startTime = Date.now() this._allowedBytes = this.bytesPerSecondFn(0, 0) this._interval = setInterval(...) } catch (err) { this.emit('error', err) } ``` -------------------------------- ### Complete Per-Route Configuration Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Demonstrates setting all configurable throttle options (`bytesPerSecond`, `streamPayloads`, `bufferPayloads`, `stringPayloads`) for a specific route. ```javascript fastify.get('/custom', { config: { throttle: { bytesPerSecond: 500000, streamPayloads: true, bufferPayloads: true, stringPayloads: false } } }, handler) ``` -------------------------------- ### Minimal Fastify Throttle Setup Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Register the plugin with a basic bytes-per-second limit. Ensure Fastify and the plugin are imported. ```javascript import Fastify from 'fastify' import fastifyThrottle from '@fastify/throttle' const fastify = Fastify() await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024 // 1 MB/s }) fastify.get('/', (req, reply) => { reply.send({ message: 'Hello' }) }) await fastify.listen({ port: 3000 }) ``` -------------------------------- ### Actual vs Requested Rate Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/implementation-details.md Illustrates how actual throughput can deviate from the requested rate due to interval granularity, chunk size, and system scheduling. The first example shows correct byte distribution, while the second shows late data release. ```javascript bytesPerSecond: 1024 // 1 KB/s // Chunk 1: 512 bytes (first second, all allowed) // Chunk 2: 512 bytes (first second, all allowed) // Total in first second: 1024 bytes (correct) // vs // Chunk 1: 2048 bytes // First 1024 bytes released in first second // Next 1024 bytes released in second second // Third 512 bytes released in second second (late) ``` -------------------------------- ### Dynamic Rate Calculation Examples Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/types.md Illustrates various strategies for dynamically calculating throttle rates using `BytesPerSecondFn`. Examples include constant, ramping, delayed, and adaptive rates. ```typescript // Constant rate of 100 KB/s const constantRate: BytesPerSecondFn = (elapsed, bytes) => 100000 // Ramp up rate over 10 seconds const rampingRate: BytesPerSecondFn = (elapsed, bytes) => { const rate = Math.min(1000000, 100000 + (90000 * elapsed / 10)) return Math.floor(rate) } // Delay start for 3 seconds const delayedRate: BytesPerSecondFn = (elapsed, bytes) => { return elapsed < 3 ? 0 : 50000 } // Unlimited after first 1MB const adaptiveRate: BytesPerSecondFn = (elapsed, bytes) => { return bytes < 1024 * 1024 ? 100000 : Infinity } ``` -------------------------------- ### Configuration Merge Behavior Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Illustrates how per-route configurations merge with global settings, with per-route values taking precedence. This example shows overriding `bytesPerSecond` on one route and `bufferPayloads` on another, while inheriting other settings from the global configuration. ```javascript // Global configuration await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024, streamPayloads: true, bufferPayloads: false, stringPayloads: false }) fastify.get('/route1', { config: { throttle: { bytesPerSecond: 500000 // overrides global // streamPayloads: true (inherited from global) // bufferPayloads: false (inherited from global) // stringPayloads: false (inherited from global) } } }, handler) fastify.get('/route2', { config: { throttle: { bufferPayloads: true // overrides global for buffers only // bytesPerSecond: 1024 * 1024 (inherited from global) // streamPayloads: true (inherited from global) // stringPayloads: false (inherited from global) } } }, handler) ``` -------------------------------- ### Per-Route Throttling Configuration Example Source: https://github.com/fastify/fastify-throttle/blob/main/README.md Configure throttling for a specific route using the 'config.throttle' option. This example sets bytesPerSecond to 1000 for the root route. ```javascript 'use strict' const fastify = require('fastify')() await fastify.register(import('@fastify/throttle')) fastify.get('/', { config: { throttle: { bytesPerSecond: 1000 } } }, (req, reply) => { reply.send(createReadStream(resolve(__dirname, __filename))) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Custom Throttle Rate Function Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Example of a custom rate function that allows 0 bytes for the first 2 seconds, then switches to 10KB/s. This demonstrates dynamic rate control. ```javascript // Example: 0 bytes for first 2 seconds, then 10KB/s const rateFn = (elapsedTime, bytesSent) => { return elapsedTime < 2 ? 0 : 10000 } const stream = new ThrottleStream({ bytesPerSecond: rateFn }) ``` -------------------------------- ### ThrottleStream Constructor Examples Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/throttle-stream.md Demonstrates creating ThrottleStream instances with a fixed rate, without the 'new' keyword, with a dynamic rate function, and using the default rate. ```javascript const { ThrottleStream } = require('@fastify/throttle') // Fixed rate const throttle1 = new ThrottleStream({ bytesPerSecond: 1024 * 1024 }) // Without new const throttle2 = ThrottleStream({ bytesPerSecond: 100000 }) // With function const throttle3 = new ThrottleStream({ bytesPerSecond: (elapsedTime, bytes) => { return elapsedTime < 5 ? 0 : 1024 * 1024 } }) // Default rate if no options const throttle4 = new ThrottleStream() ``` -------------------------------- ### Usage Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Demonstrates how to integrate ThrottleStream into a Node.js stream pipeline for file transfer throttling. ```APIDOC ### Usage Example ```javascript import { ThrottleStream } from '@fastify/throttle' import { createReadStream } from 'fs' import { pipeline } from 'stream' // Throttle file to 1MB/s const fileStream = createReadStream('large-file.bin') const throttle = new ThrottleStream({ bytesPerSecond: 1024 * 1024 }) pipeline(fileStream, throttle, process.stdout, (err) => { if (err) console.error('Pipeline failed:', err) }) // Dynamic throttling based on elapsed time const dynamicThrottle = new ThrottleStream({ bytesPerSecond: (elapsedTime, bytesSent) => { // Ramp up from 100KB/s to 1MB/s over 10 seconds const rate = Math.min(1024 * 1024, 100000 + (90000 * elapsedTime / 10)) return Math.floor(rate) } }) ``` ``` -------------------------------- ### Per-Route Throttle Configuration Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/types.md Demonstrates how to configure throttle options for a specific route using the extended FastifyContextConfig. These options override global plugin settings. ```typescript fastify.get('/endpoint', { config: { throttle: { bytesPerSecond: 100000, streamPayloads: true } } }, handler) ``` -------------------------------- ### Throttle Stream Initialization (_init) Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/throttle-stream.md Initializes the throttling system when the first data chunk arrives. It sets the start time, calculates initial allowed bytes, and starts a 1-second interval for updates. ```javascript _init() { this.startTime = Date.now() this._allowedBytes = this.bytesPerSecondFn(0, 0) this._interval = setInterval(() => intervalHandler(this), 1000) } ``` -------------------------------- ### ThrottleStream startTime Check Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/throttle-stream.md Illustrates how to check if the ThrottleStream has started processing data by examining its startTime property. ```javascript if (throttle.startTime === null) { // stream hasn't processed any data yet } ``` -------------------------------- ### Register Plugin with Global Options Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Register the plugin with global options that apply to all routes unless overridden. This example sets a global rate limit and configures payload throttling. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024, // 1 MB/s streamPayloads: true, // throttle streams bufferPayloads: false, // don't throttle buffers stringPayloads: false // don't throttle strings }) ``` -------------------------------- ### Throttle Stream Rate Function Examples Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/throttle-stream.md Examples of rate functions for the ThrottleStream. These functions determine the bytes per second allowed based on elapsed time and bytes sent. ```javascript // Constant (elapsed, sent) => 100000 ``` ```javascript // Time-based (elapsed, sent) => { if (elapsed < 5) return 0 return 1000000 } ``` ```javascript // Bytes-based (elapsed, sent) => { if (sent > 10000000) return 100000 return 1000000 } ``` ```javascript // Dynamic ramping (elapsed, sent) => { const startRate = 100000 const endRate = 10000000 const rampTime = 30 const progress = Math.min(elapsed / rampTime, 1) return Math.floor(startRate + (endRate - startRate) * progress) } ``` -------------------------------- ### Bytes-Based: Slow Start Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Implement a slow start mechanism where the rate limit increases after a certain amount of data has been sent. This is useful for gradually increasing bandwidth for clients. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { return (elapsedTime, bytesSent) => { // Slow start, full speed after 1 MB if (bytesSent < 1024 * 1024) { return 100 * 1024 // 100 KB/s } else { return 10 * 1024 * 1024 // 10 MB/s } } } }) ``` -------------------------------- ### Initial Allowed Bytes Calculation Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/throttle-stream.md The `_init()` method calculates the initial `_allowedBytes` before starting the interval timer. If this initial calculation returns `0`, no data will flow until the first interval tick. ```javascript _init() { this._allowedBytes = this.bytesPerSecondFn(0, 0) // Initial load // If this returns 0, no data flows until first interval tick (up to 1s) } ``` -------------------------------- ### Initial Throttle Load Calculation Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/implementation-details.md Initializes the throttle stream by setting the start time and calculating the initial allowed bytes. This allows some data to flow immediately. ```javascript _init() { this.startTime = Date.now() this._allowedBytes = this.bytesPerSecondFn(0, 0) // Initial call this._interval = setInterval(() => intervalHandler(this), 1000) } ``` -------------------------------- ### Asynchronous BytesPerSecondGenerator Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Shows how to register fastify-throttle with an asynchronous function that fetches user tier information from a database to determine the rate limit. The function returns a Promise that resolves to the rate function. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: async (request) => { const userId = request.user?.id const tierInfo = await database.getUserTier(userId) return () => tierInfo.bytesPerSecond } }) ``` -------------------------------- ### Delay Before Start Configuration Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Implement a delay before any data transfer begins. This can be useful for scenarios where you want to ensure certain conditions are met or to simply pause data flow for a set duration. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { return (elapsedTime, bytes) => { // No data for first 5 seconds if (elapsedTime < 5) return 0 return 1024 * 1024 // then 1 MB/s } } }) ``` -------------------------------- ### Dynamic Throttling Based on Elapsed Time Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Example of dynamic throttling where the rate increases over time, ramping up from 100KB/s to 1MB/s over 10 seconds. ```javascript // Dynamic throttling based on elapsed time const dynamicThrottle = new ThrottleStream({ bytesPerSecond: (elapsedTime, bytesSent) => { // Ramp up from 100KB/s to 1MB/s over 10 seconds const rate = Math.min(1024 * 1024, 100000 + (90000 * elapsedTime / 10)) return Math.floor(rate) } }) ``` -------------------------------- ### Configure Throttle Rate with Fixed Bytes Per Second (MB/s) Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Specify a fixed bytes-per-second limit for the throttle rate. This example shows setting the limit to 1 MB/s. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024 // 1 MB/s }) ``` -------------------------------- ### Global and Per-Route Throttling Configuration Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Example of setting global throttling options for the fastify-throttle plugin and overriding specific options for a particular route. Per-route configurations take precedence. ```javascript const globalOptions = { bytesPerSecond: 1024 * 1024, // 1 MB/s for all routes streamPayloads: true, bufferPayloads: false, stringPayloads: false } await fastify.register(fastifyThrottle, globalOptions) // Override on a specific route fastify.get('/slow-endpoint', { config: { throttle: { bytesPerSecond: 10000 // Only 10 KB/s for this route } } }, handler) ``` -------------------------------- ### Synchronous BytesPerSecondGenerator Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Demonstrates registering the fastify-throttle plugin with a synchronous function to generate bytes per second limits based on request headers. Ensure the function returns a rate function directly. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { const clientTier = request.headers['x-client-tier'] || 'standard' const rates = { premium: 10 * 1024 * 1024, // 10 MB/s standard: 1 * 1024 * 1024, // 1 MB/s free: 100 * 1024 // 100 KB/s } return () => rates[clientTier] } }) ``` -------------------------------- ### Configure Throttle Rate with Fixed Bytes Per Second (100 MB/s) Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Specify a fixed bytes-per-second limit for the throttle rate. This example shows setting the limit to 100 MB/s. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 100 * 1024 * 1024 // 100 MB/s }) ``` -------------------------------- ### Configure Throttle Rate with Fixed Bytes Per Second Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Specify a fixed bytes-per-second limit for the throttle rate. This example shows setting the limit to 16 KB/s. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 16384 // 16 KB/s }) ``` -------------------------------- ### Asynchronous BytesPerSecondGenerator Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/types.md Generates an asynchronous rate calculator by querying a database. Use this when the rate depends on external data, such as user tiers fetched from a database. ```typescript const asyncGenerator: BytesPerSecondGenerator = async (request) => { const userId = request.user?.id const userTier = await db.getUserTier(userId) return () => userTier.bytesPerSecond } ``` -------------------------------- ### Basic File Throttling Usage Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Example of throttling a file stream to a fixed rate of 1MB/s using ThrottleStream and Node.js stream pipeline. ```javascript import { ThrottleStream } from '@fastify/throttle' import { createReadStream } from 'fs' import { pipeline } from 'stream' // Throttle file to 1MB/s const fileStream = createReadStream('large-file.bin') const throttle = new ThrottleStream({ bytesPerSecond: 1024 * 1024 }) pipeline(fileStream, throttle, process.stdout, (err) => { if (err) console.error('Pipeline failed:', err) }) ``` -------------------------------- ### Synchronous BytesPerSecondGenerator Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/types.md Generates a synchronous rate calculator based on request headers. Use this when the rate can be determined directly from request information without external lookups. ```typescript const generator: BytesPerSecondGenerator = (request) => { const priority = request.headers['x-priority'] || 'normal' const rates = { high: 10 * 1024 * 1024, normal: 1 * 1024 * 1024, low: 100 * 1024 } return () => rates[priority] } ``` -------------------------------- ### Register Fastify Throttle with Dynamic Rates Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/throttle-stream.md Register the throttle plugin with custom bytes-per-second rates determined by client headers. This example demonstrates setting different limits for premium, standard, and free clients. ```javascript import fastifyThrottle from '@fastify/throttle' import { createReadStream } from 'fs' const fastify = require('fastify')() await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { const clientTier = request.headers['x-client-tier'] || 'free' const rates = { premium: 50 * 1024 * 1024, // 50 MB/s standard: 5 * 1024 * 1024, // 5 MB/s free: 500 * 1024 // 500 KB/s } return (elapsedTime, bytesSent) => { // Could implement further logic based on elapsed time return rates[clientTier] } }, streamPayloads: true }) fastify.get('/download/:file', async (request, reply) => { const filePath = `./files/${request.params.file}` reply.send(createReadStream(filePath)) // Automatically throttled by the stream }) await fastify.listen({ port: 3000 }) ``` -------------------------------- ### Configure Throttle Rate with Sync Function Returning Promise Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md When a synchronous function for `bytesPerSecond` returns a Promise, set the `async` option to `true`. This example demonstrates a synchronous function that resolves a Promise for the rate. ```javascript await fastify.register(fastifyThrottle, { async: true, bytesPerSecond: (request) => { // This is synchronous but returns a Promise return Promise.resolve((elapsedTime, bytes) => { return 1024 * 1024 }) } }) ``` -------------------------------- ### Time-Based BytesPerSecondGenerator Example Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/types.md Generates a rate calculator where the rate dynamically adjusts based on elapsed time and bytes transferred. This is useful for implementing ramp-up periods or time-sensitive throttling. ```typescript const timeBasedGenerator: BytesPerSecondGenerator = (request) => { const clientType = request.headers['x-client'] || 'web' return (elapsed, bytes) => { if (clientType === 'mobile') { return Math.min(500000, 100000 + (40000 * elapsed)) // ramp up for mobile } else { return 5000000 // full speed for desktop } } } ``` -------------------------------- ### Dynamic bytesPerSecond Function Example Source: https://github.com/fastify/fastify-throttle/blob/main/README.md Implement dynamic rate limiting by providing a factory function for bytesPerSecond. This function runs per request and returns a rate limiter function based on client ID. ```javascript const fastify = require('fastify')() await fastify.register(import('@fastify/throttle')) fastify.get('/', { config: { throttle: { bytesPerSecond: function bytesPerSecondfactory(request) { // this function runs for every request const client = request.headers['customer-id'] return function (elapsedTime, bytes) { return CONFIG[client] * 2 // return a number of xyz } } } } }, (req, reply) => { reply.send(createReadStream(resolve(__dirname, __filename))) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Register and Configure Fastify Throttle Source: https://github.com/fastify/fastify-throttle/blob/main/README.md Register the @fastify/throttle plugin with Fastify and configure options like bytesPerSecond, streamPayloads, bufferPayloads, and stringPayloads. This setup adds an 'onSend' hook to throttle response download speeds. ```javascript import Fastify from 'fastify' const fastify = Fastify() await fastify.register(import('@fastify/throttle'), { bytesPerSecond: 1024 * 1024, // 1MB/s streamPayloads: true, // throttle the payload if it is a stream bufferPayloads: true, // throttle the payload if it is a Buffer stringPayloads: true // throttle the payload if it is a string }) fastify.get('/', (request, reply) => { reply.send({ hello: 'world' }) }) fastify.listen({ port: 3000 }, err => { if (err) { throw err } console.log('Server listening at http://localhost:3000') }) ``` -------------------------------- ### Async bytesPerSecond Function Example Source: https://github.com/fastify/fastify-throttle/blob/main/README.md Use an async factory function for bytesPerSecond, returning a Promise that resolves to the rate limiting function. Set 'async: true' to ensure the Promise is awaited. ```javascript const fastify = require('fastify')() await fastify.register(import('@fastify/throttle')) fastify.get('/', { config: { throttle: { async: true, bytesPerSecond: function bytesPerSecondfactory(request) { // this function runs for every request const client = request.headers['customer-id'] return Promise.resolve(function (elapsedTime, bytes) { return CONFIG[client] * 2 // return a number of xyz }) } } } }, (req, reply) => { reply.send(createReadStream(resolve(__dirname, __filename))) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Measure Actual Throughput Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/implementation-details.md Implement a mechanism to measure the actual throughput of data transfer. This involves recording start times and total bytes transferred to calculate the real-world data rate. ```javascript let startTime = null let totalBytes = 0 fastify.get('/test', (request, reply) => { startTime = Date.now() totalBytes = 0 reply.send({ onResponse: () => { const elapsed = Date.now() - startTime const actual = (totalBytes * 1000) / elapsed console.log(`Actual throughput: ${actual} bytes/sec`) } }) }) ``` -------------------------------- ### Use Async Generator for Rate Limiting Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/implementation-details.md For dynamic rate limits based on external data, query the data once at the start and return a constant function. Avoid querying external data within the rate function itself, as this leads to repeated, inefficient calls. ```javascript // ✓ Good: Query once at start bytesPerSecondFn: async (request) => { const rate = await db.getUserRate(request.user.id) return () => rate // Constant function } ``` ```javascript // ✗ Poor: Query every interval bytesPerSecondFn: async (request) => { return async (elapsed, bytes) => { return await db.getUserRate(request.user.id) } } ``` -------------------------------- ### Override Global Throttle Settings Per Route Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Override global settings on specific routes using the `config.throttle` property. This example shows how to set a lower `bytesPerSecond` for a specific route and disable throttling entirely for another. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024 // 1 MB/s globally }) fastify.get('/slow', { config: { throttle: { bytesPerSecond: 100 * 1024 // 100 KB/s for this route } } }, handler) fastify.get('/unlimited', { config: { throttle: { bytesPerSecond: Infinity // no throttling for this route } } }, handler) ``` -------------------------------- ### Override Payload Type Settings Per Route Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Override specific payload type configurations like `bufferPayloads` for individual routes. This example enables buffer throttling for a single route while global settings remain unchanged. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024, streamPayloads: true, bufferPayloads: false, stringPayloads: false }) fastify.get('/buffer-throttled', { config: { throttle: { bufferPayloads: true // enable buffer throttling for this route only } } }, handler) ``` -------------------------------- ### ThrottleStream bytesPerSecondFn Usage Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/throttle-stream.md Shows how to call the bytesPerSecondFn to get the throttle rate based on elapsed time and bytes sent. ```javascript throttle.bytesPerSecondFn(elapsedTime, bytesSent) // => number ``` -------------------------------- ### Default stringPayloads Behavior Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md By default, string response payloads are not throttled. This example shows the default configuration where `stringPayloads` is set to `false`. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024, stringPayloads: false // strings bypass throttling }) fastify.get('/text', (request, reply) => { reply.send('Lorem ipsum dolor sit amet...') }) ``` -------------------------------- ### Gradual Ramp-Up Configuration Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Configure a gradual increase in bandwidth over a specified time. This can be used to avoid overwhelming resources or to provide a smoother user experience during initial data transfer. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { return (elapsedTime, bytes) => { // Start slow, ramp up to full speed over 30 seconds const fullSpeed = 5 * 1024 * 1024 const rampTime = 30 const elapsed = Math.min(elapsedTime, rampTime) return Math.floor((elapsed / rampTime) * fullSpeed) } } }) ``` -------------------------------- ### Synchronous Rate Function Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/implementation-details.md Define a synchronous function that returns the rate calculator. This function is called once per request and must not throw errors during setup. ```javascript bytesPerSecond: (request) => { return (elapsedTime, bytes) => 1024 * 1024 } // Detected as sync, called immediately: const rateFn = bytesPerSecond(request) // rateFn is stored in this.bytesPerSecondFn ``` -------------------------------- ### Async: Database Lookup Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Fetch rate limits dynamically from a database based on user ID. Ensure the database query is efficient and handles cases where user configuration might be missing. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: async (request) => { const userId = request.user?.id const userConfig = await database.query( 'SELECT rate_limit FROM users WHERE id = ?', [userId] ) return () => userConfig?.rate_limit || 1 * 1024 * 1024 } }) ``` -------------------------------- ### Fastify Throttle With All Options Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Configure all available options for the Fastify Throttle plugin, including stream, buffer, and string payload throttling. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024, streamPayloads: true, // Throttle streams (default) bufferPayloads: true, // Throttle buffers stringPayloads: true, // Throttle strings async: false // Rate function is not async }) ``` -------------------------------- ### Fastify Throttle Plugin Entry Point (index.js) Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/module-architecture.md The main plugin function for Fastify Throttle. It handles route registration, payload wrapping, and supports various configurations for bytes per second. ```javascript import fastifyPlugin from 'fastify-plugin'; import { isAsyncFunction } from './lib/is-async-function.js'; import { ThrottleStream } from './lib/throttle-stream.js'; const fastifyThrottle = async (fastify, options) => { const { bytesPerSecond, enable, ...restOptions } = options; if (enable === false) { return; } const bytesPerSecondFn = typeof bytesPerSecond === 'function' ? bytesPerSecond : () => bytesPerSecond; const isBytesPerSecondAsync = isAsyncFunction(bytesPerSecondFn); fastify.addHook('onRoute', (routeOptions, done) => { const routeThrottleConfig = routeOptions.config?.throttle; if (!routeThrottleConfig) { return done(); } const { bytesPerSecond: routeBytesPerSecond, enable: routeEnable } = routeThrottleConfig; if (routeEnable === false) { return done(); } const routeBytesPerSecondFn = typeof routeBytesPerSecond === 'function' ? routeBytesPerSecond : () => routeBytesPerSecond; const isRouteBytesPerSecondAsync = isAsyncFunction(routeBytesPerSecondFn); const onSendHook = async (request, reply, payload) => { if (payload === undefined || payload === null) { return payload; } const currentBytesPerSecond = isRouteBytesPerSecondAsync ? await routeBytesPerSecondFn(request, reply) : routeBytesPerSecondFn(request, reply); if (currentBytesPerSecond === undefined || currentBytesPerSecond === null || currentBytesPerSecond <= 0) { return payload; } if (typeof payload === 'string') { payload = Buffer.from(payload); } if (Buffer.isBuffer(payload)) { const throttleStream = new ThrottleStream({ bytesPerSecond: currentBytesPerSecond, }); return throttleStream.end(payload); } if (payload instanceof require('node:stream').Readable) { const throttleStream = new ThrottleStream({ bytesPerSecond: currentBytesPerSecond, }); return require('node:stream').pipeline(payload, throttleStream, (err) => { if (err) { fastify.log.error(err); } }); } return payload; }; routeOptions.config = { ...routeOptions.config, onSend: [ ...(Array.isArray(routeOptions.config.onSend) ? routeOptions.config.onSend : [routeOptions.config.onSend]), onSendHook, ], }; done(); }); fastify.addHook('onSend', async (request, reply, payload) => { if (payload === undefined || payload === null) { return payload; } const currentBytesPerSecond = isBytesPerSecondAsync ? await bytesPerSecondFn(request, reply) : bytesPerSecondFn(request, reply); if (currentBytesPerSecond === undefined || currentBytesPerSecond === null || currentBytesPerSecond <= 0) { return payload; } if (typeof payload === 'string') { payload = Buffer.from(payload); } if (Buffer.isBuffer(payload)) { const throttleStream = new ThrottleStream({ bytesPerSecond: currentBytesPerSecond, }); return throttleStream.end(payload); } if (payload instanceof require('node:stream').Readable) { const throttleStream = new ThrottleStream({ bytesPerSecond: currentBytesPerSecond, }); return require('node:stream').pipeline(payload, throttleStream, (err) => { if (err) { fastify.log.error(err); } }); } return payload; }); }; export default fastifyPlugin(fastifyThrottle); ``` -------------------------------- ### Gradual Rate Ramp-Up Over Time Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Implement a gradual increase in the allowed bandwidth over a specified ramp-up period. The rate progresses linearly towards a maximum target. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { const maxRate = 10 * 1024 * 1024 // 10 MB/s target const rampTime = 30 // seconds return (elapsedTime, bytes) => { const progress = Math.min(elapsedTime / rampTime, 1) return Math.floor(maxRate * progress) } } }) ``` -------------------------------- ### Time-Dependent Rate Scheduling (Bandwidth Scheduling) Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Implement dynamic rate limiting based on the current hour of the day. Higher rates are applied during off-peak hours and lower rates during peak hours. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { return (elapsedTime, bytes) => { const now = new Date() const hours = now.getHours() // Peak hours (9-17): 1 MB/s // Off-peak (17-9): 10 MB/s if (hours >= 9 && hours < 17) { return 1 * 1024 * 1024 } else { return 10 * 1024 * 1024 } } } }) ``` -------------------------------- ### Header-Based Rate Limit Configuration Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Configure rate limits using a custom header 'x-download-speed'. If the header is missing or invalid, a default rate of 1 MB/s is applied. Ensures the rate is non-negative. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { const customRate = parseInt(request.headers['x-download-speed'], 10) const rate = isNaN(customRate) ? 1024 * 1024 : customRate return () => Math.max(0, rate) // Ensure non-negative } }) ``` -------------------------------- ### Registering Fastify Throttle with TypeScript Options Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/README.md Demonstrates how to register the Fastify Throttle plugin with specific TypeScript type-checked options. Ensure you import the necessary types. ```typescript import fastifyThrottle from '@fastify/throttle' import type { FastifyThrottleOptions } from '@fastify/throttle' const options: FastifyThrottleOptions = { bytesPerSecond: 1024 * 1024, streamPayloads: true } await fastify.register(fastifyThrottle, options) ``` -------------------------------- ### ThrottleStream Constructor Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Instantiate a ThrottleStream to control data throughput. You can set a fixed rate or provide a dynamic function to adjust the rate over time. ```APIDOC ## new ThrottleStream(options?) ### Description Creates a new ThrottleStream instance to throttle data flow. ### Parameters #### options (Object) - Optional Configuration object for the stream. - **bytesPerSecond** (number | Function) - Optional, Default: 16384 Fixed rate in bytes per second, or a function `(elapsedTime: number, bytesSent: number) => number` that returns the current rate. ### Constructor Behavior - If called without `new`, automatically constructs and returns a new instance. - Extends Node.js `Transform` stream. - Initializes internal state for tracking elapsed time and bytes sent. - Does not begin throttling until the first chunk is written. ### Public Properties - **bytesPerSecondFn** (Function): The function used to calculate throttle rate. - **startTime** (number | null): Timestamp (milliseconds) when the stream began processing. - **bytes** (number): Total number of bytes passed through the stream. ### Example ```javascript import { ThrottleStream } from '@fastify/throttle' // Fixed rate of 1MB/s const throttle = new ThrottleStream({ bytesPerSecond: 1024 * 1024 }) // Dynamic rate function const dynamicThrottle = new ThrottleStream({ bytesPerSecond: (elapsedTime, bytesSent) => { // Ramp up from 100KB/s to 1MB/s over 10 seconds const rate = Math.min(1024 * 1024, 100000 + (90000 * elapsedTime / 10)) return Math.floor(rate) } }) ``` ``` -------------------------------- ### Fair-Share Bandwidth with Multiple Streams Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/implementation-details.md When multiple `ThrottleStream` instances are active, they naturally contribute to a fair-share distribution of the available bandwidth. For example, two requests can each utilize approximately half of the globally defined bandwidth. ```plaintext // Global: 10 MB/s // Request 1: ~5 MB/s (limited by rate function) // Request 2: ~5 MB/s (limited by rate function) // Total: ~10 MB/s ``` -------------------------------- ### Integration with Fastify JWT Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Integrate Fastify Throttle with Fastify JWT to apply dynamic throttling rates based on user authentication. This example shows fetching user tier from a database after JWT validation. ```javascript import jwt from '@fastify/jwt' import fastifyThrottle from '@fastify/throttle' await fastify.register(jwt, { secret: 'secret' }) await fastify.register(fastifyThrottle, { bytesPerSecond: async (request) => { // JWT is already validated by decorator const userId = request.user?.id const tier = await db.getUserTier(userId) return () => tier.bytesPerSecond } }) ``` -------------------------------- ### Async Rate Generator Without `async` Option Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md If your `bytesPerSecond` function is declared with `async`, the `async` option is not needed as the plugin can detect it automatically. This example shows an `async` function directly returning a Promise. ```javascript await fastify.register(fastifyThrottle, { // async option not needed bytesPerSecond: async (request) => { const config = await database.getUserConfig(request.user.id) return (elapsedTime, bytes) => config.bytesPerSecond } }) ``` -------------------------------- ### Global Configuration with Per-Route Overrides Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Configure a global rate limit and then override it for specific routes. This allows for a default throttling policy with exceptions for high-traffic or sensitive endpoints. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: 1 * 1024 * 1024, // 1 MB/s global streamPayloads: true, bufferPayloads: false }) // Ultra-fast route fastify.get('/cdn-mirror', { config: { throttle: { bytesPerSecond: 100 * 1024 * 1024 // 100 MB/s } } }, handler) // Very slow route fastify.get('/limited', { config: { throttle: { bytesPerSecond: 100 * 1024 // 100 KB/s } } }, handler) // No throttling fastify.get('/internal', { config: { throttle: { bytesPerSecond: Infinity } } }, handler) ``` -------------------------------- ### FastifyThrottlePluginOptions Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/types.md Extended interface for plugin options, currently equivalent to FastifyThrottleOptions. It exists for clarity and future extensibility. ```APIDOC ## FastifyThrottlePluginOptions ### Description Extended interface for plugin options (currently equivalent to FastifyThrottleOptions). ### Type Definition ```typescript interface FastifyThrottlePluginOptions extends FastifyThrottleOptions { } ``` ### Notes This interface exists as a named export for clarity and future extensibility, but currently includes no additional properties beyond those in `FastifyThrottleOptions`. ``` -------------------------------- ### Fastify Throttle Package JSON Entry Points Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/module-architecture.md Defines the main and types entry points for the Fastify Throttle package, specifying how it's exported for CommonJS and ESM environments. ```json { "main": "index.js", "types": "types/index.d.ts" } ``` -------------------------------- ### Async: Remote Configuration Service Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Retrieve rate limit configurations from an external service using an asynchronous fetch. This allows for centralized management of rate limits across different services. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: async (request) => { const configService = 'https://config.example.com/api/throttle' const response = await fetch(configService, { headers: { 'X-User-ID': request.user.id } }) const config = await response.json() return () => config.bytesPerSecond } }) ``` -------------------------------- ### Tier-Based Rate Limiting Configuration Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/configuration.md Implement rate limiting based on user tiers (e.g., free, pro, enterprise). This allows for differentiated service levels. Ensure `getUserTier` is correctly implemented and accessible. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: async (request) => { const tier = await getUserTier(request.user.id) const rates = { free: 100 * 1024, pro: 5 * 1024 * 1024, enterprise: Infinity } return () => rates[tier] } }) ``` -------------------------------- ### Empty Route Config Inherits Global Settings Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/implementation-details.md An empty route configuration (`config: {}`) will inherit the global `bytesPerSecond` settings. The route will be throttled based on the globally defined rate. ```javascript fastify.get('/', { config: {} // No throttle property }, handler) // Merge: Object.assign({globalOpts}, {}) // Still has globalOpts.bytesPerSecond // Route is throttled ``` -------------------------------- ### Route-Specific Throttle Configuration with Type Safety Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/README.md Shows how to configure throttle options for a specific route using the `config` property, ensuring type safety through Fastify's context configuration augmentation. ```typescript fastify.get('/download', { config: { throttle: { bytesPerSecond: 500000 } } }, handler) // Type-checked by FastifyContextConfig augmentation ``` -------------------------------- ### Throttle by Device Type (Mobile vs. Desktop) Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Register the plugin to set different rate limits based on whether the request originates from a mobile or desktop device. User agent detection is used to differentiate between device types. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { const userAgent = request.headers['user-agent'] || '' const isMobile = /mobile|android|iphone|ipad/i.test(userAgent) if (isMobile) { return () => 2 * 1024 * 1024 // 2 MB/s for mobile } else { return () => 20 * 1024 * 1024 // 20 MB/s for desktop } } }) ``` -------------------------------- ### Request-Based Rate Selection with User Tiers Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Dynamically set rate limits based on user tiers derived from the request object. Ensure the 'user' property and 'tier' are available on the request. ```javascript await fastify.register(fastifyThrottle, { bytesPerSecond: (request) => { const userTier = request.user?.tier || 'free' const rates = { free: 100 * 1024, // 100 KB/s pro: 10 * 1024 * 1024, // 10 MB/s enterprise: Infinity // Unlimited } return () => rates[userTier] } }) ``` -------------------------------- ### Register Fastify Throttle Plugin Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/api-reference.md Register the fastify-throttle plugin with global options. This sets the default throttling rate for all routes. Ensure Fastify and the plugin are imported. ```javascript import Fastify from 'fastify' import fastifyThrottle from '@fastify/throttle' const fastify = Fastify() // Register with global options await fastify.register(fastifyThrottle, { bytesPerSecond: 1024 * 1024, // 1 MB/s streamPayloads: true, bufferPayloads: true }) fastify.get('/', (_req, reply) => { reply.send({ hello: 'world' }) }) await fastify.listen({ port: 3000 }) ``` -------------------------------- ### Stream-Based File Download with Throttling Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Serve files using streams, allowing the throttle plugin to manage download speed. Ensure the file path is correctly resolved. ```javascript import { createReadStream } from 'fs' import { resolve } from 'path' fastify.get('/download/:filename', (request, reply) => { const filePath = resolve('./downloads', request.params.filename) reply.send(createReadStream(filePath)) }) ``` -------------------------------- ### FastifyContextConfig Extension for Route Throttle Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/types.md Augments Fastify's context configuration to allow per-route throttle settings. The 'throttle' property is optional and overrides global options. ```typescript declare module 'fastify' { interface FastifyContextConfig { throttle?: fastifyThrottle.FastifyThrottleOptions; } } ``` -------------------------------- ### Register Fastify Throttle Plugin Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/module-architecture.md Register the fastify-throttle plugin with Fastify, passing any necessary options. ```javascript fastify.register(fastifyThrottle, options) ``` -------------------------------- ### Load Testing Pattern Source: https://github.com/fastify/fastify-throttle/blob/main/_autodocs/usage-patterns.md Simulate different client tiers for load testing by creating an endpoint that returns data of a specified size, allowing you to test throttling behavior under various conditions. ```javascript // Simulate different client tiers fastify.get('/load-test/:tier', (request, reply) => { const tier = request.params.tier const size = parseInt(request.query.size, 10) || 1024 * 1024 // Return data to be throttled reply.send(Buffer.allocUnsafe(size)) }) // Usage: // curl http://localhost:3000/load-test/free?size=1000000 // curl http://localhost:3000/load-test/pro?size=10000000 ```