Skip to content

Commit

Permalink
fix: type-safed hitinfo
Browse files Browse the repository at this point in the history
  • Loading branch information
OrJDev committed Apr 16, 2024
1 parent 9d70e44 commit 9d0ae48
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 52 deletions.
8 changes: 8 additions & 0 deletions .changeset/happy-pillows-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@trpc-limiter/core': patch
'@trpc-limiter/memory': patch
'@trpc-limiter/redis': patch
'@trpc-limiter/upstash': patch
---

fix: type-safed hitinfo
5 changes: 1 addition & 4 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,7 @@ const t = initTRPC.context<Context>().create()

const rateLimiter = createTrpcRedisLimiter<typeof t>({
fingerprint: (ctx) => defaultFingerPrint(ctx.req),
message: (hitInfo) =>
`Too many requests, please try again later. ${Math.ceil(
(hitInfo.reset - Date.now()) / 1000
)}`,
message: (hitInfo) => `Too many requests, please try again later. ${hitInfo}`,
max: 15,
windowMs: 10000,
redisClient: redis,
Expand Down
5 changes: 1 addition & 4 deletions examples/nextjs-redis/src/server/api/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,7 @@ const rateLimiter = createTrpcRedisLimiter<typeof t>({
console.log("c$", c);
return c;
},
message: (hitInfo) =>
`Too many requests, please try again later. ${Math.ceil(
(hitInfo.reset - Date.now()) / 1000,
)}`,
message: (hitInfo) => `Too many requests, please try again later. ${hitInfo}`,
max: 5,
windowMs: 10000,
redisClient: redis,
Expand Down
9 changes: 0 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@
"prepare": "husky install"
},
"lint-staged": {
"*.{js,json}": "prettier --write",
"packages/**/*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"examples/**/*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"package.json": "sort-package-json"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export const defineTRPCLimiter = <

export const defineLimiterWithProps = <
T,
Store extends IStoreCallback<T> = IStoreCallback<T>,
Res = any
Res,
Store extends IStoreCallback<T> = IStoreCallback<T>
>(
adapter: ILimiterAdapter<Store, Res, T>,
getDefaultOptions: (
Expand Down
2 changes: 1 addition & 1 deletion packages/memory/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class MemoryStore {
/** Reference to the active timer. */
interval: NodeJS.Timer

constructor(options: Required<TRPCRateLimitOptions<AnyRootConfig>>) {
constructor(options: Required<TRPCRateLimitOptions<AnyRootConfig, any>>) {
this.windowMs = options.windowMs
this.resetTime = calculateNextResetTime(this.windowMs)
this.hits = {}
Expand Down
5 changes: 1 addition & 4 deletions packages/redis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ const t = initTRPC.context<Context>().create()

const rateLimiter = createTrpcRedisLimiter<typeof t>({
fingerprint: (ctx) => defaultFingerPrint(ctx.req),
message: (hitInfo) =>
`Too many requests, please try again later. ${Math.ceil(
(hitInfo.reset - Date.now()) / 1000
)}`,
message: (hitInfo) => `Too many requests, please try again later. ${hitInfo}`,
max: 15,
windowMs: 10000,
redisClient: redis,
Expand Down
41 changes: 23 additions & 18 deletions packages/redis/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,28 @@ import {
IRateLimiterStoreOptions,
} from 'rate-limiter-flexible'

export const createTrpcRedisLimiter = defineLimiterWithProps<{
redisClient: IRateLimiterStoreOptions['storeClient']
limiter?: (
opts: Required<BaseOpts<AnyRootConfig, any>>
) => IRateLimiterStoreOptions['insuranceLimiter']
}>(
const isBlocked = async (store: RateLimiterRedis, fingerprint: string) => {
try {
await store.consume(fingerprint)
return null
} catch (error) {
if (error instanceof RateLimiterRes) {
return Math.round(error.msBeforeNext / 1000) || 1
}
// Should not happen with `insuranceLimiter`
throw error
}
}

export const createTrpcRedisLimiter = defineLimiterWithProps<
{
redisClient: IRateLimiterStoreOptions['storeClient']
limiter?: (
opts: Required<BaseOpts<AnyRootConfig, any>>
) => IRateLimiterStoreOptions['insuranceLimiter']
},
NonNullable<Awaited<ReturnType<typeof isBlocked>>>
>(
{
store: (opts) => {
return new RateLimiterRedis({
Expand All @@ -26,18 +42,7 @@ export const createTrpcRedisLimiter = defineLimiterWithProps<{
insuranceLimiter: opts.limiter(opts),
})
},
async isBlocked(store, fingerprint) {
try {
await store.consume(fingerprint)
return null
} catch (error) {
if (error instanceof RateLimiterRes) {
return Math.round(error.msBeforeNext / 1000) || 1
}
// Should not happen with `insuranceLimiter`
throw error
}
},
isBlocked,
},
(currentState) => {
return {
Expand Down
26 changes: 16 additions & 10 deletions packages/upstash/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,28 @@ import {
defineLimiterWithProps,
BaseOpts,
AnyRootConfig,
defaultFingerPrint,
} from '@trpc-limiter/core'
import { Ratelimit } from '@upstash/ratelimit'
import { RegionRatelimitConfig } from '@upstash/ratelimit/types/single'

export const createTRPCUpstashLimiter = defineLimiterWithProps<{
rateLimitOpts: (
opts: Required<BaseOpts<AnyRootConfig, any>>
) => RegionRatelimitConfig
}>(
const isBlocked = async (store: Ratelimit, fingerprint: string) => {
const { success, pending, ...rest } = await store.limit(fingerprint)
await pending
return success ? null : rest
}

export const createTRPCUpstashLimiter = defineLimiterWithProps<
{
rateLimitOpts: (
opts: Required<BaseOpts<AnyRootConfig, any>>
) => RegionRatelimitConfig
},
NonNullable<Awaited<ReturnType<typeof isBlocked>>>
>(
{
store: (opts) => new Ratelimit(opts.rateLimitOpts(opts)),
async isBlocked(store, fingerprint) {
const { success, pending, ...rest } = await store.limit(fingerprint)
await pending
return success ? null : rest
},
isBlocked,
},
(currnetState) => {
return { rateLimitOpts: currnetState.rateLimitOpts }
Expand Down

0 comments on commit 9d0ae48

Please sign in to comment.