11import fp from "fastify-plugin" ;
2- import {
3- ConditionalCheckFailedException ,
4- UpdateItemCommand ,
5- } from "@aws-sdk/client-dynamodb" ;
6- import { DynamoDBClient } from "@aws-sdk/client-dynamodb" ;
7- import { genericConfig } from "common/config.js" ;
2+ import { isAtLimit } from "api/functions/rateLimit.js" ;
83import { FastifyPluginAsync , FastifyRequest , FastifyReply } from "fastify" ;
94
105interface RateLimiterOptions {
@@ -13,66 +8,6 @@ interface RateLimiterOptions {
138 rateLimitIdentifier ?: string ;
149}
1510
16- interface RateLimitParams {
17- ddbClient : DynamoDBClient ;
18- rateLimitIdentifier : string ;
19- duration : number ;
20- limit : number ;
21- userIdentifier : string ;
22- }
23-
24- async function isAtLimit ( {
25- ddbClient,
26- rateLimitIdentifier,
27- duration,
28- limit,
29- userIdentifier,
30- } : RateLimitParams ) : Promise < {
31- limited : boolean ;
32- resetTime : number ;
33- used : number ;
34- } > {
35- const nowInSeconds = Math . floor ( Date . now ( ) / 1000 ) ;
36- const timeWindow = Math . floor ( nowInSeconds / duration ) * duration ;
37- const PK = `rate-limit:${ rateLimitIdentifier } :${ userIdentifier } :${ timeWindow } ` ;
38-
39- try {
40- const result = await ddbClient . send (
41- new UpdateItemCommand ( {
42- TableName : genericConfig . RateLimiterDynamoTableName ,
43- Key : {
44- PK : { S : PK } ,
45- SK : { S : "counter" } ,
46- } ,
47- UpdateExpression : "ADD #rateLimitCount :inc SET #ttl = :ttl" ,
48- ConditionExpression :
49- "attribute_not_exists(#rateLimitCount) OR #rateLimitCount <= :limit" ,
50- ExpressionAttributeValues : {
51- ":inc" : { N : "1" } ,
52- ":limit" : { N : limit . toString ( ) } ,
53- ":ttl" : { N : ( timeWindow + duration ) . toString ( ) } ,
54- } ,
55- ExpressionAttributeNames : {
56- "#rateLimitCount" : "rateLimitCount" ,
57- "#ttl" : "ttl" ,
58- } ,
59- ReturnValues : "UPDATED_NEW" ,
60- ReturnValuesOnConditionCheckFailure : "ALL_OLD" ,
61- } ) ,
62- ) ;
63- return {
64- limited : false ,
65- used : parseInt ( result . Attributes ?. rateLimitCount . N || "1" , 10 ) ,
66- resetTime : timeWindow + duration ,
67- } ;
68- } catch ( error ) {
69- if ( error instanceof ConditionalCheckFailedException ) {
70- return { limited : true , resetTime : timeWindow + duration , used : limit } ;
71- }
72- throw error ;
73- }
74- }
75-
7611const rateLimiterPlugin : FastifyPluginAsync < RateLimiterOptions > = async (
7712 fastify ,
7813 options ,
0 commit comments