@lidofinance/next-ip-rate-limit 0.27.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +4 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +4 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -71,8 +71,9 @@ const $c63185ef25ccfd28$export$67218453e01a0be8 = (req)=>{
|
|
|
71
71
|
if (cfConnectionIp) return Array.isArray(cfConnectionIp) ? cfConnectionIp[0] : cfConnectionIp.split(",")[0];
|
|
72
72
|
return xff ? Array.isArray(xff) ? xff[0] : xff.split(",")[0] : "127.0.0.1";
|
|
73
73
|
};
|
|
74
|
-
const $c63185ef25ccfd28$export$d0a20d44a54350ab = ({ id: id , res: res , req: req })=>{
|
|
74
|
+
const $c63185ef25ccfd28$export$d0a20d44a54350ab = ({ id: id , res: res , req: req , retryAfter: retryAfter })=>{
|
|
75
75
|
res.status(429);
|
|
76
|
+
if (retryAfter) res.setHeader("Retry-After", retryAfter.toString());
|
|
76
77
|
throw new Error(`${(0, $54a02752d7f6015e$export$3f27bc10068ef877)} ${id} ${req.url || ""}`);
|
|
77
78
|
};
|
|
78
79
|
|
|
@@ -95,7 +96,8 @@ const $abe9c276dfd79488$export$122bebc9e141287c = (data)=>{
|
|
|
95
96
|
if (remaining < 0) (0, $c63185ef25ccfd28$export$d0a20d44a54350ab)({
|
|
96
97
|
id: id,
|
|
97
98
|
res: res,
|
|
98
|
-
req: req
|
|
99
|
+
req: req,
|
|
100
|
+
retryAfter: timeFrame
|
|
99
101
|
});
|
|
100
102
|
return res;
|
|
101
103
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;;;;;;;;;;;;;;;;;AEEO,MAAM;IAEH,aAA+B,EAAE,CAAA;IAEzC,aAAc;QACZ,IAAI,CAAC,QAAQ,GAAG,IAAI;IACtB;IAEA,IAAI,GAAW,EAAE,KAAa,EAAE,WAAmB,EAAE;QACnD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK;mBAAE;QAAM;QAE/B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,WAC1B,aAAa,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM;QAGvC,2FAA2F;QAC3F,+EAA+E;QAC/E,MAAM,YAAY,WAAW,IAAM;YACjC,aAAa;YAEb,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAO,MAAM;YACvD,IAAI,CAAC,MAAM,CAAC;QACd,GAAG,cAAc;QACjB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;IACvB;IAEA,IAAI,GAAW,EAAE;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM;IACjC;IAEA,IAAI,GAAW,EAAE,WAAmB,EAAE;QACpC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MACpB,IAAI,CAAC,GAAG,CAAC,KAAK,AAAC,CAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,SAAS,CAAA,IAAK,GAAG;aAExD,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG;QAGnB,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB;IACA,OAAO,GAAW,EAAE;QAClB,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MACpB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;IAEzB;AACF;;AD9CA;;;;;AGAO,MAAM,4CAAqB;IAChC,OAAO,CAAC,iBAAiB,CAAC;IAC1B,WAAW,CAAC,qBAAqB,CAAC;IAClC,OAAO,CAAC,iBAAiB,CAAC;AAC5B;AAEO,MAAM,4CAAgB;;ADN7B;AAQO,MAAM,4CAAQ,CAAC,MAAwB;IAC5C,MAAM,iBAAiB,IAAI,OAAO,CAAC,mBAAmB;IACtD,MAAM,MAAM,IAAI,OAAO,CAAC,kBAAkB;IAE1C,IAAI,gBAAgB,OAAO,MAAM,OAAO,CAAC,kBAAkB,cAAc,CAAC,EAAE,GAAG,eAAe,KAAK,CAAC,IAAI,CAAC,EAAE;IAE3G,OAAO,MAAO,MAAM,OAAO,CAAC,OAAO,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,GAAI,WAAW;AAC9E;AAEO,MAAM,4CAA2C,CAAC,MAAE,GAAE,OAAE,IAAG,OAAE,IAAG,EAAE,GAAK;
|
|
1
|
+
{"mappings":"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","sources":["packages/next/ip-rate-limit/src/index.ts","packages/next/ip-rate-limit/src/ip-rate-limit.ts","packages/next/ip-rate-limit/src/storage.ts","packages/next/ip-rate-limit/src/utils.ts","packages/next/ip-rate-limit/src/constants.ts","packages/next/ip-rate-limit/src/wrapper.ts","packages/next/ip-rate-limit/src/types.ts"],"sourcesContent":["export * from './ip-rate-limit'\nexport * from './wrapper'\nexport * from './constants'\nexport * from './types'\n","import { RateLimitStorage } from './storage'\nimport { getIP, rateLimitedResponse } from './utils'\nimport { RATE_LIMIT_HEADERS } from './constants'\nimport { RateLimit } from './types'\n\nlet rateLimitStorage: RateLimitStorage\n\nexport const ipRateLimit: RateLimit = (data) => {\n if (!rateLimitStorage) rateLimitStorage = new RateLimitStorage()\n\n const { res, req, limit, timeFrame } = data\n const headers = RATE_LIMIT_HEADERS\n const id = `ip:${getIP(req)}`\n\n const time = Math.floor(Date.now() / 1000 / timeFrame)\n const key = `${id}:${time}`\n\n const callCount = rateLimitStorage.inc(key, data.timeFrame)\n const remaining = limit - (callCount || 0)\n const reset = (time + 1) * timeFrame\n\n res.setHeader(headers.limit, `${limit}`)\n res.setHeader(headers.remaining, `${remaining < 0 ? 0 : remaining}`)\n res.setHeader(headers.reset, `${reset}`)\n\n if (remaining < 0) rateLimitedResponse({ id, res, req, retryAfter: timeFrame })\n\n return res\n}\n","import { RateLimitStorageType } from './types'\n\nexport class RateLimitStorage {\n private _storage: RateLimitStorageType\n private timeoutIds: NodeJS.Timeout[] = []\n\n constructor() {\n this._storage = new Map()\n }\n\n set(key: string, value: number, durationSec: number) {\n this._storage.set(key, { value })\n\n if (this._storage.get(key)?.timeoutId) {\n clearTimeout(this._storage.get(key)?.timeoutId)\n }\n\n // code based on the work with setTimeouts from the code from the nestjs throttling service\n // https://github.com/nestjs/throttler/blob/master/src/throttler.service.ts#L25\n const timeoutId = setTimeout(() => {\n clearTimeout(timeoutId)\n\n this.timeoutIds = this.timeoutIds.filter((id) => id != timeoutId)\n this.delete(key)\n }, durationSec * 1000)\n this.timeoutIds.push(timeoutId)\n }\n\n get(key: string) {\n return this._storage.get(key)?.value\n }\n\n inc(key: string, durationSec: number) {\n if (this._storage.has(key)) {\n this.set(key, (this._storage.get(key)?.value || 0) + 1, durationSec)\n } else {\n this.set(key, 1, durationSec)\n }\n\n return this.get(key)\n }\n delete(key: string) {\n if (this._storage.has(key)) {\n this._storage.delete(key)\n }\n }\n}\n","import { NextApiRequest } from 'next'\nimport { ERROR_MESSAGE } from './constants'\nimport { RateLimitedResponse } from './types'\n\n// now we use headers from \"cloudflare\" and rely on their validity.\n// If there are no \"cloudflare\" headers, we use the \"x-forwarded-for\" header,\n// but keep in mind that these headers can be changed by anyone\n// https://developers.cloudflare.com/fundamentals/get-started/reference/http-request-headers/\nexport const getIP = (req: NextApiRequest) => {\n const cfConnectionIp = req.headers['cf_connecting_ip']\n const xff = req.headers['x-forwarded-for']\n\n if (cfConnectionIp) return Array.isArray(cfConnectionIp) ? cfConnectionIp[0] : cfConnectionIp.split(',')[0]\n\n return xff ? (Array.isArray(xff) ? xff[0] : xff.split(',')[0]) : '127.0.0.1'\n}\n\nexport const rateLimitedResponse: RateLimitedResponse = ({ id, res, req, retryAfter }) => {\n res.status(429)\n if (retryAfter) res.setHeader('Retry-After', retryAfter.toString())\n throw new Error(`${ERROR_MESSAGE} ${id} ${req.url || ''}`)\n}\n","export const RATE_LIMIT_HEADERS = {\n limit: `X-RateLimit-Limit`,\n remaining: `X-RateLimit-Remaining`,\n reset: `X-RateLimit-Reset`,\n}\n\nexport const ERROR_MESSAGE = 'API rate limit exceeded for'\n","import { RequestWrapper } from '@lidofinance/next-api-wrapper'\n\nimport { ipRateLimit } from './ip-rate-limit'\nimport { RateLimitWrapperArgs } from './types'\n\nexport const rateLimitWrapper =\n ({ rateLimit, rateLimitTimeFrame }: RateLimitWrapperArgs): RequestWrapper =>\n async (req, res, next) => {\n ipRateLimit({\n req,\n res,\n limit: rateLimit,\n timeFrame: rateLimitTimeFrame,\n })\n\n await next?.(req, res, next)\n }\n","import { NextApiResponse, NextApiRequest } from 'next'\n\nexport type RateLimitStorageType = Map<string, { value: number; timeoutId?: NodeJS.Timeout }>\n\nexport type RateLimitedResponse = (data: {\n res: NextApiResponse\n id: string\n req: NextApiRequest\n retryAfter?: number\n}) => void\n\nexport type RateLimit = (data: {\n req: NextApiRequest\n res: NextApiResponse\n limit: number\n timeFrame: number\n}) => NextApiResponse\n\nexport type RateLimitWrapperArgs = {\n rateLimit: number\n rateLimitTimeFrame: number\n}\n"],"names":[],"version":3,"file":"index.cjs.map","sourceRoot":"../../../../"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;AAEA,mCAAmC,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,OAAO,CAAA;CAAE,CAAC,CAAA;AAE7F,kCAAkC,CAAC,IAAI,EAAE;
|
|
1
|
+
{"mappings":";;AAEA,mCAAmC,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,OAAO,CAAA;CAAE,CAAC,CAAA;AAE7F,kCAAkC,CAAC,IAAI,EAAE;IACvC,GAAG,EAAE,eAAe,CAAA;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,cAAc,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,KAAK,IAAI,CAAA;AAEV,wBAAwB,CAAC,IAAI,EAAE;IAC7B,GAAG,EAAE,cAAc,CAAA;IACnB,GAAG,EAAE,eAAe,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;CAClB,KAAK,eAAe,CAAA;AAErB,mCAAmC;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,kBAAkB,EAAE,MAAM,CAAA;CAC3B,CAAA;AErBD,OAAO,MAAM;;;;CAIZ,CAAA;AAED,OAAO,MAAM,6CAA6C,CAAA;AEC1D,OAAO,MAAM,aAAa,SAqBzB,CAAA;ACvBD,OAAO,MAAM,sDACyB,oBAAoB,KAAG,cAU1D,CAAA","sources":["packages/next/ip-rate-limit/src/src/types.ts","packages/next/ip-rate-limit/src/src/storage.ts","packages/next/ip-rate-limit/src/src/constants.ts","packages/next/ip-rate-limit/src/src/utils.ts","packages/next/ip-rate-limit/src/src/ip-rate-limit.ts","packages/next/ip-rate-limit/src/src/wrapper.ts","packages/next/ip-rate-limit/src/src/index.ts","packages/next/ip-rate-limit/src/index.ts"],"sourcesContent":[null,null,null,null,null,null,null,"export * from './ip-rate-limit'\nexport * from './wrapper'\nexport * from './constants'\nexport * from './types'\n"],"names":[],"version":3,"file":"index.d.ts.map","sourceRoot":"../../../../"}
|
package/dist/index.mjs
CHANGED
|
@@ -55,8 +55,9 @@ const $15f73ba5d70a67f1$export$67218453e01a0be8 = (req)=>{
|
|
|
55
55
|
if (cfConnectionIp) return Array.isArray(cfConnectionIp) ? cfConnectionIp[0] : cfConnectionIp.split(",")[0];
|
|
56
56
|
return xff ? Array.isArray(xff) ? xff[0] : xff.split(",")[0] : "127.0.0.1";
|
|
57
57
|
};
|
|
58
|
-
const $15f73ba5d70a67f1$export$d0a20d44a54350ab = ({ id: id , res: res , req: req })=>{
|
|
58
|
+
const $15f73ba5d70a67f1$export$d0a20d44a54350ab = ({ id: id , res: res , req: req , retryAfter: retryAfter })=>{
|
|
59
59
|
res.status(429);
|
|
60
|
+
if (retryAfter) res.setHeader("Retry-After", retryAfter.toString());
|
|
60
61
|
throw new Error(`${(0, $1022f9b28fec0213$export$3f27bc10068ef877)} ${id} ${req.url || ""}`);
|
|
61
62
|
};
|
|
62
63
|
|
|
@@ -79,7 +80,8 @@ const $4a980b7982e8368e$export$122bebc9e141287c = (data)=>{
|
|
|
79
80
|
if (remaining < 0) (0, $15f73ba5d70a67f1$export$d0a20d44a54350ab)({
|
|
80
81
|
id: id,
|
|
81
82
|
res: res,
|
|
82
|
-
req: req
|
|
83
|
+
req: req,
|
|
84
|
+
retryAfter: timeFrame
|
|
83
85
|
});
|
|
84
86
|
return res;
|
|
85
87
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";;;;;;AEEO,MAAM;IAEH,aAA+B,EAAE,CAAA;IAEzC,aAAc;QACZ,IAAI,CAAC,QAAQ,GAAG,IAAI;IACtB;IAEA,IAAI,GAAW,EAAE,KAAa,EAAE,WAAmB,EAAE;QACnD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK;mBAAE;QAAM;QAE/B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,WAC1B,aAAa,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM;QAGvC,2FAA2F;QAC3F,+EAA+E;QAC/E,MAAM,YAAY,WAAW,IAAM;YACjC,aAAa;YAEb,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAO,MAAM;YACvD,IAAI,CAAC,MAAM,CAAC;QACd,GAAG,cAAc;QACjB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;IACvB;IAEA,IAAI,GAAW,EAAE;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM;IACjC;IAEA,IAAI,GAAW,EAAE,WAAmB,EAAE;QACpC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MACpB,IAAI,CAAC,GAAG,CAAC,KAAK,AAAC,CAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,SAAS,CAAA,IAAK,GAAG;aAExD,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG;QAGnB,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB;IACA,OAAO,GAAW,EAAE;QAClB,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MACpB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;IAEzB;AACF;;AD9CA;;;;;AGAO,MAAM,4CAAqB;IAChC,OAAO,CAAC,iBAAiB,CAAC;IAC1B,WAAW,CAAC,qBAAqB,CAAC;IAClC,OAAO,CAAC,iBAAiB,CAAC;AAC5B;AAEO,MAAM,4CAAgB;;ADN7B;AAQO,MAAM,4CAAQ,CAAC,MAAwB;IAC5C,MAAM,iBAAiB,IAAI,OAAO,CAAC,mBAAmB;IACtD,MAAM,MAAM,IAAI,OAAO,CAAC,kBAAkB;IAE1C,IAAI,gBAAgB,OAAO,MAAM,OAAO,CAAC,kBAAkB,cAAc,CAAC,EAAE,GAAG,eAAe,KAAK,CAAC,IAAI,CAAC,EAAE;IAE3G,OAAO,MAAO,MAAM,OAAO,CAAC,OAAO,GAAG,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,GAAI,WAAW;AAC9E;AAEO,MAAM,4CAA2C,CAAC,MAAE,GAAE,OAAE,IAAG,OAAE,IAAG,EAAE,GAAK;
|
|
1
|
+
{"mappings":"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","sources":["packages/next/ip-rate-limit/src/index.ts","packages/next/ip-rate-limit/src/ip-rate-limit.ts","packages/next/ip-rate-limit/src/storage.ts","packages/next/ip-rate-limit/src/utils.ts","packages/next/ip-rate-limit/src/constants.ts","packages/next/ip-rate-limit/src/wrapper.ts","packages/next/ip-rate-limit/src/types.ts"],"sourcesContent":["export * from './ip-rate-limit'\nexport * from './wrapper'\nexport * from './constants'\nexport * from './types'\n","import { RateLimitStorage } from './storage'\nimport { getIP, rateLimitedResponse } from './utils'\nimport { RATE_LIMIT_HEADERS } from './constants'\nimport { RateLimit } from './types'\n\nlet rateLimitStorage: RateLimitStorage\n\nexport const ipRateLimit: RateLimit = (data) => {\n if (!rateLimitStorage) rateLimitStorage = new RateLimitStorage()\n\n const { res, req, limit, timeFrame } = data\n const headers = RATE_LIMIT_HEADERS\n const id = `ip:${getIP(req)}`\n\n const time = Math.floor(Date.now() / 1000 / timeFrame)\n const key = `${id}:${time}`\n\n const callCount = rateLimitStorage.inc(key, data.timeFrame)\n const remaining = limit - (callCount || 0)\n const reset = (time + 1) * timeFrame\n\n res.setHeader(headers.limit, `${limit}`)\n res.setHeader(headers.remaining, `${remaining < 0 ? 0 : remaining}`)\n res.setHeader(headers.reset, `${reset}`)\n\n if (remaining < 0) rateLimitedResponse({ id, res, req, retryAfter: timeFrame })\n\n return res\n}\n","import { RateLimitStorageType } from './types'\n\nexport class RateLimitStorage {\n private _storage: RateLimitStorageType\n private timeoutIds: NodeJS.Timeout[] = []\n\n constructor() {\n this._storage = new Map()\n }\n\n set(key: string, value: number, durationSec: number) {\n this._storage.set(key, { value })\n\n if (this._storage.get(key)?.timeoutId) {\n clearTimeout(this._storage.get(key)?.timeoutId)\n }\n\n // code based on the work with setTimeouts from the code from the nestjs throttling service\n // https://github.com/nestjs/throttler/blob/master/src/throttler.service.ts#L25\n const timeoutId = setTimeout(() => {\n clearTimeout(timeoutId)\n\n this.timeoutIds = this.timeoutIds.filter((id) => id != timeoutId)\n this.delete(key)\n }, durationSec * 1000)\n this.timeoutIds.push(timeoutId)\n }\n\n get(key: string) {\n return this._storage.get(key)?.value\n }\n\n inc(key: string, durationSec: number) {\n if (this._storage.has(key)) {\n this.set(key, (this._storage.get(key)?.value || 0) + 1, durationSec)\n } else {\n this.set(key, 1, durationSec)\n }\n\n return this.get(key)\n }\n delete(key: string) {\n if (this._storage.has(key)) {\n this._storage.delete(key)\n }\n }\n}\n","import { NextApiRequest } from 'next'\nimport { ERROR_MESSAGE } from './constants'\nimport { RateLimitedResponse } from './types'\n\n// now we use headers from \"cloudflare\" and rely on their validity.\n// If there are no \"cloudflare\" headers, we use the \"x-forwarded-for\" header,\n// but keep in mind that these headers can be changed by anyone\n// https://developers.cloudflare.com/fundamentals/get-started/reference/http-request-headers/\nexport const getIP = (req: NextApiRequest) => {\n const cfConnectionIp = req.headers['cf_connecting_ip']\n const xff = req.headers['x-forwarded-for']\n\n if (cfConnectionIp) return Array.isArray(cfConnectionIp) ? cfConnectionIp[0] : cfConnectionIp.split(',')[0]\n\n return xff ? (Array.isArray(xff) ? xff[0] : xff.split(',')[0]) : '127.0.0.1'\n}\n\nexport const rateLimitedResponse: RateLimitedResponse = ({ id, res, req, retryAfter }) => {\n res.status(429)\n if (retryAfter) res.setHeader('Retry-After', retryAfter.toString())\n throw new Error(`${ERROR_MESSAGE} ${id} ${req.url || ''}`)\n}\n","export const RATE_LIMIT_HEADERS = {\n limit: `X-RateLimit-Limit`,\n remaining: `X-RateLimit-Remaining`,\n reset: `X-RateLimit-Reset`,\n}\n\nexport const ERROR_MESSAGE = 'API rate limit exceeded for'\n","import { RequestWrapper } from '@lidofinance/next-api-wrapper'\n\nimport { ipRateLimit } from './ip-rate-limit'\nimport { RateLimitWrapperArgs } from './types'\n\nexport const rateLimitWrapper =\n ({ rateLimit, rateLimitTimeFrame }: RateLimitWrapperArgs): RequestWrapper =>\n async (req, res, next) => {\n ipRateLimit({\n req,\n res,\n limit: rateLimit,\n timeFrame: rateLimitTimeFrame,\n })\n\n await next?.(req, res, next)\n }\n","import { NextApiResponse, NextApiRequest } from 'next'\n\nexport type RateLimitStorageType = Map<string, { value: number; timeoutId?: NodeJS.Timeout }>\n\nexport type RateLimitedResponse = (data: {\n res: NextApiResponse\n id: string\n req: NextApiRequest\n retryAfter?: number\n}) => void\n\nexport type RateLimit = (data: {\n req: NextApiRequest\n res: NextApiResponse\n limit: number\n timeFrame: number\n}) => NextApiResponse\n\nexport type RateLimitWrapperArgs = {\n rateLimit: number\n rateLimitTimeFrame: number\n}\n"],"names":[],"version":3,"file":"index.mjs.map","sourceRoot":"../../../../"}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "IP rate limit for next server api requests",
|
|
4
4
|
"repository": "git@github.com:lidofinance/warehouse.git",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.28.0",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist"
|
|
9
9
|
],
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"next": "^12.2.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@lidofinance/config-prettier": "~0.
|
|
28
|
+
"@lidofinance/config-prettier": "~0.28.0",
|
|
29
29
|
"@types/jest": "^28.0.0",
|
|
30
30
|
"@types/node": "^18.11.2",
|
|
31
31
|
"jest": "^28.0.0",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"ts-jest": "^28.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@lidofinance/next-api-wrapper": "~0.
|
|
36
|
+
"@lidofinance/next-api-wrapper": "~0.28.0"
|
|
37
37
|
}
|
|
38
38
|
}
|