1
- import { RedisClientOptions , createClient } from "redis " ;
1
+ import { ActionFunction , ActionFunctionArgs , LoaderFunction } from "@remix-run/server-runtime " ;
2
2
import { Ratelimit } from "@upstash/ratelimit" ;
3
- import {
4
- ActionFunction ,
5
- ActionFunctionArgs ,
6
- LoaderFunction ,
7
- LoaderFunctionArgs ,
8
- } from "@remix-run/server-runtime" ;
3
+ import Redis , { RedisOptions } from "ioredis" ;
9
4
import { env } from "~/env.server" ;
10
5
11
6
function createRedisRateLimitClient (
12
- redisOptions : RedisClientOptions
7
+ redisOptions : RedisOptions
13
8
) : ConstructorParameters < typeof Ratelimit > [ 0 ] [ "redis" ] {
14
- const redis = createClient ( redisOptions ) ;
9
+ const redis = new Redis ( redisOptions ) ;
15
10
16
11
return {
17
12
sadd : async < TData > ( key : string , ...members : TData [ ] ) : Promise < number > => {
18
- return redis . sAdd ( key as string , members as any ) ;
13
+ return redis . sadd ( key , members as ( string | number | Buffer ) [ ] ) ;
19
14
} ,
20
15
eval : < TArgs extends unknown [ ] , TData = unknown > (
21
16
...args : [ script : string , keys : string [ ] , args : TArgs ]
22
17
) : Promise < TData > => {
23
- return redis . eval ( args [ 0 ] , {
24
- keys : args [ 1 ] ,
25
- arguments : args [ 2 ] as string [ ] ,
26
- } ) as Promise < TData > ;
18
+ const script = args [ 0 ] ;
19
+ const keys = args [ 1 ] ;
20
+ const argsArray = args [ 2 ] ;
21
+ return redis . eval (
22
+ script ,
23
+ keys . length ,
24
+ ...keys ,
25
+ ...( argsArray as ( string | Buffer | number ) [ ] )
26
+ ) as Promise < TData > ;
27
27
} ,
28
28
} ;
29
29
}
30
30
31
31
type Options = {
32
- redis : RedisClientOptions ;
32
+ redis : RedisOptions ;
33
33
limiter : ConstructorParameters < typeof Ratelimit > [ 0 ] [ "limiter" ] ;
34
34
} ;
35
35
@@ -45,6 +45,9 @@ class RateLimitter {
45
45
} ) ;
46
46
}
47
47
48
+ //todo Express middleware
49
+ //use the Authentication header with Bearer token
50
+
48
51
async loader ( key : string , fn : LoaderFunction ) : Promise < ReturnType < LoaderFunction > > {
49
52
const { success, pending, limit, reset, remaining } = await this . #rateLimitter. limit (
50
53
`ratelimit:${ key } `
@@ -80,7 +83,12 @@ class RateLimitter {
80
83
81
84
export const standardRateLimitter = new RateLimitter ( {
82
85
redis : {
83
- url : `redis://${ env . REDIS_USERNAME } :${ env . REDIS_PASSWORD } @${ env . REDIS_HOST } :${ env . REDIS_PORT } ` ,
86
+ port : env . REDIS_PORT ,
87
+ host : env . REDIS_HOST ,
88
+ username : env . REDIS_USERNAME ,
89
+ password : env . REDIS_PASSWORD ,
90
+ enableAutoPipelining : true ,
91
+ ...( env . REDIS_TLS_DISABLED === "true" ? { } : { tls : { } } ) ,
84
92
} ,
85
93
limiter : Ratelimit . slidingWindow ( 1 , "60 s" ) ,
86
94
} ) ;
0 commit comments