@trpc-limiter/core
Advanced tools
+11
-12
@@ -1,13 +0,8 @@ | ||
| import { AnyRootConfig as AnyRootConfig$1 } from '@trpc/server'; | ||
| import { RootConfig, AnyRootTypes, MiddlewareFunction } from '@trpc/server/unstable-core-do-not-import'; | ||
| type AnyRootConfig = { | ||
| _config: AnyRootConfig$1; | ||
| _config: RootConfig<AnyRootTypes>; | ||
| }; | ||
| type TRPCRateLimitOptions<TRoot extends AnyRootConfig, Res> = { | ||
| type BaseOpts<TRoot extends AnyRootConfig, Res> = { | ||
| /** | ||
| * Your root tRPC object returned from `initTRPC.create()` | ||
| * @required | ||
| **/ | ||
| root: TRoot; | ||
| /** | ||
| * Time frame in milliseconds how long to keep track of requests | ||
@@ -37,4 +32,5 @@ * @default 60000 (1 minute) | ||
| }; | ||
| type TRPCRateLimitOptions<TRoot extends AnyRootConfig, Res, A = null> = A extends null ? BaseOpts<TRoot, Res> : A & BaseOpts<TRoot, Res>; | ||
| type ILimiterCallback<TRoot extends AnyRootConfig, Res, T = string> = (info: Res, ctx: TRoot['_config']['$types']['ctx'], fingerprint: string) => T | Promise<T>; | ||
| type ILimiterAdapter<Store extends IStoreCallback, Res> = { | ||
| type ILimiterAdapter<Store extends IStoreCallback<A>, Res, A = null> = { | ||
| store: Store; | ||
@@ -44,6 +40,9 @@ isBlocked: (store: ReturnType<Store>, fingerprint: string, opts: Required<TRPCRateLimitOptions<AnyRootConfig, Store>>) => Promise<InferResCallback<Res> | null> | InferResCallback<Res> | null; | ||
| type InferResCallback<Res> = NonNullable<Res extends Promise<infer R2> ? R2 : Res>; | ||
| type IStoreCallback = (opts: Required<TRPCRateLimitOptions<AnyRootConfig, any>>) => any; | ||
| type IStoreCallback<A = null> = (opts: Required<TRPCRateLimitOptions<AnyRootConfig, any, A>>) => any; | ||
| type MwFn<TRoot extends AnyRootConfig> = MiddlewareFunction<TRoot['_config']['$types']['ctx'], TRoot['_config']['$types']['meta'], TRoot['_config']['$types']['ctx'], TRoot['_config']['$types']['ctx'], unknown>; | ||
| declare const defineTRPCLimiter: <Store extends IStoreCallback, Res>(adapter: ILimiterAdapter<Store, Res>) => <TRoot extends AnyRootConfig>(opts: TRPCRateLimitOptions<TRoot, Res>) => ({ ctx, next, input }: any) => Promise<any>; | ||
| declare const defineTRPCLimiter: <Store extends IStoreCallback<A>, Res, A = null>(adapter: ILimiterAdapter<Store, Res, A>, getDefaultOptions?: ((currentState: Required<TRPCRateLimitOptions<AnyRootConfig, any, A>>) => Required<A>) | undefined) => <TRoot extends AnyRootConfig>(opts: TRPCRateLimitOptions<TRoot, Res, A>) => MwFn<TRoot>; | ||
| declare const defineLimiterWithProps: <T, Res, Store extends IStoreCallback<T> = IStoreCallback<T>>(adapter: ILimiterAdapter<Store, Res, T>, getDefaultOptions: (currentState: Required<TRPCRateLimitOptions<AnyRootConfig, any, T>>) => Required<T>) => <TRoot extends AnyRootConfig>(opts: TRPCRateLimitOptions<TRoot, Res, T>) => MwFn<AnyRootConfig>; | ||
| declare const defaultFingerPrint: (req: Request | Record<any, any>) => any; | ||
| export { AnyRootConfig, ILimiterAdapter, ILimiterCallback, IStoreCallback, InferResCallback, TRPCRateLimitOptions, defineTRPCLimiter }; | ||
| export { AnyRootConfig, BaseOpts, ILimiterAdapter, ILimiterCallback, IStoreCallback, InferResCallback, MwFn, TRPCRateLimitOptions, defaultFingerPrint, defineLimiterWithProps, defineTRPCLimiter }; |
+23
-5
| // src/index.ts | ||
| import { TRPCError } from "@trpc/server"; | ||
| var parseOptions = (passed) => { | ||
| return { | ||
| root: passed.root, | ||
| var parseOptions = (passed, getDefaultOptions) => { | ||
| const b = { | ||
| ...passed, | ||
| windowMs: passed.windowMs ?? 6e4, | ||
@@ -12,6 +12,11 @@ max: passed.max ?? 5, | ||
| }; | ||
| const newOpts = getDefaultOptions ? getDefaultOptions(b) : {}; | ||
| return { | ||
| ...b, | ||
| ...newOpts | ||
| }; | ||
| }; | ||
| var defineTRPCLimiter = (adapter) => { | ||
| var defineTRPCLimiter = (adapter, getDefaultOptions) => { | ||
| return (opts) => { | ||
| const options = parseOptions(opts); | ||
| const options = parseOptions(opts, getDefaultOptions); | ||
| const store = adapter.store(options); | ||
@@ -42,4 +47,17 @@ const middleware = async ({ ctx, next, input }) => { | ||
| }; | ||
| var defineLimiterWithProps = (adapter, getDefaultOptions) => { | ||
| const d = defineTRPCLimiter(adapter, getDefaultOptions); | ||
| return (opts) => { | ||
| return d(opts); | ||
| }; | ||
| }; | ||
| var defaultFingerPrint = (req) => { | ||
| const forwarded = req instanceof Request ? req.headers.get("x-forwarded-for") : req.headers["x-forwarded-for"]; | ||
| const ip = forwarded ? (typeof forwarded === "string" ? forwarded : forwarded[0])?.split(/, /)[0] : req?.socket?.remoteAddress ?? null; | ||
| return ip || "127.0.0.1"; | ||
| }; | ||
| export { | ||
| defaultFingerPrint, | ||
| defineLimiterWithProps, | ||
| defineTRPCLimiter | ||
| }; |
+5
-5
| { | ||
| "name": "@trpc-limiter/core", | ||
| "version": "0.0.8", | ||
| "version": "1.0.0", | ||
| "private": false, | ||
@@ -23,9 +23,9 @@ "keywords": [ | ||
| "devDependencies": { | ||
| "@trpc/client": "^10.7.0", | ||
| "@trpc/server": "^10.7.0", | ||
| "@trpc/client": "next", | ||
| "@trpc/server": "next", | ||
| "typescript": "^4.9.3" | ||
| }, | ||
| "peerDependencies": { | ||
| "@trpc/client": "^10.0.0-proxy-beta.21", | ||
| "@trpc/server": "^10.0.0-proxy-beta.21" | ||
| "@trpc/client": "next", | ||
| "@trpc/server": "next" | ||
| }, | ||
@@ -32,0 +32,0 @@ "engines": { |
+29
-6
@@ -34,7 +34,10 @@ # @trpc-limiter/core | ||
| import { initTRPC, TRPCError } from '@trpc/server' | ||
| import type { IContext } from './context' | ||
| import { createTRPCStoreLimiter } from '@trpc-limiter/memory' | ||
| import { | ||
| createTRPCStoreLimiter, | ||
| defaultFingerPrint, | ||
| } from '@trpc-limiter/memory' | ||
| // trpc context type | ||
| type IContext = { | ||
| req: Request // your request type | ||
| req: Request | ||
| } | ||
@@ -45,5 +48,3 @@ | ||
| const limiter = createTRPCStoreLimiter({ | ||
| root, | ||
| fingerprint: (ctx, _input) => | ||
| ctx.req.headers.get('x-forwarded-for') ?? '127.0.0.1', // return the ip from the request | ||
| fingerprint: (ctx, _input) => defaultFingerPrint(ctx.req), // return the ip from the request | ||
| windowMs: 20000, | ||
@@ -64,1 +65,23 @@ // hitInfo is inferred from the return type of `isBlocked`, its a number in this case | ||
| ``` | ||
| ## defaultFingerPrint | ||
| The `defaultFingerPrint` function is exported from every adapter, it basically tries and fetch the IP from the request supporting both NextJS & SolidStart (Fetch). | ||
| ```ts | ||
| import { | ||
| createTRPCStoreLimiter, | ||
| defaultFingerPrint, | ||
| } from '@trpc-limiter/memory' | ||
| // or | ||
| import { | ||
| createTRPCUpstashLimiter, | ||
| defaultFingerPrint, | ||
| } from '@trpc-limiter/upstash' | ||
| // or | ||
| import { createTrpcRedisLimiter, defaultFingerPrint } from '@trpc-limiter/redis' | ||
| ``` |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
8111
31.89%106
21.84%1
-50%85
37.1%2
100%